Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

share|improve this question
    
You could measure the width of the text (see How can I use an hbox inside a TikZ environment for text dimension measurement?) and use this value to position the node. Alternatievly, you could place the arrow label as normal, properly aligned node and then draw the arrow and other node relative to it. –  Martin Scharrer Jun 28 '11 at 10:41
add comment

2 Answers

up vote 2 down vote accepted

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

share|improve this answer
    
@Martin : But in this case the arrow has not exactly the right length to fit the text,no ? –  Alain Matthes Jun 28 '11 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. –  Martin Scharrer Jun 28 '11 at 11:21
    
@Martin I wait and see ... because I'm not sure to understand the question. –  Alain Matthes Jun 28 '11 at 11:25
    
@Altermundus: Good idea, me too ;-) –  Martin Scharrer Jun 28 '11 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,...)? –  Jamie Vicary Jun 28 '11 at 16:44
show 1 more comment
\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

share|improve this answer
    
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). –  Martin Scharrer Jun 28 '11 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 :) –  Alain Matthes Jun 28 '11 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. –  Martin Scharrer Jun 28 '11 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! :) –  Jamie Vicary Jun 28 '11 at 16:45
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.