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.

  • 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 '11 at 4:10
  • @Werner I added the MWE. – yayu Nov 25 '11 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 '11 at 14:47
37

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} 
  • 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 '13 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 '13 at 14:50
  • 1
    @jja: Are you using pdflatex for the compilation? – Jake Mar 12 '13 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 '13 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 '14 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}
1

Here is a little improvement of Jake's answer.

Problem:

  • The options line width and outer sep are not considered. Therefore the link box is usually to 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 as outer sep and shifted the two points by that value to the middle of the node:

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

Visualization and Description:

enter image description here

  • The node has a thick blue border with a green line on top.
  • The black rectangle surrounds the node anchors (north west and south east).
  • The yellow rectangle is the visualization of the hyperlink area.
  • Setting of outer sep from left to right is: "not set", 0mm, 3mm.
  • In the lower images the yellow rectangles (hyperlink areas) cover the blue rectangles (node borders) exactly.

Code:

\documentclass[border=2mm]{standalone}

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

% NOTE: added option "draw=yellow" for testing (can be removed for normal usage)
\tikzset{
    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), draw=yellow] {\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}},
                \p1=([shift={(\n0, -\n0)}] sourcenode.north west),
                \p2=([shift={(-\n0, \n0)}] sourcenode.south east),
                \n1={\x2-\x1},
                \n2={\y1-\y2} in
            node [inner sep=0pt, outer sep=0pt, anchor=north west, at=(\p1), draw=yellow] {\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
        }
    },
}

\begin{document}

\newcommand{\comparison}[1][]{
    \begin{tikzpicture}[
            line width=1mm,
            node distance=5mm,
            inner sep=2mm,
            #1
        ]

        \foreach \variant [count=\i] in {Jake, dexteritas} {
            \node[draw=blue, hyperlink \variant={test}] (a) at (0,-2*\i) {\variant};
            \node[very thin, draw=green] 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]

\end{document}
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.