14

When I place text in a 3D figure along a plane, the hyperref box does not get adjusted. The problem text in the image was placed as

        \node [yz slant style, anchor=west, black] at (0,1,3) 
                {\href{http://tex.stackexchange.com}{TeX.SE}};

If I remove the yz slant style then things work fine as first link shows, but then the text is not aligned in the plane that I desire.

Is there a way to fix for this?

enter image description here

References:

Notes:

  • The code below look more intimidating than it is -- most of it is setting up the slant so can be ignored for the purposes of this question. But that was needed to illustrate the problem.

Code:

\documentclass{article}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage[colorlinks=false, pdfborder={0 0 1}, allbordercolors=cyan]{hyperref}

\begin{document}

%% https://tex.stackexchange.com/a/51388/4301
\newcommand*\elevation{14}
\newcommand*\anglerot{-50}
\pgfmathsetmacro\xc{cos(\anglerot)}  
\pgfmathsetmacro\xs{sin(\anglerot)}   
\pgfmathsetmacro\yc{cos(\elevation)} 
\pgfmathsetmacro\ys{sin(\elevation)} 
\newcommand*\axexthreed{\xs*1cm,-\xc*1cm} 
\newcommand*\axeythreed{\yc*1cm,-\ys*1cm}
\newcommand*\axezthreed{0cm,1cm} 

\newcommand*{\CoordX}{3}%
\newcommand*{\CoordY}{4}%
\newcommand*{\CoordZ}{5}%

%% https://tex.stackexchange.com/a/170255/4301
\tikzset{yz slant style/.style={red, yslant=-tan(\elevation), xscale=cos(\elevation)}}
%\tikzset{xy slant style/.style={blue, xslant=-tan(\elevation+\anglerot), rotate=-\elevation, yscale=cos(\anglerot)}}
%\tikzset{xz slant style/.style={orange, yslant=-cot(\anglerot), xscale=sin(-\anglerot)}}


\begin{tikzpicture}[x = {(\axexthreed)},
                    y = {(\axeythreed)},
                    z = {(\axezthreed)},
                    ]

    %% Draw Axes:
    \draw[gray, thick, -latex] (-1,0,0) -- (\CoordX,0,0) node[black, left=6pt ] {$x$}; 
    \draw[gray, thick, -latex] (0,-1,0) -- (0,\CoordY,0) node[black, right=6pt] {$y$}; 
    \draw[gray, thick, -latex] (0,0,-1) -- (0,0,\CoordZ) node[black, above=6pt] {$z$};       

    %% Place text in yz plane
        \node [anchor=west] at (0,1,4) 
                {\href{http://tex.stackexchange.com}{TeX.SE (no slant)}};
                
        \node [yz slant style, anchor=west, black] at (0,1,3) %  ??? How get this border to work ???
                {\href{http://tex.stackexchange.com}{TeX.SE (slant)}};
\end{tikzpicture}
\end{document}
2
  • A Lazy man's solution is to disable pdfborder and draw the borders for node: \node [yz slant style, anchor=west, draw,cyan,text=black] at (0,1,3)........i.stack.imgur.com/l1VaO.png
    – user11232
    Apr 6 '15 at 7:20
  • @HarishKumar: Hmmm. Will consider doing that if an automated solution does not found. Apr 6 '15 at 7:34
11

Regarding pdfTeX: It's a limitation of TikZ. Transformations are done using raw commands, not the pdfTeX primitive \pdftransformmatrix. The latter does not include translations, because it can be achieved by moving boxes. However, Tikz' basic system layer command needs the whole matrix including translations, thus a fix would mean a redesign at least at the lower layer(s).

The internals:

pdfTeX provides:

\pdfsetmatrix{<a> <b> <c> <d>}

which pdfTeX translates to the equivalent

\pdfliteral{<a> <b> <c> <d> 0 0 cm}

with notifying pdfTeX about the transformation, thus that the link and anchor positions can be corrected.

TikZ defines in the system layer \pgf@transformcm:

\def\pgfsys@transformcm#1#2#3#4#5#6{%
  \pgfsysprotocol@literalbuffered{#1 #2 #3 #4}%
  \pgf@sys@bp{#5}% <x>: horizontal translation in bp
  \pgf@sys@bp{#6}% <y>: vertical translation in bp
  \pgfsysprotocol@literal{cm}%
}

This is equivalent to (with <x> and <y> as the result of the conversion to bp):

\pdfliteral{#1 #2 #3 #4 <x> <y> cm}

But the contents of \pdfliteral is not parsed by pdfTeX, thus pdfTeX does not know about the transformation.

The translation components <x and <y> spoil the fun, because pdfTeX's \pdftransformmatrix can only handle the value zero.

At any case, arbitrary link shapes are not directly supported by pdfTeX.

7
  • 1
    Can you elaborate a little more on this? I can't see why they are related. If I use, say, \pdfsetmatrix the box still contains the skewed elements however retains its rectangular form.
    – percusse
    Apr 6 '15 at 9:41
  • @percusse Longer explanation added. Apr 6 '15 at 10:03
  • Ah the last sentence is the key then. Because I can get the current transformation matrix in PGF and trim off its displacement components and supply to \pdfsetmatrix and it actually works the elements are skewed. But still the box is simply enlarged not skewed.
    – percusse
    Apr 6 '15 at 10:09
  • @percusse All translations must be done via TeX's way of shifting boxes. If \pdfliteral is used for the translation, then pdfTeX does not know about it. Apr 6 '15 at 10:15
  • 2
    @HeikoOberdiek There is a new answer and I'm very courious what you think of it.
    – Keks Dose
    Feb 27 '18 at 11:18
8

Skewed, slanted, sheared, rotated hyperlinks are no problem, at least if Acrobat Reader is used for display:

enter image description here

For this, we define the href={<url>} option, that turns any quadrangle-shaped TikZ node into a hyperlink.

We patch hyperref to also include the /QuadPoints [...] entry into the Link PDF annotation. According to the PDF specification, /QuadPoints [...] defines the corner coordinates of any number of quadrangles that only need be entirely inscribed within the usual, horizontal link rectangle and which further determine the mouse sensitive area of the hyperlink. Even arbitrarly shaped regions could be turned into hyperlinks in that way, simply by superposition of multiple quadrangles.

(Run pdflatex/lualatex twice.)

\documentclass{article}

\usepackage{luatex85} %for LuaLaTeX compatibility
\usepackage{xcolor}
\usepackage{tikz}
\usepackage[colorlinks=false, pdfborder={0 0 1}, allbordercolors=cyan]{hyperref}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% href={<URL>} for TikZ nodes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usetikzlibrary{calc}
\tikzset{
    href/.style={
        alias=hrefnode,
        append after command={
            let \p1 = (hrefnode.south west),
                \p2 = (hrefnode.south east),
                \p3 = (hrefnode.north east),
                \p4 = (hrefnode.north west)
                in
            node [inner sep=0pt, outer sep=0pt,at=(\p1)] {\pdfsavepos%
              \writeAux{}{%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.x1\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastxpos sp}}%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.y1\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastypos sp}}}%
            }
            node [inner sep=0pt, outer sep=0pt,at=(\p2)] {\pdfsavepos%
              \writeAux{}{%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.x2\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastxpos sp}}%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.y2\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastypos sp}}}%
            }
            node [inner sep=0pt, outer sep=0pt,at=(\p3)] {\pdfsavepos%
              \writeAux{}{%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.x3\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastxpos sp}}%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.y3\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastypos sp}}}%
            }
            node [inner sep=0pt, outer sep=0pt,at=(\p4)] {\pdfsavepos%
              \writeAux{}{%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.x4\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastxpos sp}}%
                \string\expandafter\string\xdef\string\csname\space hrefnd\thehrefnd.y4\string\endcsname{%
                  \noexpand\hypercalcbp{\noexpand\number\pdflastypos sp}}}%
            }
            {[local bounding box=link rect] (\p1)--(\p2)--(\p3)--(\p4)--cycle}
            node [inner sep=0pt, outer sep=0pt,anchor=center,at=(link rect.center)] {%
              {\edef\QuadPoints{/QuadPoints [%
                  \csname hrefnd\thehrefnd.x1\endcsname\space\csname hrefnd\thehrefnd.y1\endcsname\space
                  \csname hrefnd\thehrefnd.x2\endcsname\space\csname hrefnd\thehrefnd.y2\endcsname\space
                  \csname hrefnd\thehrefnd.x3\endcsname\space\csname hrefnd\thehrefnd.y3\endcsname\space
                  \csname hrefnd\thehrefnd.x4\endcsname\space\csname hrefnd\thehrefnd.y4\endcsname%
                ]}%
              \href{#1}{%
                % upscale a bit to ensure /QuadPoints lie within /Rect (link bounding box)
                \tikz[scale=1.01] \useasboundingbox (\p1)--(\p2)--(\p3)--(\p4)--cycle;%
              }}%
              \stepcounter{hrefnd}%
            }
        }
    }
}
\makeatletter
  %patch hyperref
  \let\Hy@setpdfborderOrig\Hy@setpdfborder
  \def\Hy@setpdfborder{
    \QuadPoints
    \Hy@setpdfborderOrig
  }
  \def\writeAux{\protected@write\@mainaux}
  \def\QuadPoints{}
\makeatother
\newcounter{hrefnd}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

%% https://tex.stackexchange.com/a/51388/4301
\newcommand*\elevation{14}
\newcommand*\anglerot{-50}
\pgfmathsetmacro\xc{cos(\anglerot)}  
\pgfmathsetmacro\xs{sin(\anglerot)}   
\pgfmathsetmacro\yc{cos(\elevation)} 
\pgfmathsetmacro\ys{sin(\elevation)} 
\newcommand*\axexthreed{\xs*1cm,-\xc*1cm} 
\newcommand*\axeythreed{\yc*1cm,-\ys*1cm}
\newcommand*\axezthreed{0cm,1cm} 

\newcommand*{\CoordX}{3}%
\newcommand*{\CoordY}{4}%
\newcommand*{\CoordZ}{5}%

%% https://tex.stackexchange.com/a/170255/4301
\tikzset{yz slant style/.style={red, yslant=-tan(\elevation), xscale=cos(\elevation)}}
\tikzset{xy slant style/.style={blue, xslant=-tan(\elevation+\anglerot), rotate=-\elevation, yscale=cos(\anglerot)}}
\tikzset{xz slant style/.style={orange, yslant=-cot(\anglerot), xscale=sin(-\anglerot)}}


\begin{tikzpicture}[x = {(\axexthreed)},
                    y = {(\axeythreed)},
                    z = {(\axezthreed)},
                    ]

    %% Draw Axes:
    \draw[gray, thick, -latex] (-1,0,0) -- (\CoordX,0,0) node[black, left=6pt ] {$x$}; 
    \draw[gray, thick, -latex] (0,-1,0) -- (0,\CoordY,0) node[black, right=6pt] {$y$}; 
    \draw[gray, thick, -latex] (0,0,-1) -- (0,0,\CoordZ) node[black, above=6pt] {$z$};       

    %% Place text in various planes
    \node [yz slant style,anchor=west,black,href={http://tex.stackexchange.com}] at (0,1,3) {TeX.SE (slant)};
    \node [xy slant style,anchor=north west,black,href={http://tex.stackexchange.com}] at (1.5,1,0) {TeX.SE (slant)};
    \node [xz slant style,anchor=south west,rotate=90,black,href={http://tex.stackexchange.com}] at (1.5,0,1) {TeX.SE (slant)};
\end{tikzpicture}
\end{document}

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.