31

I have a TikZ tree. Now I want to make the nodes click-able directing to relevant sections in the document (or directed to URLs). Some of the content in the nodes are not text. Is it possible to turn the nodes into links, and if so, how? I would prefer the nodes themselves to be links, and not the text they contain.

Addition: I am not really good at it, and still learning, but here is a skeletal outline of the idea I am working on... (a graphical table of contents)

\documentclass{minimal} 
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}
\tikzstyle{level 1}=[sibling distance=60mm]
\tikzstyle{level 2}=[sibling distance=25mm]

\node[circle,draw,grow=down] {\textbf{COOL TOC}}
    child {node {installation}
        child {node {Linux}}
        child {node {Mac}}
        child {node {Windows}}
    }
    child {node {Get Started}
        child {node {do A}}
        child {node {do B}}
    }
    child {node {Looking Further}
        child {node {manual}}
        child {node {online}}
    }
    child[grow=up] {node {troubleshoot}
        child {node {if X happens}}
        child {node {if Y happens}}
    };
\end{tikzpicture}

\end{document}

enter image description here

There are fancier examples for example this one would make for a great TOC.

3
  • 2
    Please add a minimal working example (MWE) that shows what you've done thus far in terms of creating a tikz tree with some document elements.
    – Werner
    Nov 25, 2011 at 4:10
  • @Werner I added the MWE.
    – yayu
    Nov 25, 2011 at 4:47
  • 2
    I added a little code to complete the MWE. An MWE should provide sufficient code for a simple copy-paste-compile so that someone interested in finding a solution doesn't have to do any puzzling over what packages you're using, or type \documentclass etc. which gets boring. This is a nice question!
    – qubyte
    Nov 25, 2011 at 14:47

4 Answers 4

40

Here's a new TikZ style called hyperlink node=<target> that takes a hypertarget reference. It works by measuring the node it is supplied to, and then placing a new invisible node on top of that. The new node has the content \hyperlink{<target>}{\phantom{\rule{<width of node>}{<height of node>}}, so it has the same size as the original node, but the whole area is clickable.

\documentclass{article}
\usepackage[hidelinks]{hyperref}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\tikzset{
    hyperlink node/.style={
        alias=sourcenode,
        append after command={
            let     \p1 = (sourcenode.north west),
                \p2=(sourcenode.south east),
                \n1={\x2-\x1},
                \n2={\y1-\y2} in
            node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\p1)] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
                    %xelatex needs \XeTeXLinkBox, won't create a link unless it
                    %finds text --- rules don't work without \XeTeXLinkBox.
                    %Still builds correctly with pdflatex and lualatex
        }
    }
}

\tikz \node [draw, inner sep=2ex,hyperlink node=pagetwo] {Go to Page Two};

\clearpage
\hypertarget{pagetwo}{Page Two}
\end{document} 
7
  • 3
    Very nice! I wanted to put a url link into the document so I exchanged \hyperlink with \href. This works as expected.
    – Sebastian
    Mar 4, 2013 at 16:15
  • This doesn't work for me. The output PDF has the node but it is not clickable. There were no errors in compilation, and I tried it with both Okular and Evince.
    – jja
    Mar 12, 2013 at 14:50
  • 1
    @jja: Are you using pdflatex for the compilation?
    – Jake
    Mar 12, 2013 at 15:05
  • Ah, that was it. I was using xelatex and it didn't work, but I just compiled with pdflatex and it worked perfectly. I guess a follow-up question would be how to do this with xelatex, if it can be done at all...
    – jja
    Mar 12, 2013 at 16:23
  • 2
    I've tried to add this to an existing drawing and get the error message Package pgf Error: No shape named is known. (note the two spaces after named. Any ideas?
    – vwegert
    Feb 10, 2014 at 19:59
3

Apart from Jake's nice idea – here's some code that works fine here in a recent document using the code from Drawing a directory listing a la the tree command in TikZ (answer of A. Stacey) and your MWE. It's not as fancy as your's, but maybe stylish, too.

\documentclass{article} 

\usepackage{tikz}
%------------------%
\makeatletter
\newcount\dirtree@lvl
\newcount\dirtree@plvl
\newcount\dirtree@clvl
\def\dirtree@growth{%
  \ifnum\tikznumberofcurrentchild=1\relax
  \global\advance\dirtree@plvl by 1
  \expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}
  \fi
  \global\advance\dirtree@lvl by 1\relax
  \dirtree@clvl=\dirtree@lvl
  \advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname
  \pgf@xa=0.5cm\relax % change the length to your needs
  \pgf@ya=-0.75cm\relax % change the length to your needs
  \pgf@ya=\dirtree@clvl\pgf@ya
  \pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
  \ifnum\tikznumberofcurrentchild=\tikznumberofchildren
  \global\advance\dirtree@plvl by -1
  \fi
}
\tikzset{ %definition of a new style "dirtree"
  dirtree/.style={
    growth function=\dirtree@growth,
    every node/.style={anchor=north},
    every child node/.style={anchor=west},
    edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}
  }
}
\makeatother
%------------------%

\usepackage{hyperref}

\begin{document}

\begin{tikzpicture}[dirtree] % it's what we defined above

\node {\textbf{COOL TOC}}
    child { node {\hyperref[install]{installation} }
        child { node {\hyperref[linux]{Linux}} }
        child { node {\hyperref[mac]{Mac}} }
        child { node {\hyperref[win]{Windows}} }
    }
    child {node {\hyperref[start]{Get Started}}
        child { node {\hyperref[caseA]{do A}} }
        child { node {\hyperref[caseB]{do B}} }
    }
    child {node {\hyperref[trbl-shoot]{troubleshoot}}
        child {node {\hyperref[caseX]{if X happens}}}
        child {node {\hyperref[caseY]{if Y happens}}}
    }
    % I've put the external resources to the end:
    child {node {Looking Further}
        child { node {\href{file:manual.pdf}{manual}} }% works only, if "manual.pdf" is in
                                                       % the same directory as the compiled
                                                       % version of this document
        child { node {\href{http://website.example.com/online-resource/}{online}} }
    };
\end{tikzpicture}

\section*{Installation}\label{install}
\subsection*{Linux}\label{linux}
Some content.

\subsection*{Mac}\label{mac}
Some content.

\subsection*{Windows}\label{win}
Some content.

\section*{Get started}\label{start}
\subsection*{First: Do A}\label{caseA}
Some content.

\subsection*{Second: Do B}\label{caseB}
 Some content.

\section*{Trouble shooting}\label{trbl-shoot}
\subsection*{If X happens:}\label{caseX}
Some content.

\subsection*{If Y happens:}\label{caseY}
 Some content.

 \end{document}
0
3

Here is a little improvement of Jake's answer. Thanks to frougon's comment, different values for outer xsep and outer ysep are now correctly considered.

Problem

  • The options line width and outer sep are not considered. Therefore, the link box is usually too large (only working case is outer sep=0).
  • DrBones addendum does not solve this problem, because it only changes the size of the hyperlink node, but not the hyperlink area itself.

Solution

If outer sep is not set, it is half of line width. Therefore, we just have to use outer sep to solve the following cases.

I defined \n0 and \n1 as outer xsep and outer ysep and shifted the two points by that values to the middle of the node:

let \n0={\pgfkeysvalueof{/pgf/outer xsep}},
    \n1={\pgfkeysvalueof{/pgf/outer ysep}},
    \p1=([shift={(\n0, -\n1)}] sourcenode.north west),
    \p2=([shift={(-\n0, \n1)}] sourcenode.south east),

Visualization and Description

result of code below

  • The node has a thick cyan border.
  • The black rectangle surrounds the node anchors (north west and south east).
  • The yellow rectangle is the visualization of the hyperlink area.
  • The passed options are shown in the lower part of the figure.
  • If yellow (hyperlink areas) and cyan (node borders) overlap, we get green, as we see in the hyperlink dexteritas variant.

Code

\documentclass[border=2mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}
\usepackage[hidelinks]{hyperref}

% NOTE: added option "test highlight" for testing (can be removed for normal usage)
\tikzset{
    test highlight/.style={draw=yellow, draw opacity=0.5},
    hyperlink Jake/.style={
        alias=sourcenode,
        append after command={
            let \p1=(sourcenode.north west),
                \p2=(sourcenode.south east),
                \n1={\x2-\x1},
                \n2={\y1-\y2} in
            node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\p1), test highlight] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
            %xelatex needs \XeTeXLinkBox, won't create a link unless it
            %finds text --- rules don't work without \XeTeXLinkBox.
            %Still builds correctly with pdflatex and lualatex
        }
    },
    hyperlink dexteritas/.style={
        alias=sourcenode,
        append after command={
            let \n0={\pgfkeysvalueof{/pgf/outer xsep}},
                \n1={\pgfkeysvalueof{/pgf/outer ysep}},
                \p1=([shift={(\n0, -\n1)}] sourcenode.north west),
                \p2=([shift={(-\n0, \n1)}] sourcenode.south east),
                \n2={\x2-\x1},
                \n3={\y1-\y2} in
            node [inner sep=0pt, outer sep=0pt, anchor=north west, at=(\p1), test highlight] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n2}{\n3}}}}}
            %xelatex needs \XeTeXLinkBox, won't create a link unless it
            %finds text --- rules don't work without \XeTeXLinkBox.
            %Still builds correctly with pdflatex and lualatex
        }
    },
}

\begin{document}

\newcommand{\comparison}[1][]{
    \begin{tikzpicture}[
        line width=1mm,
        node distance=5mm,
        inner sep=2mm,
        blend mode=darken,
        #1
    ]
    
    \foreach \variant [count=\i] in {Jake, dexteritas} {
        \node[text width=25mm, font=\small\ttfamily] at (0,-6) {#1};
        \node[draw=cyan, draw opacity=0.5, hyperlink \variant={test}] (a) at (0,-2*\i) {\variant};
        \draw[very thin] (a.north west) rectangle (a.south east);
    }
    \end{tikzpicture}
}

\comparison
\comparison[outer sep=0mm]
\comparison[outer sep=3mm]
\comparison[outer xsep=1mm, outer ysep=4mm]

\end{document}
3
  • 1
    Nice, can you please include this change in hyperlink dexteritas: append after command={ let \n0={\pgfkeysvalueof{/pgf/outer xsep}}, \n1={\pgfkeysvalueof{/pgf/outer ysep}}, \p1=([shift={(\n0, -\n1)}] sourcenode.north west), \p2=([shift={(-\n0, \n1)}] sourcenode.south east), \n2={\x2-\x1}, \n3={\y1-\y2} in node [inner sep=0pt, outer sep=0pt, anchor=north west, at=(\p1), draw=yellow, draw opacity=0.3] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n2}{\n3}}}}}}?
    – frougon
    May 30 at 14:26
  • 1
    Then it will work fine with e.g. \comparison[outer xsep=3mm, outer ysep=4mm]. (Less important: in order to visualize things better, I added draw opacity=0.3 next to the two draw=yellow options.)
    – frougon
    May 30 at 14:26
  • 1
    @frougon Thank you for pointing this out, I have adjusted the answer accordingly. Actually, it should have been obvious that if there is an outer xsep also an outer ysep exists, but I had only ever used outer sep, which made this not noticeable. The idea with the transparency is also good :)
    – dexteritas
    Jun 2 at 15:23
0

Just a small addendum to Jake's excellent answer and unfortunately as an answer since I can't comment yet.

I had to place many links in close proximity and for the newly created hyperref node not to protrude the original node more than it has to I had to compensate for the current line width via inner sep=-0.5\pgflinewidth, and set the \XeTeXLinkMargin to zero i.e.

\setlength{\XeTeXLinkMargin}{0pt}
\tikzset{
    hyperlink node/.style={
        alias=sourcenode,
        append after command={
            let \p1= (sourcenode.north west),
                \p2= (sourcenode.south east),
                \n1={\x2-\x1},
                \n2={\y1-\y2} in
            node [inner sep=-0.5\pgflinewidth,outer sep=0pt,anchor=center, at=(sourcenode.center)] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
        }
    }
}

Now the link is exactly as large as the (rectangular) node. When using different shapes the link will of course protrude.

Maybe this helps someone

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.