[Tex/LaTex] Node spacing based on node boundaries

nodesspacingtikz-pgf

TLDR: Is there a way to get the nodes to space based on their 'tips'. Thus avoiding the x-scale=#cm all over the place to get things just right.

I am in the process of converting a bunch of visio diagrams to TikZ so I can version control them. One of the issues I am continually running into is node spacing. I usually write my code and then come up with something like this: (pre-paths)

\documentclass{article}

\usepackage{tikz}
\begin{document}
\pagestyle{empty}

\usetikzlibrary{shapes, arrows, calc, positioning}

% Define block styles
\tikzstyle{state}   = [ rounded rectangle, draw, text centered, minimum height=3em ]
\tikzstyle{test}    = [ diamond, draw, shape aspect=2, inner sep = 0pt, text width = 7em, text centered ]
\tikzstyle{action}  = [ rectangle, draw, text width=8em, inner sep = 5pt, minimum height=5em ]

\begin{tikzpicture}[node distance = 2cm, align = flush center, font = \small, xscale=5cm, on grid=true]
    % Place nodes
    \node [state] (a) {aLorem ipsum};
    \node [test, below of=a] (b) {bLorem ipsum dolor sit};
    \node [test, below of=b] (c) {cLorem ipsum dolor sit};
    \node [test, below of=c] (d) {dLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, below of=d] (e) {eLorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum,};
    \node [test, below of=e] (f) {fLorem ipsum dolor sit amet};
    \node [test, right of=f] (g) {gLorem ipsum dolor};
    \node [test, below of=f] (h) {hLorem ipsum dolo};
    \node [action, below of=h] (i) {iLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, right of=i] (j) {jLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, right of=j] (k) {kLorem ipsum dolor sit};
    \node [test, below of=i] (l) {lLorem ipsum dolor};
    \node [test, below of=j] (m) {mLorem ipsum dolor};
    \node [state, below of=l] (n) {nLorem ipsum};
    \node [state, below of=m] (o) {oLorem ipsum dol};
    \node [state, below right of=o] (p) {pLorem ipsum dolor sit \\ amet, consectetur}; 

\end{tikzpicture}

\end{document}

And it always ends up looking like garbage: Garbage

So I usually start playing around with node distance but that usually makes the chart run off the page and my vertical spacing usually can be tighter than my horizontal spacing. What I'm wondering is if there's a way to get the nodes to space based on their tips. Thus avoiding the x-scale=1cm all over the place to get things just right.

This is important, because I want it to be easy to edit in the future, so this layout has to be dynamic. If the API design changes and it's just some text addition, I don't want to have to spend 20min fiddling with x-scale to get looking nice.

I saw something here drawing with a matrix which looks promising, but it'd be a rewrite of work I've already done, so I don't want to invest more time to have it blow up in my face.

For reference, this is what I'm trying to replicate:visio

Best Answer

You should use the positioning library's syntax: Instead of saying right of=<node>, you'll have to say right=of <node>. Also, in this case you'll want to use on grid=false. That way, the node distance refers to the distance between the edges of the nodes, not their centres:

\documentclass{article}

\usepackage{tikz}
\begin{document}
\pagestyle{empty}

\usetikzlibrary{shapes, arrows, calc, positioning}

% Define block styles
\tikzstyle{state}   = [ rounded rectangle, draw, text centered, minimum height=3em ]
\tikzstyle{test}    = [ diamond, draw, shape aspect=2, inner sep = 0pt, text width = 7em, text centered ]
\tikzstyle{action}  = [ rectangle, draw, text width=8em, inner sep = 5pt, minimum height=5em ]

\begin{tikzpicture}[node distance = 2em, align = flush center, font = \small, on grid=false]
    % Place nodes
    \node [state] (a) {aLorem ipsum};
    \node [test, below=of a] (b) {bLorem ipsum dolor sit};
    \node [test, below=of b] (c) {cLorem ipsum dolor sit};
    \node [test, below=of c] (d) {dLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, below=of d] (e) {eLorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum,};
    \node [test, below=of e] (f) {fLorem ipsum dolor sit amet};
    \node [test, right=of f] (g) {gLorem ipsum dolor};
    \node [test, below=of f] (h) {hLorem ipsum dolo};
    \node [action, below=of h] (i) {iLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, right=of i] (j) {jLorem ipsum dolor sit amet, consectetur adipiscing elit.};
    \node [action, right=of j] (k) {kLorem ipsum dolor sit};
    \node [test, below=of i] (l) {lLorem ipsum dolor};
    \node [test, below=of j] (m) {mLorem ipsum dolor};
    \node [state, below=of l] (n) {nLorem ipsum};
    \node [state, below=of m] (o) {oLorem ipsum dol};
    \node [state, below right=of o] (p) {pLorem ipsum dolor sit \\ amet, consectetur}; 

\end{tikzpicture}

\end{document}