3

I'm trying to draw circles in TikZ with 1-3 digit numbers inscribed into them. The numbers should all have the same height and should be squashed horizontally to fit into the circle. The height should be based on a good fit for single digit numbers.

I guess I could achieve this with \scalebox from graphicx, but is there a way to do it with just TikZ?

Preferably I'd like to do this in a way that's portable between pain TeX, LaTeX and ConTeXt.

1
  • Concerning readability, it might be better to also introduce kerning between the digits to not have to scale them so much horizontally. Commented Nov 1, 2022 at 21:43

1 Answer 1

7
  1. Draw a circular node with the required dimensions.
  2. Add a label to its center
    • with the actual content but with no drawing
    • that is xscaled so that it fits the specified circledNumber base width.

In the xscale formula the base width (one or two digits) is divided by the width of the actual content. The min(1,<factor>) makes sure we don't widen content that is actually small enough to fit into it on its own. This is only needed when the base width is more than one digit, otherwise every sane integer number fits perfectly or needs to be squished.

I've added a debug label style that shows the text box that the outer node uses to measure its dimensions and which the inner node is scaled to.

This is not a very efficient way since we're only dealing with a handful of dimensions and PGFmath determined all the widths and heights and stuff again and again (though, for every font if needed).

Code

\input tikz.tex
\tikzset{
  every circledNumber/.style={
    shape=circle, draw, anchor=base, inner sep=+.1em, text height=height("0"),
    text width=\pgfkeysvalueof{/tikz/circledNumber base width}},
  circledNumber label/.style={
    label={[%
      xscale={min(1,\pgfkeysvalueof{/tikz/circledNumber base width}/width("#1"))},
      every circledNumber label]center:#1}},
  every circledNumber label/.style={
    draw=none, inner sep=+0pt, outer sep=+0pt, shape=rectangle},
  circledNumber base width/.initial=width("0"),
  debug label/.style={
    label={[%
      every circledNumber,
      every circledNumber label,
      draw, gray, ultra thin]center:}}}
\def\circledNumber#1{%
  \tikz[baseline=+0pt]
    \node[every circledNumber, circledNumber label={#1}, debug label/.try]{};%
}

% \begin{document}
\circledNumber{1}
\circledNumber{10}
\circledNumber{100}

{%
\tikzset{circledNumber base width=width("00")}
\circledNumber{1}
\circledNumber{10}
\circledNumber{100}
}
% \end{document}
\bye

Output

enter image description here

1
  • Of course, one could do this without a label by using two separate nodes (but a label is just another node, too). The point: xscale scales the whole node. Separate the drawing and the text to achieve the result. Commented Nov 1, 2022 at 20:32

You must log in to answer this question.

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