[Tex/LaTex] Draw an automatic “bounding box”

tikz-pgf

I have some Tikz figures in my document and want to draw a frame around it. The width of this frame should be always \textwidth. The height should be automatically adjusted to the height of the actual Tikz object. Is there a general solution which is independent of the Tikz object size?

Here my first try, which doesn't work. How can I overlap the red and black frame? (This is just an example to illustrate the problem. Usually the black rectangle is an arbitrary Tikz object.)

\documentclass{scrbook}
\usepackage{tikz}
\usepackage{blindtext}

\begin{document}
\blindtext
\begin{figure}[h]
\begin{tikzpicture}
  \node(boundbox) [draw=red] {
    \begin{tikzpicture} % could be an arbitrary complex Tikz object
      \draw (0,0) rectangle (\textwidth,0.5); 
    \end{tikzpicture}
  };
\end{tikzpicture}
\end{figure}
\blindtext
\end{document}

Best Answer

For a basic solution, you can use (which would disallow verbatim content in nodes):

\framebox[\textwidth]{<TikZ picture>}

For a TikZ solution the backgrounds library already offers a show background rectangle key (alias: framed). With a proper inner frame xsep setting we can accomplish a “framebox” very easily. As the frame actually adds more width (half the linewidth on both sides), we need to slightly change the definition of the background path.

Obviously, we would want to add this correction directly to the calculation of the inner frame xsep value but we couldn’t guarantee that it picks up the correct \pgflinewidth (as the calculation is done outside of the path). We could obviously hard-code it (related reference: [1]) but then we couldn’t use different line-width for different frames (which we probably won’t (and shouldn’t), though).

Alternatively, protruding half the linewidth into the margins with

background rectangle/.append code={\tikz@addmode{\pgf@relevantforpicturesizefalse}}

Code

\documentclass{scrartcl}
\usepackage{tikz}
\usepackage[showframe,pass]{geometry}
\usetikzlibrary{backgrounds}
\makeatletter
\tikzset{inner frame xsep=.5\textwidth-.5\pgf@picmaxx+.5\pgf@picminx}
\def\tikz@background@framed{% just overwriting the original definition
  \tikz@background@save%
  \pgfonlayer{background}
    \path[style=background rectangle] (\tikz@bg@minx+.5\pgflinewidth,\tikz@bg@miny) rectangle (\tikz@bg@maxx-.5\pgflinewidth,\tikz@bg@maxy);
  \endpgfonlayer}
\makeatother
\newcommand*\arbitrarycomplexTikZobject[1][]{
  \begin{tikzpicture}[#1] % could be an arbitrary complex Tikz object
    \filldraw[opacity=.4] (0,0) rectangle node[text=white,scale=5,opacity=1] {Ti\emph{k}Z} (.5\textwidth,2cm); 
  \end{tikzpicture}}
\begin{document}
Space.
\begin{figure}[ht]
\framebox[\textwidth]{\arbitrarycomplexTikZobject}
\caption{Frame with \texttt{\string\framebox}.}
\end{figure}
\tikzset{every picture/.append style={framed}}
\begin{figure}[ht]
\arbitrarycomplexTikZobject
\caption{Frame with the \texttt{framed} option and a nice \texttt{inner frame xsep} setting.}
\end{figure}
\begin{figure}[ht]
\arbitrarycomplexTikZobject[background rectangle/.append style={ultra thick,draw=red,top color=blue,rounded corners}]
\caption{Frame with the \texttt{framed} option, a nice \texttt{inner frame xsep} setting and a badass frame which is taken from the Ti\emph{k}Z manual but without the \texttt{double} option.}
\end{figure}
\end{document}

Output

enter image description here