# Automatically adjust text width in tikz

I would like a command, in tikz, to adjust the text zone to the rectangle. I manage manually, but I'd like something general.

MWE - below, I'd like to avoid specifying text width=... mm manually.

\documentclass[tikz]{standalone}

\begin{document}
\newcommand\mybox[3]{\draw (#1,-1) rectangle (#2,1) node[midway] {#3}}

\begin{tikzpicture}
\mybox{-1}{1.4}{short OK  };
\mybox{2}{3.6}{that's not good};
\draw (-1,-2) rectangle (1.8,-4) node[midway,text width=25mm,text centered] {that's what I'd like};
\draw (2,-2) rectangle (4,-4) node[midway,text width=15mm,text centered] {that's what I'd like};
\end{tikzpicture}
\end{document}


Edit cfr asks for some background. Here is an example of what it could be used for: a timeline. The rectangle dimensions are prescribed (by history) and the content must adjust.

\documentclass[tikz]{standalone}
\newlength{\mywidth}
\newcommand\mybox[3]{\setlength{\mywidth}{#2cm}%
\draw (#1,-1) rectangle (#2,1)
node[midway, text width=\mywidth, text centered] {#3}}

\begin{document}
\begin{tikzpicture}
\mybox{10}{15}{A 5-year-long interval during which nothing happened};
\mybox{15}{18}{A 3-year-long interval};
\mybox{18}{20}{Then he mastered Linux in 2 years};
\end{tikzpicture}
\end{document}

• If you put the rectangle inside a scope, you can use the local bounding box to compute the width. You will still need [text width= ...] only using a computed value. – John Kormylo Dec 30 '17 at 2:37
• @JohnKormylo Do you mean with something like text width=\pgfpointdiff{\pgfpointanchor{current bounding box}{south west}} {\pgfpointanchor{current bounding box}{north east}}, improved so that it works (and of course inside a scope environment)? – anderstood Dec 30 '17 at 2:47
• Close. I wasn't sure if (current bounding box) is local or global. I was going to use \begin{scope}[local bounding box=box1] ... \end{scope} with the \pgfextractx{...} after. There is another way to compute widths, but I have always use \pgfextractx. – John Kormylo Dec 30 '17 at 3:07
• Presumably, this is an XY problem (as Zarko's answer suggests, I think). The obvious answer is: use a node. For some reason, you don't want to use a node. But why you don't is not at all obvious. You're hard-coding the coordinates for the rectangle, so you obviously know the width you want. So why not just \node [text width=<dim>, draw] {<text>};? It is hard to see what you are trying to do and to understand the problem you're trying to solve. What, basically, is the point of this? Perhaps there is a better way to achieve whatever you want to do. – cfr Jan 7 '18 at 4:31
• @cfr The only restriction I need is to be able to specify the coordinates of the rectangles. Something like \mybox{xmin}{xmax}{my very long long text}. my very long long text should not cross the vertical borders of the rectangle. – anderstood Jan 7 '18 at 4:57

You could use \makecell and put \\ where you need a new line.

\documentclass[tikz]{standalone}
\usepackage{makecell}
\newcommand\mybox[3]{\draw (#1,-1) rectangle (#2,1) node[midway] {\makecell{#3}}}

\begin{document}
\begin{tikzpicture}
\mybox{-1}{1.4}{short OK  };
\mybox{2}{3.6}{that's\\ now good};
\draw (-1,-2) rectangle (1.8,-4) node[midway,text centered] {\makecell{that's what\\ I'd like}};
\draw (2,-2) rectangle (4,-4) node[midway,text centered] {\makecell{that's\\ what\\ I'd like}};
\end{tikzpicture}
\end{document}


Edit: otherwise, you could create your own width and use it as text width. As cfr suggested, I've also subtracted the inner sep in the node width calculation, otherwise the text may go too close to the border.

\documentclass[tikz]{standalone}
\newlength{\mywidth}
\newcommand\mybox[3]{\setlength{\mywidth}{#2cm}%
\addtolength{\mywidth}{-.66em}% subtract the double of the inner (x)sep here
\draw (#1,-1) rectangle (#2,1)
node[midway, text width=\mywidth, text centered] {#3}}

\begin{document}
\begin{tikzpicture}
\mybox{-1}{1.4}{short OK  };
\mybox{2}{3.6}{that's now good};
\end{tikzpicture}
\end{document}


• What does \makecell really add here that you wouldn't get with align=center? You're breaking the lines manually anyway, so I'm not clear what the advantage is. Indeed, why not just use a minipage or \parbox with centred text? Then you'd get line breaking automatically. Also, your \mywidth is too large because you haven't accounted for inner sep, have you? Doesn't text width need to be smaller than the desired node size? – cfr Jan 7 '18 at 22:43
• @cfr align=center with the \\  is the same that \makecell with the \\ , maybe the \makecell use is more familiar. With minipage or \parbox you have to explicitly give the width. I forgot the inner sep, I've now added (subtracted) it. – CarLaTeX Jan 8 '18 at 6:49

it is difficult to understand your approach to put text as node in rectangle. isn't it simpler use standard node?

\documentclass[tikz, margin=3mm]{standalone}

\begin{document}
\begin{tikzpicture}[
mybox/.style args = {#1/#2}{draw, align=flush center, fill=white,
text width=#1,
minimum height=#2}
]
\node[mybox=2cm/2cm]    at (0,0)    {short OK};
\node[mybox=2cm/2cm]    at (3,0)    {that's not good};
\node[mybox=2cm/2cm]    at (0,-2.5) {that's what I'd like};
\node[mybox=1.5cm/2cm]  at (3,-2.5) {that's what I'd like};
%
\draw (0,-5) -- node[mybox=1.5cm/2cm] {that's what I'd like} (6,-5);
\end{tikzpicture}
\end{document}


or if you persist to draw rectangle and then put text inside it:

\draw (0,-5) rectangle +(-2,-2) node[mybox=1.5cm/2cm, midway] {that's what I'd like} (6,-5);


however in this case you should remove \draw option from mybox style definition and take a care that text width of node is smaller than width of rectangle (this approach is not sensible to me, so will not further elaborate it)

edit: lets see cases with use of default and local determined size of boxes and one posibilitiy of their positioning:

\documentclass[tikz, margin=3mm]{standalone}

\begin{document}
\begin{tikzpicture}[
box/.style args = {#1/#2}{draw, fill=white, align=flush center,
text width=#1,
minimum height=#2},
box/.default = 1cm/2cm
]
\node[box,below right] at (0,0) {that's what I'd like};
\node[box,below right] at (2,0) {short OK};
\node[box=3cm/2cm,below right] at (4,0) {here is longer text in wider node};
\end{tikzpicture}
\end{document}


• This is my response to. The OP is asking how to create a node which behaves like a node and the obvious answer is: use a node. However, I strongly suspect an XY problem, as the question just doesn't make sense as it is. – cfr Jan 7 '18 at 4:24
• @cfr & Zarko The thing is that I have prescribed rectangles dimensions. For example, let's say I have \draw (2010,-1) rectangle (2013,1); \draw (2013,-1) rectangle (2018,1); and I want to write in both rectangles something long, that stays in the box. That's why I think of it as a node in a rectangle rather than the other way round. – anderstood Jan 7 '18 at 4:51
• @anderstood The question is why you have it that way. In all probability, it would be better not to. You're working against the grain of TikZ. It is unlikely to be the best strategy. That is, it will probably end in tears. – cfr Jan 7 '18 at 5:03

I suspect this is an XY problem. However, without some information about why on Earth or Jupiter you'd want to do this, better strategies are beyond the reach of my crystal-ball-gazing abilities. Not to mention my complete lack of a crystal ball.

If you must ... you might ...

\documentclass[border=11pt]{standalone}
\usepackage{tikz}
\begin{document}
\pgfmathsetmacro\mywidth{10mm-2.5pt}
\newcommand\myotherbox[3]{%
\pgfmathsetmacro\mylength{#2 cm - #1 cm - 5pt}%
\node [text width=\mylength, inner sep=2.5pt, text height=\mywidth, text depth=\mywidth, draw, anchor=west, text centered] at (#1,0) {#3};
}%
\begin{tikzpicture}
\myotherbox{-1}{1.4}{short OK};
\myotherbox{2}{3.6}{that's not good};
\end{tikzpicture}
\end{document}


However, I do not recommend this at all. Whatever the purpose, this is a very bad way to go about achieving it.

Maybe something like this?

\documentclass{standalone}
\usepackage{shapepar}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\newcommand\squarenodetext[3]{\node [draw, regular polygon, regular polygon sides=4, text width=0cm, inner sep=0mm] at (#1,#2) {\shapepar{\squareshape}#3\par};}
\begin{document}
\begin{tikzpicture}
\squarenodetext{0}{5}{\texttt{that's what I'd like} }
\end{tikzpicture}
\end{document}

• That does not adjust to the width. – anderstood Dec 30 '17 at 3:35
• I tried adapting your answer. Do you know why \newcommand\rectnodetext[3]{ \path[name path=rect] (#1,-1) rectangle (#2,1); \draw (#1,-1) rectangle (#2,1) node[midway] (A) {}; \node [text width=0cm, inner sep=0mm] at (A) {\shapepar{rect}#3\par}; } returns Shapes Paragraph error when used? – anderstood Dec 30 '17 at 13:52
• @anderstood You expect that to work?! ;) – cfr Jan 7 '18 at 4:27
• @cfr Sometimes, hopes are above expectations :D – anderstood Jan 7 '18 at 4:52

Just include a couple of options in \mybox nodes command.

\documentclass[tikz]{standalone}

\begin{document}
\newcommand\mybox[3]{%
\draw (#1,-1) rectangle (#2,1)
node[midway, align=center, text width=3em] {#3}
}

\begin{tikzpicture}
\mybox{-1}{1}{short OK};
\mybox{2}{4}{that's not good};
\draw (2,-2) rectangle (4,-4) node[midway,text width=15mm,text centered] {that's what I'd like};
\end{tikzpicture}
\end{document}

• You do not adjust text width to arguments #1 and #2. – anderstood Dec 30 '17 at 3:32
• I adjusted the text with to the box. Since you are using squared boxes in your examples. – Cragfelt Dec 30 '17 at 3:39
• @anderstood Now the question changes completely – Cragfelt Dec 30 '17 at 3:46
• Actually that was the first sentence in the question: "to adjust the text zone to the rectangle". And two lines later: "I'd like to avoid specifying text width=15mm". – anderstood Dec 30 '17 at 3:49
• @anderstood But you used only squares in your example. Anyway, your answer was not clear enough as you spected, since you needed to change it for further clarification after two answers. – Cragfelt Dec 30 '17 at 3:56