Using \pgftext in \behindbackground{} shape: color problems

colortikz-pgf

I do not know if this is expected or not; this is probably a very dumb operator error, but consider the following MWE:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\pgfdeclareshape{sline}{
    \anchor{center}{\pgfpointorigin}%
    \behindbackgroundpath{
        % \pgfsetcolor{.}%       <- line B
        % \pgfsetfillcolor{red}% <- line A
        \pgfpathmoveto{\pgfpoint{-0.3cm}{0pt}}%
        \pgfpathlineto{\pgfpoint{0.3cm}{0pt}}%
        \pgfnode{circle}{center}{}{}{\pgfusepath{stroke,fill}}%
        \pgftext[top,y=0.4cm]{zzz}%
        \pgfusepath{draw}%
    }
}
\begin{document}
Text
\begin{tikzpicture}[]
    \draw[] (0,1)  node [sline]{} (1,1) node{aaa};
    \draw[blue, fill=green] (0,0)  node [sline]{} (1,0) node{aaa};
\end{tikzpicture}
\end{document}

Which result in:

enter image description here

What is quite puzzling is the fact that "zzz" is following the fill color of the shape and not the stroke color. I tried to find something in the manual, to no avail.

What I would like is that the shape could follow the external "fill" parameter (either in the draw, or in the shape itself) but the text should follow the draw color, like "aaa" is doing (or at least following the external current color).

Uncommenting line B gives the "fill and stroke as the current color", as expected (\pgfsetcolor sets both stroke and fill):

enter image description here

…and uncommenting both line A and line B gives a fixed red fill and red text.

enter image description here

Commenting just line B gives:

enter image description here

In conclusion, it seems that the text created by \pgftext is colored with the fill color and colored with the current color only if the fill color is undefined. Is this the expected behavior?

Best Answer

  • In principal, text is colored with fill color, not stroke color. After all, modern fonts are all outline fonts. Commands like \color and \textcolor set both the fill and stroke color, making the fact that "text is filled" less imperceptible.

  • Therefore in pgf, each of \pgftext, \pgfnode, and \pgfmultipartnode colors the (node) text with current fill color.

  • But tikz introduces a new concept "text color" which is set by text=<color> and init to empty per node. If set, for node text both the current fill and stroke color are locally set to the text color. The related code is in \tikz@do@fig:

    \ifx\tikz@textcolor\pgfutil@empty%
    \else%
       \pgfutil@colorlet{.}{\tikz@textcolor}%
       \pgfutil@color{\tikz@textcolor}%
    \fi%
    

    A slightly different logic can be found in \tikz@nodepart@continue and \tikz@fig@continue which uses \pgfsetcolor{.} after \fi instead of \pgfutil@color{\tikz@textcolor}. The differences I know by far is that \pgfsetcolor will also set named colors pgfstrokecolor and pgffillcolor.

  • Therefore, through tikz options, one can use up to three different colors for a node:

    \node[draw=blue, fill=yellow!20, text=cyan] {text};
    
  • Back to pgf layer, some manual work is needed since option text=<color> is only available in tikz layer and the above code logic is only applied to tikz (not pgf) node text.

The example below provides a \pgf@cir@usetextcolor that sets the current fill and stroke color to text color if the latter is set.

\documentclass[border=10pt]{standalone}
\usepackage{tikz}

\makeatletter
\pgfdeclareshape{sline}{
    \anchor{center}{\pgfpointorigin}%
    \behindbackgroundpath{
        % \pgfsetcolor{.}%       <- line B
        % \pgfsetfillcolor{red}% <- line A
        \pgfpathmoveto{\pgfpoint{-0.3cm}{0pt}}%
        \pgfpathlineto{\pgfpoint{0.3cm}{0pt}}%
        \pgfnode{circle}{center}{}{}{\pgfusepath{stroke,fill}}%
        \pgfusepath{draw}
        % \pgfscope
        \pgf@circ@usetextcolor % if used at last, no need to wrap in pgfscope
        \pgftext[top,y=0.4cm]{zzz}%
        % \endpgfscope
    }
}

\def\pgf@circ@usetextcolor{%
  \ifx\tikz@textcolor\pgfutil@empty
  \else
    \pgfutil@colorlet{.}{\tikz@textcolor}%
    \pgfutil@color{\tikz@textcolor}%
  \fi
}
\makeatother

\begin{document}
Text
\begin{tikzpicture}[]
    \draw[] (0,1)  node [sline]{} (1,1) node{aaa};
    \draw[blue, fill=green] (0,0)  node [sline]{} (1,0) node{aaa};
    \draw[blue, fill=green] (0,-1)  node [sline,text=red]{} (1,-1) node[text=red]{aaa};
\end{tikzpicture}
\end{document}

enter image description here