3

I need to use TikZ to draw two horizontally-spaced nodes, and an arrow between them, labelled by some text. But the arrow has to be exactly the right length to fit the text, and this will be part of a macro which could be called with text of highly variable length. The problem is that I don't know the width of the text until I've drawn the arrow and labelled it, but I have to place the nodes before I can draw the arrow. TikZ must have a solution for this - any ideas?

Edit: the intention is for the arrow to reach right up to both nodes, so that it is clearly going 'from' the first node to the second, and for the arrow to only be just long enough for the text to fit as a label. So, the more text, the longer the arrow, and the further apart the nodes; the less text, the closer the nodes become.

1

2 Answers 2

2

You could measure the width of the text (see also How can I use an hbox inside a TikZ environment for text dimension measurement?) and use this value to position the node:

\documentclass{article}
\usepackage{tikz}

\newlength{\mylabelwidth}
\begin{document}
\begin{tikzpicture}
  \node[draw] (A) {A};
  \settowidth{\mylabelwidth}{\pgfinterruptpicture some label \endpgfinterruptpicture}
  \node[draw,right] (B) at ([xshift=\mylabelwidth+10pt]A.east) {B};
  \draw[->] (A) --(B) node [midway,above] {some label};
\end{tikzpicture}
\end{document}

Alternatievly, you could place the arrow label as normal, properly aligned node and then draw the arrow and other node relative to it:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
  \node[draw](A) {A};
  % The distance between the arrow and the nodes is defined by the `inner ysep` and `innser xsep` values, respectively:
  \node[inner ysep=2.5pt,inner xsep=5pt,above right] (ABlabel) at (A.east) {some label};
  \node[draw,right] (B) at (ABlabel.south east) {B};
  \draw[->] (A) --(B);
\end{tikzpicture}

\end{document}

Both lead to the same result:

Result

6
  • @Martin : But in this case the arrow has not exactly the right length to fit the text,no ? Commented Jun 28, 2011 at 11:18
  • @Altermundus: The arrow has the width of the text plus 2x inner xsep to get some normal separation. If you really want to have the arrow 100% identical with the text width simply set inner xsep=0pt, but I think this would take the statement of the OP to literally. Commented Jun 28, 2011 at 11:21
  • @Martin I wait and see ... because I'm not sure to understand the question. Commented Jun 28, 2011 at 11:25
  • @Altermundus: Good idea, me too ;-) Commented Jun 28, 2011 at 11:31
  • Martin, thanks for this answer - this is what I wanted to do. I like the idea of drawing the nodes after drawing the text, that's very clever. But maybe it wouldn't look right if the text has characters that partially protrude below the baseline (g,y,...)? Commented Jun 28, 2011 at 16:44
1
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
  \node[draw](A) {A};
  \node[draw](B) at (8,0) {B};
  \node[inner sep =0pt] (C) at ($(A)!.5!(B)+(0,1ex)$) {my label};
  \draw[->] ($(C.south west)+(0,-1ex)$) --($(C.south east)+(0,-1ex)$);
\end{tikzpicture}

\end{document}  

enter image description here

2) With a macro but I'm not sure if I understand correctly the question

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
\newcommand{\addarrow}[3]{%
  \path  ($(#1)+(0,1ex)$)--($(#2)+(0,1ex)$) node[inner sep=0pt,sloped,pos=.5](tmp){#3};
  \draw[->] ($(tmp.south west)+(0,-1ex)$) --($(tmp.south east)+(0,-1ex)$); 
}
\begin{tikzpicture}
  \node[draw](A) {A};
  \node[draw](B) at (8,3) {B};
  \addarrow{A}{B}{a very very long label}
\end{tikzpicture}
\end{document}

enter image description here

4
  • The way I interpret the OP, the two nodes to be positioned so that the arrow labels fit between them. So node B should be places at (A)+(<width of arrow label>+<some sep>,0). Commented Jun 28, 2011 at 10:54
  • @Martin The Op says : I have to place the nodes before I can draw the arrow. So if the nodes are placed and if the arrow and the label are the same length, I think it's the only possibility. But perhaps I have some difficulties with the english language. This is possible :) Commented Jun 28, 2011 at 11:05
  • If you want to draw the arrows using \draw[-> (A) -- (B) node [above] {label text}; than you need to place B beforehand, but this is dependent on the label text. I think this is the OP's dilemma. Commented Jun 28, 2011 at 11:10
  • Thanks Altermundus, but as Martin says that's not exactly what I wanted to do - sorry for not expressing myself better initially. It's still a cool solution, just to a different problem! :) Commented Jun 28, 2011 at 16:45

You must log in to answer this question.

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