[Tex/LaTex] TikZ: Background rectangles with equal width but ‘fitting’ height

backgroundshorizontal alignmentnodestikz-pgf

I'm trying to make sort of a flow chart for a series of steps, but these steps are also grouped, and I'd like my diagram to reflect that. So I'm using the pgfonlayer/background environment to draw rectangles around these groups.

I found a similiar example that uses the fit parameter to find the right dimensions.

That example works nicely except for the fact that groups do not have an equal width, so the rectangles don't look very nice:

ugly example

That's the code for that (elicit is the first node "Wissenserhebung"):

\begin{pgfonlayer}{background}
  \node [background, fit=(elicit)] {};
  % others similiar
\end{pgfonlayer}

Then, I found another way to do it, with rectangles and lots of calculations:

[nice example][2]

  \draw [background] ($(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(elicit.south east)!(matrix.east)+(0.2,-0.2)$);
  \draw [background] ($(elicit.north west)!(interpret.north west)!(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(model.south east)!(matrix.east)+(0.2,-0.2)$);
  \draw [background] ($(elicit.north west)!(representation.north west)!(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(representation.south east)!(matrix.east)+(0.2,-0.2)$);

With that code, I get nice rectangles, but they don't seem to be nodes so I cannot attach text to them.

Is there a 'canonical' way of getting these rectangles with an equal width but fitting to the height of the nodes inside and able to get text attached?
I found posts about modifying bounding rectangles, but I'm not sure if or how that could help me here.

This is the full code (minus style definitions):

\begin{tikzpicture}
\matrix (matrix) [row sep=0.5cm,column sep=0.5cm] {
  \node (elicit) [schritt] {Wissenserhebung}; & \\
  \node (interpret) [schritt] {Interpretation}; & \\
  & \node (model) [schritt] {Modellierung}; \\
  \node (representation) [schritt] {Repräsentation}; & \\
  \node (integration) [schritt] {Integration}; & \\
  \node (maintenance) [schritt] {Wartung}; & \\
};

\path[->]
  (elicit) edge (interpret)
  (interpret) edge node[right] {\hspace{.35cm}\tiny Modellbasierter Ansatz} (model)
  (interpret) edge node[right] {\tiny Rapid Prototyping} (representation)
  (model) edge (representation)
  (representation) edge (integration)
  (integration) edge (maintenance);
\begin{pgfonlayer}{background}
  % ugly, but nodes
  %\node [background, fit=(elicit)] {};
  %\node [background, fit=(interpret) (model)] {};
  %\node [background, fit=(representation)] {};

  % no nodes, but correct width
  %\draw [background] ($(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(elicit.south east)!(matrix.east)+(0.2,-0.2)$);
  %\draw [background] ($(elicit.north west)!(interpret.north west)!(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(model.south east)!(matrix.east)+(0.2,-0.2)$);
  %\draw [background] ($(elicit.north west)!(representation.north west)!(elicit.north west)-(0.2,-0.2)$) rectangle ($(matrix.east)!(representation.south east)!(matrix.east)+(0.2,-0.2)$);
\end{pgfonlayer}
\end{tikzpicture}

Best Answer

You can use nodes with the fit library by adding coordinates to each of the fit lists that lie on the left and right borders of the bounding box, but at the same vertical position as the nodes you want to highlight. You can do this with the calc library and its syntax ($(A)!(C)!(B)$), which projects the point (C) on the line from (A) to (B).

In the example below, I've used a script that takes a node name as an argument and returns three coordinates: The node itself, and its projection on the left and right borders of the bounding box. In order to make the new boxes all the same width, the bounding box needs to be "frozen", so one box doesn't influence the size of the next. You can do this by issuing \path [use as bounding box] (current bounding box.north west) (current bounding box.south east) before the first background box, which stops the updating of the bounding box.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{backgrounds,fit,calc}


\begin{document}

\tikzset{
    schritt/.style={
        draw,
        rounded corners,
        fill=blue!20,
        inner xsep=2em,
    },
    background/.style={
        draw,
        fill=yellow!30,
        align=right
    }
}

% Returns three nodes: The argument, and the projections of the argument on the left and right borders of the bounding box
\newcommand{\extendnode}[1]{
    (#1)
    ($(current bounding box.north east)!(#1)!(current bounding box.south east)$)
    ($(current bounding box.north west)!(#1)!(current bounding box.south west)$)
}

\begin{tikzpicture}
\matrix (matrix) [row sep=0.5cm,column sep=0.5cm] {
  \node (elicit) [schritt] {Wissenserhebung}; & \\
  \node (interpret) [schritt] {Interpretation}; & \\
  & \node (model) [schritt] {Modellierung}; \\
  \node (representation) [schritt] {Repräsentation}; & \\
  \node (integration) [schritt] {Integration}; & \\
  \node (maintenance) [schritt] {Wartung}; & \\
};

\path[->]
  (elicit) edge (interpret)
  (interpret) edge node[right] {\hspace{.35cm}\tiny Modellbasierter Ansatz} (model)
  (interpret) edge node[right] {\tiny Rapid Prototyping} (representation)
  (model) edge (representation)
  (representation) edge (integration)
  (integration) edge (maintenance);

\begin{pgfonlayer}{background}

  \path [use as bounding box] (current bounding box.north west) (current bounding box.south east); % Freeze current bounding box
  \node [fit={\extendnode{elicit}}, background] {First};
  \node [fit={\extendnode{interpret} (model)}, background] {Second};
  \node [fit=\extendnode{representation}, background] {Third};
  \node [fit=\extendnode{integration}, background] {Fourth};
  \node [fit=\extendnode{maintenance}, background] {Fifth};

\end{pgfonlayer}
\end{tikzpicture}


\end{document}

nodes of equal width