9

I have the following situation:

a bar whose width should match the height of another node

Here, I would like the rotated node to automatically match the height of the text node to its left, automatically growing or shrinking depending on the amount of text/line count in it. Right now, the hard-coded 8em only fits almost and needs constant care in case of changing text contents.

I assume that the fit library could help me here, but with my limited tikz code-foo I could only get misspelled pgf key errors and infinite compiles.

Here's the image as an MWE:

\documentclass{article}
\usepackage{tikz}
\usepackage{varwidth}
\usetikzlibrary{positioning,shapes}

\begin{document}
\begin{tikzpicture}[%
  node distance=2em,
  textbox/.style={rectangle split, rectangle split parts=2, 
                  rectangle split part fill={black!90,black!5},
                  rectangle split part align=base,
                  draw=gray,align=center},
  barstyle/.style={fill=black!90,text=white,align=center,inner ysep=6pt,rotate=90}]

\node[barstyle,minimum width=8em] % THIS should match height of text node automatically
  (bar) {A Bar!};

\node[textbox,left=of bar.north] (textnode) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty\\
    drawn-out text\\
    much too long\\
    to fit on a single\\
    line.
  \end{varwidth}};
\end{tikzpicture}
\end{document}
  • phew, it was hard to decide which answer to accept with all those good options. In the end, I liked style 2 args solution most, although the label= makes it more difficult to use in case that text has multiple lines, too. – ojdo Jul 29 '16 at 13:01
8

You can use fit library to compute node's height. But with fitting nodes, it's better to add its contents with the label option.

Following code defines a barstyle style with two arguments, the first one is the original node which is used to get its height while the second is the node contents.

\documentclass{article}
\usepackage{tikz}
\usepackage{varwidth}
\usetikzlibrary{positioning,shapes, fit}

\begin{document}
\begin{tikzpicture}[%
  node distance=2em,
  textbox/.style={rectangle split, rectangle split parts=2, 
                  rectangle split part fill={black!90,black!5},
                  rectangle split part align=base,
                  draw=gray,align=center},
  barstyle/.style 2 args={fill=black!90,
            minimum width=3em, 
            fit={(#1.south) (#1.north)}, inner ysep=0pt, label={[rotate=90, white]center:#2}
    }]

\node[textbox] (textnode) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty\\
    drawn-out text\\
    much too long\\
    to fit on a single\\
    line.
  \end{varwidth}};

\node[barstyle={textnode}{A Bar!}, right=of textnode] (bar) {};

\node[textbox, below= of textnode] (textnode2) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty 
    drawn-out text\\
    much too long 
    to fit on a single\\
    line.
  \end{varwidth}};

\node[barstyle={textnode2}{A Bar!}, right=of textnode2] (bar2) {};

\end{tikzpicture}
\end{document}

nodes whose heights match those of another node

2nd solution:

A completely different solution could be to use \tcbsetmacrotoheightofnode or \tcbsetmacrotowidthofnode macros from skins library in tcolorbox (see: 12.9 Extracting node dimensions) package:

\tcbsetmacrotoheightofnode{\myheight}{textnode2}

saves height of textnode2 node in macro \myheight which can be used in minimum height|width|size option from other nodes.

\documentclass{article}
\usepackage{tikz}
\usepackage{varwidth}
\usetikzlibrary{positioning,shapes}
\usepackage[skins]{tcolorbox}

\begin{document}
\begin{tikzpicture}[%
  node distance=2em,
  textbox/.style={rectangle split, rectangle split parts=2, 
                  rectangle split part fill={black!90,black!5},
                  rectangle split part align=base,
                  draw=gray,align=center},
  barstyle/.style={fill=black!90, text=white, align=center, inner ysep=6pt, rotate=90}
  ]

\node[textbox] (textnode) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty\\
    drawn-out text\\
    much too long\\
    to fit on a single\\
    line.
  \end{varwidth}};

  \tcbsetmacrotoheightofnode{\myheight}{textnode}

    \node[barstyle, minimum width=\myheight, right= of textnode, anchor=north] (bar) {A Bar!};

\node[textbox, below= of textnode] (textnode2) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty 
    drawn-out text\\
    much too long 
    to fit on a single\\
    line.
  \end{varwidth}};

  \tcbsetmacrotoheightofnode{\myheight}{textnode2}

    \node[barstyle, minimum width=\myheight, right=of textnode2, anchor=north] (bar2) {A Bar!};

\end{tikzpicture}
\end{document}
7

And, just for fun, a method using the let syntax from the calc library.

enter image description here

\documentclass{article}
\usepackage{tikz}
\usepackage{varwidth}
\usetikzlibrary{positioning,shapes,calc}

\begin{document}
\begin{tikzpicture}[%
  node distance=2em,
  textbox/.style={rectangle split, rectangle split parts=2, 
                  rectangle split part fill={black!90,black!5},
                  rectangle split part align=base,
                  draw=gray,align=center},
  barstyle/.style={fill=black!90,text=white,align=center,inner ysep=6pt,rotate=90}]

\node[textbox] (textnode) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty\\
    drawn-out text\\
    much too long\\
    to fit on a single\\
    line.
  \end{varwidth}};

\path let
\p1=(textnode.south), \p2=(textnode.north)
in
node[barstyle,right=of textnode.south east,minimum width=\y2-\y1] 
  (bar) {A Bar!};
\end{tikzpicture}
\end{document}
6

By looking at this previous question:

Extract x, y coordinate of an arbitrary point on curve in TikZ

\documentclass{article}
\usepackage{tikz}
\usepackage{varwidth}
\usetikzlibrary{positioning,shapes,calc}

\begin{document}
\newdimen\XCoord
\newdimen\YCoord
\makeatletter
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\begin{tikzpicture}[%
  node distance=2em,
  textbox/.style={rectangle split, rectangle split parts=2, 
                  rectangle split part fill={black!90,black!5},
                  rectangle split part align=base,
                  draw=gray,align=center},
  barstyle/.style={fill=black!90,text=white,align=center,inner ysep=6pt,rotate=90}]

\node[textbox] (textnode) {%
  {\color{white} Input}
  \nodepart{two}
  \begin{varwidth}{.8\columnwidth}
    Some pretty\\
    drawn-out text\\
    much too long\\
    to fit on a single\\
    line.
  \end{varwidth}};
 \gettikzxy{(textnode.north)}{\ax}{\ay}
\gettikzxy{(textnode.south east)}{\bx}{\by}
\node[barstyle,minimum width=\ay-\by,anchor=south west] at($(\bx,\by)+(1cm,0.cm)$) % THIS should match height of text node automatically
  (bar) {A Bar!};
\end{tikzpicture}
\end{document} 

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.