[Tex/LaTex] Shrinking text to the width of a node within a tikzpicture

calculationstikz-pgfwidth

I would like to be able to scale text to the width of a TikZ node.

Using \widthof within tikzpicture as a starting point, I've arrived at somewhat of a solution, except it has incorrect spacing, and can probably be done more elegantly.

\documentclass{article}
\usepackage{tikz}
\usepackage{calc}
\usepackage{xstring}
\usepackage{ifthen}

\newlength{\scaleratio}

\makeatletter
\newcommand{\settowidthofnode}[2] {%
  \pgfextractx{#1}{\pgfpointanchor{#2}{east}}%
  \pgfextractx{\pgf@xa}{\pgfpointanchor{#2}{west}}%
  \addtolength{#1}{-\pgf@xa}%
}%
\makeatother

\makeatletter
\newcommand{\shrinktowidthofnode}[2] {%
  \settowidthofnode{\pgf@xb}{#2}%
  \setlength{\scaleratio} {%
    {1.0pt * \ratio{\pgf@xb}{\widthof{#1}}}%
  }%
  \ifthenelse{\lengthtest{\scaleratio < 1.0pt}} {%
    \setlength{\scaleratio}{\scaleratio}%
    \tokenize{\tokenized}{\the\scaleratio}%
    \StrBefore{\tokenized}{pt}[\result]%
    \scalebox{\result}{#1}%
  } {%
    #1%
  }%
}%
\makeatother

\begin{document}

\begin{tikzpicture}[every node/.style={draw,rectangle}]
  \draw[step=0.5cm,gray,very thin] (-3,-3) grid (3,3);
  \node (n) {blah};
  \node (m) [below of=n] {\shrinktowidthofnode{AAAAAAAA}{n}};
  \node (o) [below of=m] {\scalebox{0.43259}{AAAAAAAA}};
\end{tikzpicture}

\end{document}

The output looks like this:

Result

It's hard to see, but if you zoom in, the middle node's bounding box is larger than it should be, and there's some extra space on its left (there was more extra space earlier, but for some reason adding % to the end of each line in the \newcommands helped).

The bottom node is the ground truth. Any ideas?

Best Answer

The east and west anchors include the inner margin between the text and the frame (inner sep). So you set your text as wide as the frame of the other node, not its text. Then the new node adds its own inner margin which makes it wider. I would use the text and center anchors instead (see pgfmanual page 420). They give you half the text width, so this must only be doubled.

There is also no need to use calc with tikz. It comes with its own math engine pgfmath which is more powerful. Also note that \pgfpointanchor (and all other \pgfpoint... macros) already stores the x-value into \pgf@x. The \pgfextractx just calls \pgf@process (which executes the \pgfpoint... macro locally and only makes the result global available) and set #1=\pgf@x.

In your case it's better to work with \pgf@x directly, just keep in mind that it will be overwritten by the next \pgfpoint... macro. Also there is no need to calculate the scale factor by yourself. Use \resizebox{<width>}{<height>}{<content>} from the graphics package (already loaded by pgf or tikz). Use a ! for the height here so that it scales accordantly to the width.

Now there seems to be an unwanted space inside either \pgfpointanchor or the anchor code itself which causes the extra white space before your AAAAAAAs. Adding \unskip after them fixes this. But this is worth investigating and to report it to the developers.

\documentclass{article}
\usepackage{tikz}

\makeatletter
\newcommand{\settowidthofnode}[2]{%
  \pgfpointanchor{#2}{center}%
  \unskip
  \setlength{#1}{\pgf@x}%
  \pgfpointanchor{#2}{text}
  \unskip
  \addtolength{#1}{-\pgf@x}%
  \addtolength{#1}{#1}%
}%
\newcommand{\shrinktowidthofnode}[2]{%
  \begingroup
  \settowidthofnode{\pgf@xb}{#2}%
  \resizebox{\pgf@xb}{!}{#1}%
  \endgroup
}%
\makeatother

\begin{document}

\begin{tikzpicture}[every node/.style={draw,rectangle}]
  \draw[step=0.5cm,gray,very thin] (-3,-3) grid (3,3);
  \node (n) {blah};
  \node (m) [below of=n] {\shrinktowidthofnode{AAAAAAAA}{n}};
  \node (o) [below of=m] {\scalebox{0.43259}{AAAAAAAA}};
\end{tikzpicture}

\end{document}

Result:

Result

Related Question