15

I would like to rotate each character in the text of the TikZ edge label while keeping the edge label's orientation unchanged.

The following code:

\documentclass{standalone}

\usepackage{tikz}

% TikZ styles
\tikzset{
root/.style={circle,draw=red!70,fill=red!30},
leaf/.style={circle,draw=blue!70,fill=blue!30},
label/.style={sloped,above}
}

\begin{document}
\begin{tikzpicture}
\node [root] {$r$}
    child { node [leaf] {$l_1$}
        edge from parent
        node[label] {\texttt{CBA}}
    }
    child { node [leaf] {$l_2$}
        edge from parent
        node[label] {\texttt{ABC}}
    };
\end{tikzpicture}
\end{document}

produces this:

characters not rotated

The text is sloped according to the edge orientation, which is great. However, what I would like to achieve is to keep the baseline of the text sloped while rotating each of the characters individually. I would also like to adjust the character spacing if necessary.

The effect which I would like to achieve is to make each character look like it has not been rotated at all while changing the orientation of the text as a whole. The result should look like this:

characters rotated

Is there any way to achieve that? I know that I can put some nodes containing the individual letters along the edge's path, but I was wondering if there is a simpler method.

Ideally, I would prefer to have some sort of style, say slopedandrotated, which would do exactly that.

1

1 Answer 1

14

The text along path decoration can be altered slightly to set the indivdual characters upright. This solution requires a bit of manual adjustment using raise and text align/left indent to get the positioning right, but it works quite well. It supports all the options of the original text along path decoration, as described in the manual. To use text formatting options, you have to enclose them in delimiters, which default to |. I've added an option to increase the spacing between the individual letters, called kern factor, as some font options don't look good with the default spacing.

\documentclass[border=5mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.text}

% TikZ styles
\tikzset{
root/.style={circle,draw=red!70,fill=red!30},
leaf/.style={circle,draw=blue!70,fill=blue!30},
label/.style={sloped,above}
}

\makeatletter
\tikzset{
    /pgf/decoration/kern factor/.code=\pgfmathsetmacro\tikz@textalongpath@kern{0.5*#1},
    /pgf/decoration/kern factor=1
}
\pgfdeclaredecoration{text along path not sloped}{initial}{
\state{initial}[width=+0pt, next state=left indent, 
    persistent precomputation={%
        \edef\pgf@lib@dec@text@indent@left{\pgfkeysvalueof{/pgf/decoration/text align/left indent}}%
        \edef\pgf@lib@dec@text@indent@right{\pgfkeysvalueof{/pgf/decoration/text align/right indent}}%
        \edef\pgf@lib@dec@text@align{\pgfkeysvalueof{/pgf/decoration/text align/align}}%
        \pgfdecoratedremainingdistance=\pgfdecoratedpathlength%
      \advance\pgfdecoratedremainingdistance by-\pgf@lib@dec@text@indent@right\relax%
      \edef\pgfdecoratedpathlength{\the\pgfdecoratedremainingdistance}%
      \pgf@lib@dec@text@getwidth%
      \pgf@x=\pgf@lib@dec@text@width\relax%
      \pgf@y=\pgfdecoratedremainingdistance%
      \ifpgf@lib@dec@text@fit%
        \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax%
        \advance\pgf@y by-\pgf@x%
        \ifpgf@lib@dec@text@stretch@spaces%
            \def\pgf@lib@dec@text@character@shift{0pt}%
            \divide\pgf@y by\pgf@lib@dec@space@count\relax%
            \edef\pgf@lib@dec@text@space@shift{\the\pgf@y}%
        \else%
            \c@pgf@counta=\pgf@lib@dec@character@count\relax%
            \advance\c@pgf@counta by-1\relax%
            \divide\pgf@y by\c@pgf@counta\relax%
            \edef\pgf@lib@dec@text@character@shift{\the\pgf@y}%
            \def\pgf@lib@dec@text@space@shift{0pt}%
          \fi%
          \ifdim\pgf@y<0pt\relax%
            \pgf@lib@dec@text@fitfalse%
            \pgf@lib@dec@text@stretch@spacesfalse%
            \def\pgf@lib@dec@text@character@shift{0pt}%
            \def\pgf@lib@dec@text@space@shift{0pt}%
          \fi%
      \else%
        \def\pgf@lib@dec@text@character@shift{0pt}%
        \def\pgf@lib@dec@text@space@shift{0pt}%
          \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@left@text%
          \else%
            \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@right@text%
                \advance\pgf@y by-\pgf@x%
                \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}%
            \else%
                \advance\pgf@y by-\pgf@x%
                \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax%
                \pgf@y=0.5\pgf@y%
                \advance\pgf@y by\pgf@lib@dec@text@indent@left\relax%
                \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}%
            \fi%
          \fi%
      \fi%
      \let\pgfdecorationrestoftext=\pgfdecorationtext%
    }]{}
\state{left indent}[width=+\pgf@lib@dec@text@indent@left, next state=scan]{}
%
\state{scan}[width=+0pt, next state=before typeset,
 persistent precomputation={
   \pgf@lib@dec@text@scanchar%
   \ifvoid\pgf@lib@dec@text@box%
     \setbox\pgf@lib@dec@text@box\hbox{}%
     \wd\pgf@lib@dec@text@box16383pt\relax%
   \fi%
 }]{}
%
\state{before typeset}[width=+\tikz@textalongpath@kern\wd\pgf@lib@dec@text@box, next state=typeset]{}
%
\state{typeset}[width=+0pt, next state=after typeset]
{%
  \pgftransformresetnontranslations
  \setbox\pgf@hbox\hbox{\copy\pgf@lib@dec@text@box}%
  \pgfqboxsynced\pgf@hbox%
}
\state{after typeset}[width=+.5\wd\pgf@lib@dec@text@box, next state=shift,
    persistent precomputation={%
    \ifpgf@lib@dec@text@fit%
        \ifpgf@lib@dec@text@stretch@spaces%
            \ifpgf@lib@dec@text@scan@space%
                \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@space@shift%
            \else%
                \def\pgf@lib@dec@text@shift{0pt}%
            \fi%
        \else%
            \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@character@shift%
          \fi%
        \else%
            \def\pgf@lib@dec@text@shift{0pt}%
      \fi%  
  }]{}
\state{shift}[width=+\pgf@lib@dec@text@shift, next state=scan]{}
\state{final}{}
}
\makeatother

\begin{document}
\begin{tikzpicture}
\node [root] {$r$}
    child { node [leaf] {$l_1$}
        edge from parent[postaction={
            decorate,
            decoration={
                text along path not sloped,
                raise=-1.75ex,
                text={|\ttfamily|CBA},
                text align/left indent=0.5em,
                kern factor=2
            }
        }]
    }
    child { node [leaf] {$l_2$}
        edge from parent [postaction={
            decorate,
            decoration={
                text along path not sloped,
                raise=0.4ex,
                text={|\ttfamily|ABC},
                text align/left indent=0.3em,
                kern factor=2
            }
        }]
    };
\end{tikzpicture}
\end{document}
6
  • Wow, what a fast response! Thank you very much! It really appears to be working. I don't understand the code between \makeatletter and \makeatother, but it appears to do the job. Despite not being perfect and fully automatic, I accept it. Mar 30, 2012 at 17:36
  • 1
    I have created this 3-parameter style to make it a little bit more usable: edge not sloped/.style n args={3}{postaction={ decorate, decoration={ text along path not sloped, raise=#2, text={#1}, text align/left indent=#3 } }} Mar 30, 2012 at 17:42
  • 1
    Normally, @ is a special character that can't be used in command names. \makeatletter temporarily changes its category code to "letter", so that it can be used. \makeatother changes it back. This convention lets package authors define "internal" macros that cannot be called inadvertently from the main document. As for fully-automatic -- no solution can work fully with all possible fonts; ultimately, tweaking the design to look right is best left to the designer's eye.
    – Ben Lerner
    Mar 30, 2012 at 17:45
  • However, there is still one more issue: I can't seem to figure out how to change the text font, shape, size, color etc. Simply putting \texttt{ABC} in place of the text does not work (latex freezes - it probably gets into some infinite loop). I hope it can be achieved easily. Mar 30, 2012 at 17:50
  • 1
    @PeterBašista: Adding font formatting options is a bit different to normal in this case, it works as it does for the normal text along path decoration as described in the manual. I've edited my answer to show an example.
    – Jake
    Mar 30, 2012 at 18:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .