[Tex/LaTex] Adjusting edge alignment and positioning of fitted node

fitpositioningtikz-pgf

I would like to achieve the following:

what I want

Namely a top left node, a bottom left node with the same width as the top left node (with possibly different height), and a right node with the total height of two left nodes. The right node must contain multiple things, possibly pictures.

The following code solves this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usetikzlibrary{fit}
\usetikzlibrary{calc}

\begin{document}

\newdimen\XCoordA
\newdimen\YCoordA
\newdimen\XCoordB
\newdimen\YCoordB

\newcommand*{\ExtractCoordinateA}[1]{\path (#1); \pgfgetlastxy{\XCoordA}{\YCoordA};}%
\newcommand*{\ExtractCoordinateB}[1]{\path (#1); \pgfgetlastxy{\XCoordB}{\YCoordB};}%

\pgfdeclarelayer{toplayer}%
\pgfdeclarelayer{background}%
\pgfsetlayers{background,toplayer}%
\begin{tikzpicture}[
    block/.style=               {inner sep=10pt, font=\footnotesize, align=center, draw, thick},
    left_block/.style=          {block, minimum width=100pt},
    zerofit_block/.style=       {block, inner sep=0pt},
    inner_text/.style=          {inner sep=0pt, font=\small, align=center},
    inner_text_small/.style=    {inner_text, font=\tiny},
]

\begin{pgfonlayer}{background}

    \node [left_block, fill=green!50!white]
        (block_top_left) {This is\\block\_top\_left};
    \node [left_block, fill=red!50!white, below=0.2 of block_top_left.south west, anchor=north west]
        (block_bottom_left) {block\_bottom\_left};

\end{pgfonlayer}

\begin{pgfonlayer}{toplayer}

    \node [inner_text, below right=-0.7 and 1 of block_top_left]
        (block_right_label) {This is\\block\_right};
    \node [inner_text_small, below=0.1 of block_right_label]
        (block_right_text) {This is\\block\_right's\\text};

\end{pgfonlayer}

\begin{pgfonlayer}{background}

    \ExtractCoordinateA{$(block_top_left.north) - (0,0.4pt)$}; %0.4pt is half of the thick line width
    \ExtractCoordinateB{$(block_right_label)$};
    \coordinate (block_right_north) at (\XCoordB,\YCoordA);
    \ExtractCoordinateA{$(block_bottom_left.south) + (0,0.4pt)$};
    \coordinate (block_right_south) at (\XCoordB,\YCoordA);
    \coordinate (block_right_east_west_inner_sep) at (0.5,0);
    \coordinate (block_right_west) at ($(block_right_label.west) - (block_right_east_west_inner_sep)$);
    \coordinate (block_right_east) at ($(block_right_label.east) + (block_right_east_west_inner_sep)$);

    \node [zerofit_block, fill=yellow!50!white, fit=(block_right_north) (block_right_south) (block_right_west) (block_right_east)]
        (block_right) {};

\end{pgfonlayer}

\end{tikzpicture}%
\end{document}

There are numerous ugly things about this solution that I don't like:

  1. Width of the two left nodes are controlled manually, with minimum width, but I would like to have the wider node have just an inner sep and the narrower node stretch in width to follow it.
  2. Controlling the fitted right node's north, south, east and west with four manually calculated coordinates seems like overkill and just feels wrong.
  3. North and south artificial coordinate of the fitted right node require that the drawn line thickness is subtracted. This is not even manually calculated but hardcoded to half the draw thickness; as soon as the draw thickness of the nodes change, this must be adjusted by hand.
  4. The worst problem: Right block's inner blocks (block_right_label and block_right_text) are manually positioned. It would be better to somehow control the fitted node edges and draw the inner nodes after the fitted node has been positioned. This way, I could precisely control the spacing between the right fitted node and the left nodes, maybe even set it equal to the spacing between the left nodes. Not to mention that manually positioning the inner nodes will not achieve a perfectly equal top and bottom inner sep like this.

Am I approaching this problem completely wrong? Fit seems like the wrong solution here. In any case, can you offer me solutions for any number of the above problems?

Best Answer

  1. This is done by setting the width of the first node, and then fitting the other two nodes to the previous nodes, using the fit library.
  2. Same as #1.
  3. Solved with #1.
  4. This depends on what you want to do. If you only want two short nodes inside of the yellow, you can add two more nodes anchored there. But it depends on what you want to do

Output

figure 1

Code

\documentclass[margin=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,fit}

\tikzset{
    every node/.style={draw, rectangle, align=center, text width=3cm, inner sep=0, thick, outer sep=0}
}

\begin{document}
\begin{tikzpicture}[node distance=5mm]
\node[fill=green!40, minimum height=2cm, minimum width=5cm, text width=3cm] (one) {This is\\block top left};
\node[fill=red!40,  fit={(one.west) (one.east)}, minimum height=1cm, anchor=north west, below =of one] (two) {block bottom left};
\node[fill=yellow, fit={(one)(two)},right =of two.south east, anchor=south west] (three) {This is\\block right};

\end{tikzpicture}
\end{document}
Related Question