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 would like to label lines at the same midway horizontal position (pos=0.5). But as the second line is tilted, the labels lower left corner should touch the line. Hence, I would need to manually adjust the position of the second label, to let's say 0.4.

Is there any way to automatically do this?

South that A and B are exactly below each other, but still the lower left corner of B touches the line?

Below is some minimal example where B touches the line as desired, but A and B are not aligned below each other.

\documentclass{minimal}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2, 0) node[draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw (0,0) -- (2,-3) node[draw, inner sep=5pt, pos=0.5, anchor=south west] {B};
\end{tikzpicture}
\end{document}
share|improve this question
    
Maybe it is possible by some non-trivial coding using the intersection library and/or a projection from calc library, however, as long you don't need this very often I would adjust it by hand. –  Martin Scharrer Oct 12 '11 at 8:53
add comment

3 Answers

up vote 7 down vote accepted

I would use the let syntax for this (which requires the calc library to be loaded). This has the advantage of not influencing the bounding box of your picture.

You can calculate the desired coordinate for the lower left corner of the B node like this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw let \p1 = (0,0),
    \p2 = (2,-3),
    \p3 = (A.south west) in
    (\p1) -- (\p2) node at (\x3, {(\y2-\y1)*\x3/(\x2-\x1)}) [name=B,draw, inner sep=5pt, anchor=south west] {B};
\end{tikzpicture}
\end{document}


And here's a different approach that allows the nodes to be of different widths, as per Andrew Stacey's suggestion.
The idea is to use a diamond node which contains the rectangular node as payload. By setting the shape aspect according to the slope of the line and anchoring its lower corner on the desired position along the line, the rectangle node will change its position according to the width of the content.

I used a matrix of nodes for the outer node, which allows the inner node to be correctly handled by TikZ (you could also use a normal node and define the inner node using \tikz \node ...;, but this kind of nesting leads to problems). Using a matrix of nodes means that you have to terminate your node using \\.

I wrapped the calculations and style settings into a corner on line style, which passes its arguments to the inner node.

Here are two examples:

\draw (0,0) -- (4, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw let \p1 = (0,0),
    \p2 = (3,-5),
    \p3 = (A.south) in
    (\p1) -- (\p2) 
    node  [corner on line={draw, inner sep=5pt}] {B\\ }
    node  [corner on line={draw, inner sep=5pt}] {Engorgio!\\ }
;

will yield

And here are the same examples with the outer node drawn in colour

\draw (0,0) -- (4, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw let \p1 = (0,0),
    \p2 = (3,-5),
    \p3 = (A.south) in
    (\p1) -- (\p2) 
    node  [corner on line={draw=black, inner sep=5pt}, draw=blue] {B\\ }
    node  [corner on line={draw=black, inner sep=5pt}, draw=red] {Engorgio!\\ }
;


Here's the complete code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, shapes.geometric, matrix}

\tikzset{
    calculate slope/.code={
        \pgfmathsetmacro\aspect{abs((\x2-\x1)/(\y2-\y1))}
        \tikzset{shape aspect=\aspect}
    },
    corner on line/.style={
        at={(\x3, {(\y2-\y1)*\x3/(\x2-\x1)})},
        matrix of nodes,
        diamond,
        anchor=south,
        inner sep=0pt,
        outer sep=-0.5\pgflinewidth,
        calculate slope,
        nodes={
            rectangle,
            #1
        }
    }
}

\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (4, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw let \p1 = (0,0),
    \p2 = (3,-5),
    \p3 = (A.south) in
    (\p1) -- (\p2) 
    node  [corner on line={draw=black, inner sep=5pt}, draw=blue] {B\\ }
    node  [corner on line={draw=black, inner sep=5pt}, draw=red] {Engorgio!\\ }
;
\end{tikzpicture}
\end{document}
share|improve this answer
1  
Same problem with Torbjørn's answer: what happens if node A is a different width to node B? –  Loop Space Oct 12 '11 at 9:22
add comment

Here's a correction for Jake and Torbjørn's answers that avoids using the node A to position the node B. I think that there ought to be a better way of doing this, but this is based on their methods which use an auxiliary node to position the main one. To ensure that the nodes are the same size, we use a blank copy of the actual node that we wish to place. This does mean that we have to include it twice, but it wouldn't be hard to figure out a macro that did it all automatically.

Here's the correction for Torbjørn's:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {ABC};
\draw [name path=sloped] (0,0) -- node (B) [inner sep=5pt, pos=0.5, anchor=south] {\phantom{B}} (2,-3);
\path [name path=vertical] (B.south west) -- (B.north west);
\draw [name intersections={of=vertical and sloped, by=x}] (x)
        node[above right,draw,inner sep=5pt] {B};
\end{tikzpicture}
\end{document}

and here's for Jake's:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {ABC};
\draw (0,0) -- node (B) [inner sep=5pt, pos=0.5, anchor=south] {\phantom{B}} (2,-3);
\path let \p1 = (0,0),
    \p2 = (2,-3),
    \p3 = (B.south west) in
    (\p1) -- (\p2) node at (\x3, {(\y2-\y1)*\x3/(\x2-\x1)}) [draw, inner sep=5pt, anchor=south west] {B};
\end{tikzpicture}
\end{document}

Full credit to both of them for the actual ideas, this is just a minor correction to remove the dependence on the other node.

Result:

node in vertical middle of line

share|improve this answer
add comment

There may well be better ways of doing this. The following draws a dummy line vertically down from the south west corner of the top node, uses the intersection library to find the intersection between this line and the sloped line, and places a node at this intersection.

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{intersections}
\begin{document}
\begin{tikzpicture}
\draw (0,0) -- (2, 0) node (A) [draw, inner sep=5pt, pos=0.5, anchor=south] {A};
\draw [name path=sloped] (0,0) -- (2,-3);
\path [name path=vertical] (A.south west) -- ++(0,-3);
\draw [name intersections={of=vertical and sloped, by=x}] (x)
        node[above right,draw,inner sep=5pt] {B};
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
1  
Nice idea, but wouldn't work if the top node was a different width to the bottom node. Far better to use the bottom node twice. –  Loop Space Oct 12 '11 at 9:16
    
@AndrewStacey You're right. Well, that depends if the OP wants the center or the left edge of the nodes to be the directly above each other. (The latter is perhaps not very probable ...) What do you mean by using the bottom node twice exactly? –  Torbjørn T. Oct 12 '11 at 9:28
    
@AndrewStacey (Never mind about that last question.) –  Torbjørn T. Oct 12 '11 at 9:29
    
I was mostly looking for the nodes to be centered exactly below each other. Was actually hoping that there is the possibility to define a new "anchor" or something, to avoid using phantom nodes and such... But seems that's not working... –  Aeon512 Oct 12 '11 at 9:41
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.