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'm trying in TikZ to find a general way to draw an arrow and label it at the end. Something like this works reasonably well:

\draw[->] (0, 0) -- (1, 3) node[pos=1.1]{$\vec{v}$};

However, depending on the orientation, if the label is too long, then the label can overlap the arrow:

\draw[->] (0, 0) -- (3, 0) node[pos=1.1]{$\vec{v} + \vec{w}$};

What I would ideally like is, for the latter arrow, the left side is at pos=1.1. I know I can do this in this specific case by using node[pos=1.1, anchor=west], but I'm looking for something more general (so that I could abstract this all and define a command to do it automatically).

One approach I considered was trying to find the width and height of the label and move the label using those values. So, 2 questions: Is there a way to find the width/height? Or, alternatively, is there a better approach?

share|improve this question
2  
Hi Janet, welcome to the site! Do you want the length of the arrow to be fixed, as it is in your example? Or would you be happy with placing the nodes first, and drawing the arrow afterwards? That approach would be much easier. –  Jake Jan 5 '13 at 16:24
    
Note that it wouldn't be enough to find the height and width of the node, you'd also need the orientation of the line pointing at the node, so you know in which direction to shift the node. –  Jake Jan 5 '13 at 16:35
    
Is a relative position (1.1) the best here? That way the distance between the end of the line and the node differ for different line lengths. –  Qrrbrbirlbel Jan 5 '13 at 16:45
add comment

1 Answer

up vote 10 down vote accepted

For straight lines (--) a special to path could be the solution.

I have defined three to styles:

  1. a=<node text>: relative positioning
    • a position=<pos amount> (default 1.1)
  2. aa=<node text>: absolute positioning
    • aa distance=<length> (default 1ex)
  3. bb: absolute positioning but saves the coordinate and the angle for later use:
    • \xVecN: the x value,
    • \yVecN: the y value,
    • \aVecB: the anchor angle.
    • The bb style uses these values internally.
    • aa distance=<length> (default 1ex)

The lines in the code sample that are marked with % debug can be removed; they are only there to show how the styles work.

Code

\documentclass[tikz,border=2pt]{standalone}
\usetikzlibrary{calc}
\newlength{\qrrAadistance}
\setlength{\qrrAadistance}{1ex}
\newcommand*{\qrrAposition}{1.1}
\tikzset{
    a style/.style={% this style should be set to further change the behaviour of the nodes that are now hidden inside
        draw, % debug
    },
    a position/.code={\pgfmathsetmacro\qrrAposition{#1}},
    a/.style={% relative position
        to path={
            let \p1=(\tikztostart),
                \p2=(\tikztotarget),
                \n1={atan2(\x2-\x1,\y2-\y1)} in
              -- (\tikztotarget) \tikztonodes node[pos=\qrrAposition, anchor=\n1-180, a style] {#1}
                                              node[pos=\qrrAposition, fill=black, circle, inner sep=0.6pt] {}% debug
        }
    },
    aa distance/.code={\pgfmathsetlength\qrrAadistance{#1}},
    aa distance/.initial=1ex,
    aa/.style={% fixed distance
        to path={
            let \p1=(\tikztostart),
                \p2=(\tikztotarget),
                \n1={atan2(\x2-\x1,\y2-\y1)} in
              -- (\tikztotarget) \tikztonodes node[anchor=\n1-180, a style] at ($(\tikztotarget)+(\n1:\the\qrrAadistance)$) {#1}
                                              node[fill=black, circle, inner sep=0.6pt] at ($(\tikztotarget)+(\n1:\the\qrrAadistance)$) {} % debug
        }
    },
    b/.style={% later usage
        to path={
            let \p1=(\tikztostart),
                \p2=(\tikztotarget),
                \n1={atan2(\x2-\x1,\y2-\y1)},
                \p{node}=($(\tikztotarget)+(\n1:\the\qrrAadistance)$)
                 in
              -- (\tikztotarget) \tikztonodes
              \pgfextra{\xdef\aVecN{\n1-180}\xdef\xVecN{\x{node}}\xdef\yVecN{\y{node}}}
        }
    },
    bb style/.style={
        anchor=\aVecN,
        at={(\xVecN,\yVecN)},
        a style,
    },
}
\begin{document}
\begin{tikzpicture}
\draw[->] (0, 0) to[a=$\vec{v}$] (1, 3);
\draw[->] (0, 0) to[aa=$\vec{v} + \vec{w}$] (3, 0);
\draw[->] (0, 0) to[bb] (1, -3);
\node[bb style] {$\vec{v} + \vec{w} + (0, -6)$};
\end{tikzpicture}
\end{document}

Output

enter image description here

% debug

How it works

\foreach \angle in {0,2,...,358}{
\begin{tikzpicture}
\path[use as bounding box] (-2.5,-2) -- (2.5,2);
\draw[->] (0, 0) to[aa=$\vec{v} + \vec{w}$] (\angle:1cm);
\end{tikzpicture}
}

Difference between absolute and relative positioning

\foreach \l in {0.1,0.2,...,2.9,3.0,2.9,...,0.2}{
\begin{tikzpicture}
\path (0,0) -- (0:4.5cm);
\draw[->]              (0, 0) to[a =$\vec{v} + \vec{w}$] (0:\l);
\draw[yshift=-.7cm,->] (0, 0) to[aa=$\vec{v} + \vec{w}$] (0:\l);
\end{tikzpicture}
}

Output

enter image description here enter image description here

share|improve this answer
    
Thank you! I wasn't aware that anchor could take an angle, so that is good to know. But you're right that absolute positioning makes more sense, and I like that better. One small typo in the code above for anyone else following along: b/.style should be bb/.style –  Janet Jan 5 '13 at 22:26
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.