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{\xs1cm,-\xc1cm} \newcommand\axeythreed{\yc1cm,-\ys1cm} \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}

Peter Grill
  • 223,288
  • 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)........ → http://i.stack.imgur.com/l1VaO.png –  Apr 06 '15 at 07:20
  • @HarishKumar: Hmmm. Will consider doing that if an automated solution does not found. – Peter Grill Apr 06 '15 at 07:34

2 Answers2

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.

Heiko Oberdiek
  • 271,626
  • 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 06 '15 at 09:41
  • @percusse Longer explanation added. – Heiko Oberdiek Apr 06 '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 06 '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. – Heiko Oberdiek Apr 06 '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
  • @KeksDose It requires a PDF viewer that support QuadPoints. Thus, both the normal annotation box, and the entry for QuadPoints should be correct to get best results. – Heiko Oberdiek Feb 27 '18 at 18:06
  • @HeikoOberdiek Thank you. Is this one of the cases in which pstricks has more power than tikz? I remember Herbert said there were some things tikz can't do, but pstricks can. – Keks Dose Feb 28 '18 at 08:11
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}
AlexG
  • 54,894