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.

qubyte
  • 17,299
yayu
  • 5,237
  • 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 04:10
  • @Werner I added the MWE. – yayu Nov 25 '11 at 04: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

4 Answers4

41

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} 
Keith Davies
  • 745
  • 4
  • 16
Jake
  • 232,450
  • 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 04 '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
  • Does not work well if the node has a rotate command applied to it. – Joe Corneli Feb 16 '18 at 12:38
  • I made a little improvement that maps the hyperlink area more accurate on the node by considering the option outer sep. I put it into an answer below to show the difference more clearly. – dexteritas Jan 30 '20 at 17:22
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}
Speravir
  • 19,491
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}

dexteritas
  • 9,161
  • 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 '22 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 '22 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 02 '22 at 15:23
  • @dexteritas Thank you for this great example. I am new to LateX. I am trying to use your example to create a button with a hyperlink (ultimately, with a URL hyperlink, but I haven't figured that out yet). I am wondering if you could tell me how to allow for rounded corners? Currently, the highlight upon mouseover is falling outside the button border at the corners. Please see my editable MWE at OverLeaf: https://www.overleaf.com/5473137917hcwmhkqhyvvr I am wondering if there is a way to make the highlight conform to the button border? – Steven May 29 '23 at 10:39
  • 1
    @Steven Your question won't be seen by many people here, so it would be best to repost it as a fresh question. Follow-up questions like this are more than welcome! Please use the "Ask Question" link for your new question; there you can link to this question to provide the background. – dexteritas May 30 '23 at 08:35
  • @dexteritas Thank you for your quick reply! I have posted here: https://tex.stackexchange.com/questions/687267/matching-shape-of-invisible-ghost-hyperlink-href-to-any-tikz-shape – Steven May 31 '23 at 06:54
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

DrBones
  • 41
  • Do you happen to know how to account for different shapes? I am currently dealing with this issue as can be seen with this editable MWE on OverLeaf: https://www.overleaf.com/5473137917hcwmhkqhyvvr – Steven May 29 '23 at 23:48