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.

It is easy to produce a path between two nodes consisting of a single horizontal and a single vertical line (from the manual):

\begin{tikzpicture}
  \draw (0,0) node(a) [draw] {A}  (1,1) node(b) [draw] {B};
  \draw (a.north) |- (b.west);
  \draw[color=red] (a.east) -| (2,1.5) -| (b.north);
\end{tikzpicture}

However, what if I wanted the same short syntax to produce a path between (a) and (b) using a horizontal line, a vertical line, and a second horizontal line. It isn't to difficult to calculate the intermediate points, but how could the following syntax be defined?

\begin{tikzpicture}
  \draw (0,0) node(a) [draw] {A}  (3,1) node(b) [draw] {B};
  \draw (a.east) -|- (b.west);
\end{tikzpicture}
share|improve this question
    
Do you mean something like \begin{tikzpicture} \draw (0,0) node(a) [draw] {A} (3,1) node(b) [draw] {B}; \draw (a.east) -- ++(1,0) |- (b.west); \end{tikzpicture} –  percusse Feb 21 '12 at 23:48

4 Answers 4

up vote 36 down vote accepted

This answer extends Marc van Dongen's anwser.

The two styles are -|- and |-| with default value 0.5 to position the intermediate point (so, default is middle point).

enter image description here

\documentclass[margin=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{
  -|-/.style={
    to path={
      (\tikztostart) -| ($(\tikztostart)!#1!(\tikztotarget)$) |- (\tikztotarget)
      \tikztonodes
    }
  },
  -|-/.default=0.5,
  |-|/.style={
    to path={
      (\tikztostart) |- ($(\tikztostart)!#1!(\tikztotarget)$) -| (\tikztotarget)
      \tikztonodes
    }
  },
  |-|/.default=0.5,
}
\begin{document}
\begin{tikzpicture}[thick]
  \draw[->,blue] (2.1,1.1) to[|-|] (1.1,0.1);
  \draw[->] (2,1) to[-|-] (1,0);

  \draw[->,blue] (3.1,0.1) to[|-|] (4.1,1.1);
  \draw[->] (3,0) to[-|-] (4,1);

  \begin{scope}[yshift=-1.5cm]
    \draw[->,red] (2.1,1.1) to[|-|=.2] (1.1,0.1);
    \draw[->,orange] (2,1) to[-|-=.2] (1,0);

    \draw[->,red] (3.1,0.1) to[|-|=.8] (4.1,1.1);
    \draw[->,orange] (3,0) to[-|-=.8] (4,1);
  \end{scope}
\end{tikzpicture}
\end{document}
share|improve this answer
    
Well, I must say: This pretty much want I wanted. Nice, touch to allow for something other than 0.5 i.e. the middle point. Simple syntax, didn't know that this was possible. Good answer! –  DrJay Dec 11 '12 at 18:02
    
@DrJay Thanks... –  Paul Gaborit Dec 11 '12 at 23:59

With my paths.ortho library that contains of

this is possible.

This works by re-writing and intercepting the main TikZ parser. (Which is also the reason this may break with an TikZ update.)

This library introduces six path operators:

  • in the hvvh family:
    • |-| and
    • -|-;
  • in the udlr family:
    • ud,
    • du,
    • lr and
    • rl.

For the hvvh family exist the following keys:

  • hvvh/spacing=<n>,

    • hvvh/middle 0 to 1 and hvvh/0 to 1 which are a short-cut (?) for hvvh/spacing=0

    This key affects the timer (that is the function that places nodes along the path).
    The two kinks on the path are the positions 1/<n> and (<n>-1)/<n>. (With |- and -| the kink is at .5.)

    The default is <n> = 4.

    If <n> = 0 (see also the middle 0 to 1 key above), then a special timer is installed that makes the kinks at pos=0 and pos=1. The start of the three-parted line is pos=-1 and the end is pos=2 then.

    The position .5 is always in the middle of the second part of the path.

    These timer settings are valid for the udlr family, too!

  • hvvh/ratio sets the ratio of the middle part in relation to the start and the end. Its default is .5. The values 0 and 1 will result in the well-known |- and -| paths.

  • hvvh/distance sets—similar to the ratio—the distance between the start and the middle. If this distance is set greater then the orthogonal distance of the to-be-connected coordinates (or less then zero), you will end up with something that also could have been produced with one of the udlr paths.

The udlr family is explained on my answer to How to draw a return arrow from node-3 to node-1. (Note, that the code there is not up-to-date and is probably bugged, though the examples are still valid.)

Negative distances will result in paths that resemble the |-|/-|- paths.

Code (Question)

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{paths.ortho}
\begin{document}
\begin{tikzpicture}[thick, ->]
  \draw[blue] (2.1,1.1) |-| (1.1,0.1);
  \draw       (2,1)     -|- (1,0);

  \draw[blue] (3.1,0.1) |-| (4.1,1.1);
  \draw       (3,0)     -|- (4,1);

  \begin{scope}[yshift=-1.5cm, hvvh/ratio=.2]
    \draw[red]    (2.1,1.1) |-| (1.1,0.1);
    \draw[orange] (2,1) -|- (1,0);

    \draw[red] (3.1,0.1) [hvvh/ratio=.8] |-| (4.1,1.1);
    \draw[orange, hvvh/ratio=.8]   (3,0) -|- (4,1);
  \end{scope}
\end{tikzpicture}
\end{document}

Output (Question)

enter image description here

Examples of the usages of this library …

… can be found in paths.ortho-hvvh.tex and paths.ortho-udlr.tex. Animations created from these examples are hidden behind the following links:

share|improve this answer
5  
This is just excellent, something I have missed for years drawing complex diagrams with TikZ. Have you considered trying to get this into the TikZ CVS (so that it will continue to work with future updates of TikZ)? Till Tantau hasn't been seen at tex.se so far, but Mark Wilbrow and Christian Feuersänger are both around and may be willing to help you in this respect. –  Daniel Jun 6 '13 at 8:53
5  
I also think this should go in to the CVS. Tikz-uml has also a similar construction but this is way cleaner. However a minor problem is that it has to be freed from the etoolbox-related content. TikZ developers are very careful about that. –  percusse Jun 6 '13 at 12:33
    
@percusse That’s not a problem. The original draft didn’t used etoolbox but just re-defined the needed parsing macros. The \patchcmd version makes it a little bit more compatible if TikZ changes. But if it would be implemented there will be no re-definition but just one (ever-growing?) handler. But the code is still not complete or bug-free. For once I wanted to implement a switch that calculates the distances/ratios from the center of the nodes. Also the border is not always the correct one for certain values and combinations. (But that also happens with |-/-|.) –  Qrrbrbirlbel Jun 6 '13 at 12:56

You can do this with a to path. The following solution is intended to highlight the steps that are needed. The solution can draw connections in any direction, not just vertical/horizontal connections, and therefore generalises all other solutions presented thus far.

Also note the solution doesn't include an animated picture, so you can focus on the provided output without any risk of being distracted by the animation:-).

The solution shows a nice application of the not-too-frequently used projection modifier ($(a)!(b)!(c)$), which projects the point (b) onto the infinite line through (a) and (c).

The reader may add their own favourite auxiliary keys for drawing a horizontal-vertical-horizontal connection, or a vertical-horizontal-vertical connection.

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

\makeatletter
% The parsing is done relative to the key "/my connection/,
% which is not part of the user-defined API
\pgfkeys{/my connection/.cd,
         % Save the angle value.
         angle/.store in=\mycon@angle,
         % Save the ratio value.
         ratio/.store in=\mycon@ratio,
         % The draw key triggers the drawing. Should be last.
         draw/.style={/tikz/to path={
         let % \n{a} is the angle.
             \n{a}=\mycon@angle,
             % \n{r} is the ratio.
             \n{r}=\mycon@ratio,
             % \p{s} is the start of the connection.
             \p{s}=(\tikztostart),
             % \p{t} is the target of the connection.
             \p{t}=(\tikztotarget),
             % \p{sa} is some point on the line from \p{s} in direction \n{a}.
             \p{sa}=($(\p{s})+(\n{a}:1)$),
             % \p{st} is some point on the line from \p{t} in direction \n{a}.
             \p{st}=($(\p{t})+(\n{a}:1)$),
             % \p{proj s} is the projection of \p{s} on the line through \p{t} and \p{st}.
             \p{proj s}=($(\p{t})!(\p{s})!(\p{st})$),
             % \p{proj t} is the projection of \p{t} on the line through \p{s} and \p{sa}.
             \p{proj t}=($(\p{s})!(\p{t})!(\p{sa})$)
         in    % Second point of connection.
               -- ($(\p{s})!\n{r}!(\p{proj t})$)
               % Third point of connection.
               -- ($(\p{proj s})!\n{r}!(\p{t})$)
               % Last point of connection.
               -- (\p{t})
            \tikztonodes}}}
% The "connection" key is part of the user-defined API key.
% It has two sub-keys: ratio and angle, with default values 0.5
% and 0 respectively. We use the connection key to set the defaults,
% override the user-provided values for the keys (if any), and then
% draw the connection.
\tikzset{connection/.style={/my connection/.cd,ratio=0.5,angle=0,#1,draw}}
\makeatother

\begin{document}

\begin{tikzpicture}
\draw (0,0) coordinate(a) node[anchor=north]{$a$}
      (6,3) coordinate(b) node[anchor=south]{$b$};
\draw[->]      (a) to[connection] (b);
\draw[blue,->] (b) to[connection={ratio=0.25,angle=30}] (a);
\draw[red,->]  (a) to[connection={ratio=0.25,angle=90}] (b);
\end{tikzpicture}
\end{document}

sloped connections

share|improve this answer
    
Yes, I could do that. As stated it is easy to calculate the intermediate points (or point). But the question was wether it is possible to define the syntax: -|- –  DrJay Feb 22 '12 at 0:16
    
OK. I expected that. Thanks. –  DrJay Feb 22 '12 at 9:16
    
@MarcvanDongen I suggest some addition in my community answer... –  Paul Gaborit Dec 10 '12 at 15:00
    
Allow me some criticism: All solutions with a to path are only able to place the nodes on one part of the whole zig-zag line (here: the last one) without further modification. This is one of the major reason why I created the library in the first place; the other one is that these kind of questions had come up once a week—I’m exaggerating, of course—when I created the udlr part. –  Qrrbrbirlbel Jun 6 '13 at 5:31
    
@MarcvanDongen You can only place a node between the last kink and the target: \draw (a) to[connection] node[pos=0] {0} node[pos=1] {1} (b); For the other solutions \tikztonodes need to be placed after first or the second kink. This means that one needs either three distinctive to paths or another solution (say a key part or an improved version of pos) to be able to place nodes at all parts of the line. –  Qrrbrbirlbel Jun 6 '13 at 6:38

Try this:

\begin{tikzpicture}
\path (0,0) node(a) [draw] {A} -- (3,1) node(b) [draw] {B} coordinate[pos=0.5](inter);
\draw (a) -| (inter) |- (b) ;
\end{tikzpicture}
share|improve this answer

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.