16

When drawing a line between two nodes in TikZ, you can specify the anchors on the beginning and end nodes in order to control how the line is drawn.

I would like to specify the anchor on the beginning node, and the angle at which the line is drawn, and let TikZ figure out where it will intercept the end node. The usual use case is when I'm connecting to a "big node" and I would like the lines to be vertical.

I can cheat by placing a coordinate behind the big node, drawing a line to the coordinate instead, and then drawing the big node so that it covers things up. However this won't work if I need to put an arrow on the end.

I could try to calculate the intercept coordinate on the edge of the big node manually, but that seems against the TikZ spirit.

|- doesn't work in this case.

\documentclass[10pt]{minimal}
\usepackage[active,tightpage,pdftex]{preview}
\usepackage{tikz}

\begin{document}
\begin{preview}

\tikzstyle{RectObject}=[rectangle,fill=white,draw,line width=0.5mm]
\tikzstyle{line}=[draw]
\tikzstyle{arrow}=[draw, -latex] 

\begin{tikzpicture}
  %%%%%%%%%%%%%%%%%%%%%%%%
  %%  LEFT SIDE
  %%%%%%%%%%%%%%%%%%%%%%%%
  \draw (1,0) node[RectObject] (Small1A) {A};
  \draw (3,0) node[RectObject] (Small1B) {B};
  \coordinate (Cheat1A) at (1,2);
  \coordinate (Cheat1B) at (3,2);
  \path [line] (Small1A.north) -- (Cheat1A);
  \path [line] (Small1B.north) -- (Cheat1B);

  % need to draw Big Node last to cover up our cheating
  \draw (2,2) node[RectObject, inner xsep=1cm] (Big1) {Big Node};

  \draw (2,4) node[text width=4cm] (text1) {L: Cheating to control line orientation. Arrows would be hard.};

  %%%%%%%%%%%%%%%%%%%%%%%%
  %%  RIGHT SIDE
  %%%%%%%%%%%%%%%%%%%%%%%%
  \draw (7,2) node[RectObject, inner xsep=1cm] (Big2) {Big Node};
  \draw (6,0) node[RectObject] (Small2A) {A};
  \draw (8,0) node[RectObject] (Small2B) {B};
  \path [arrow] (Small2A) -- (Big2);
  \path [arrow] (Small2B) -- (Big2);

  \draw (7,4) node[text width=4cm] (text2) {R: No cheating. Arrows easy. Can't control line orientation.};
\end{tikzpicture}
\end{preview}
\end{document}

Here's a side-by-side example of "cheating", which shows what I want to be able to do, and "not cheating", which does not do what I want.

side-by-side example of "cheating", which shows what I want to be able to do, and "not cheating", which does not do what I want

The left side of this example shows what I want to be able to do, except I want to do it without cheating, and I'd like to put arrows on the end of the lines.

3 Answers 3

25

May be I missunderstood something but I don't see any problem with |- syntax. Using Jake's code:

\documentclass[10pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\tikzstyle{RectObject}=[rectangle,fill=white,draw,line width=0.5mm]
\tikzstyle{line}=[draw]
\tikzstyle{arrow}=[draw, -latex] 

\begin{tikzpicture}
  \draw (7,2) node[RectObject, inner xsep=1cm] (Big2) {Big Node};
  \draw (6,0) node[RectObject] (Small2A) {A};
  \draw (8,0) node[RectObject] (Small2B) {B};
  \draw[arrow] (Small2A.north)--(Small2A|-Big2.south);
  \draw[arrow] (Small2B.north)--(Small2B|-Big2.south);

\end{tikzpicture}
\end{document}

enter image description here

In case someone needs it, this syntax is explained in pgfmanual section "13.3.1 Intersections of Perpendicular Lines".

(<p> |- <q>) or (<q> -| <p>) represent a coordinate at intersection point between a vertical line passing through coordinate <p> and an horizontal passing through <q>. You can use named coordinates like (Small2B|-Big2.south) or numeric pairs like in (2,1 |- 3,4).

5
  • Oh wow, I never thought of using the syntax inside the node specification! Much more elegant than my approach!
    – Jake
    Jul 13, 2011 at 22:25
  • 1
    That is slick. I didn't know you could use the |- syntax inside a node specification like that. Originally I said "|- doesn't work" because I was thinking of (Small1A) |- (Big1.south) or something like that. Jul 18, 2011 at 19:20
  • What does the syntax (node1)--(node1|-node2.south) actually mean? Is there any documentation I might read?
    – LondonRob
    Jul 7, 2015 at 13:37
  • 2
    @LondonRob (node1|-node2.south) equals the coordinate at intersection point between and horizontal line through node2.south and a vertical line through node1.center (where .center can be omited). Take a look at pgfmanual, page 137.
    – Ignasi
    Jul 7, 2015 at 13:51
  • Fantastic. Perhaps you might add this to your answer!
    – LondonRob
    Jul 7, 2015 at 13:52
9

Jake and Ignasi's answers are excellent for the example I gave, of wanting strictly vertical lines between nodes. I found a way of doing the same thing with arbitrary orientation of the line. The "intersection of" TikZ mechanism can be used to find the intersection of lines defined by nodes or coordinates. The "intersection" syntax is tricky; it seems that you can't use the "calc" syntax inside an "intersection" specification, so you have to create a new coordinate and do the calculations there.

Example diagram: three nodes, two lines, arbitrary orientation of lines

\documentclass[10pt]{minimal}
\usepackage[active,tightpage,pdftex]{preview}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{positioning}

\begin{document}
\begin{preview}

\tikzstyle{RectObject}=[rectangle,fill=white,draw,line width=0.5mm]
\tikzstyle{line}=[draw]
\tikzstyle{arrow}=[draw, -latex] 

\begin{tikzpicture}
  \draw (2,2) node[RectObject, inner xsep=1cm] (Big1) {Big Node};
  \draw (1,0) node[RectObject] (Small1A) {A};
  \draw (3,0) node[RectObject] (Small1B) {B};

  % Method 1: use positioning library to put a coordinate at a special place
  % on the target node.  Doesn't really satisfy my criteria for setting the
  % line's orientation directly.
  \coordinate[left=1.4cm of Big1.south] (Small1AatBig1);
  \path [arrow] (Small1A) -- (Small1AatBig1);

  % Method 2: set a phantom coordinate using polar coordinates, then draw
  % a line to the intersection of the target node and the phantom line
  % Intersection syntax is tricky: no parentheses and no spaces around --
  \coordinate (Phantom) at ($ (Small1B) + (115:5cm) $);
  \path [arrow] (Small1B) -- (intersection of Big1.south--Big1.south east and Small1B--Phantom);

\end{tikzpicture}
\end{preview}
7

Two approaches, both using the TikZ calc library: Either use the syntax ($(A)!(C)!(B)$), which specifies the projection of (C) on the line from (A) to (B), or use the let \p1 = (<coordinate>) in ... syntax, which stores a coordinate in a macro \p1 and lets you access its x and y coordinates separately with \x1 and \y1:

\documentclass[10pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\tikzstyle{RectObject}=[rectangle,fill=white,draw,line width=0.5mm]
\tikzstyle{line}=[draw]
\tikzstyle{arrow}=[draw, -latex] 

\begin{tikzpicture}
  \draw (7,2) node[RectObject, inner xsep=1cm] (Big2) {Big Node};
  \draw (6,0) node[RectObject] (Small2A) {A};
  \draw (8,0) node[RectObject] (Small2B) {B};
  \path [arrow]  let \p1=(Small2A), \p2=(Big2.south) in (Small2A) -- (\x1,\y2);
  \path [arrow] (Small2B) -- ($(Big2.south east)!(Small2B)!(Big2.south)$);

\end{tikzpicture}
\end{document}

vertical lines with arrow tips

You must log in to answer this question.

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