Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The best way would be to use a style.

Manually there are at least three ways to get a filled wrapper :

\documentclass[11pt]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{ fit,backgrounds, calc,scopes}

\begin{document}
\begin{tikzpicture}[x=2 cm,y=2 cm]
\node[draw,fill=blue!20] (s){start};
\node[draw,fill=green!20] (e) at (2,1){end};
    \begin{scope}[on background layer]
        \node[rounded corners,
              fill=lightgray!50,
              inner sep = 4ex,
              fit=(s)(e),
              label=above:Wrapper] {}; 
    \end{scope}%    
\end{tikzpicture}  

\begin{tikzpicture}[scale=2]
\node[draw,fill=blue!20] (s){start};
\node[draw,fill=green!20] (e) at (2,1){end};  
    \begin{scope}[on background layer]
       \fill[rounded corners,
             red!20] ($(s.south west)+(-2ex,-2ex)$) rectangle ($(e.north east)+(2ex,2ex)$)
             coordinate  [pos=0.5] (ce) 
             coordinate  [pos=1] (ne) 
             (ce |- ne)  coordinate (no) ;  
\node [above]  at (no) {Wrapper} ; 
\end{scope}%    
\end{tikzpicture}

\begin{tikzpicture}[scale=2]
{ [local bounding box= box]  
\node[draw,fill=blue!20] (s){start};
\node[draw,fill=green!20] (e) at (2,1){end}; }

    \begin{scope}[on background layer]
       \fill[rounded corners,
             red!20] ($(box.south west)+(-2ex,-2ex)$) rectangle ($(box.north east)+(2ex,2ex)$)
             coordinate  [pos=0.5]  (ce) 
             coordinate  [pos=1]    (ne) 
             (ce |- ne)  coordinate (no) ;  
\node [above]  at (no) {Wrapper} ; 
\end{scope}%    
\end{tikzpicture}  

\end{document}

And you get

enter image description here

Automatically

I made some tries

\documentclass[11pt]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{fit,backgrounds,calc}

\tikzset{add reference/.style={insert path={%
    coordinate [pos=0,xshift=-0.5\pgflinewidth,yshift=-0.5\pgflinewidth] (#1 south west) 
    coordinate [pos=1,xshift= 0.5\pgflinewidth,yshift= 0.5\pgflinewidth] (#1 north east)
    coordinate [pos=.5] (#1 center)                        
    (#1 south west |- #1 north east)     coordinate (#1 north west)
    (#1 center     |- #1 north east)     coordinate (#1 north)
    (#1 center     |- #1 south west)     coordinate (#1 south)
    (#1 south west -| #1 north east)     coordinate (#1 south east)
    (#1 center     -| #1 south west)     coordinate (#1 west)
    (#1 center     -| #1 north east)     coordinate (#1 east)   
}}}  

\tikzset{wrapper/.style={%
          append after command={%
             ($(\tikzlastnode.south west)+(-#1,-#1)$) 
                  rectangle 
             ($(\tikzlastnode.north east)+(#1,#1)$)[add reference=R]
}}}
\begin{document} 

\begin{enumerate}
\item   \begin{tikzpicture}
      \draw[fill=red!50,label distance=.5cm]    
       node[label=90:Wrapper,
            draw,
            fill=blue!30,
            wrapper={.5cm}] at (2,3) {Inside} ; 
    \end{tikzpicture}  

\item   \begin{tikzpicture}
      \draw[fill=red!50]   
           node[wrapper={.5cm},
                draw,
                fill=blue!30] at (2,3) {Inside} ; 
      \node[above,align=center] at (R north){Wrapper};
    \end{tikzpicture}

\item  \begin{tikzpicture} [wrapper/.style ={append after command={%
          node[inner sep=#1,
               draw,
               fit=(\tikzlastnode),
               fill=lightgray!50,
               fill opacity=.5](tw){}}}]
      \node[wrapper={4ex},draw,fill=blue!30,text=black]  {Inside} ;
      \node[above] at (tw.north) {Wrapper} ;  
    \end{tikzpicture}

\item  \begin{tikzpicture} [wrapper/.style 2 args={% 
    insert path={%
      \pgfextra{%
      \begin{scope}[on background layer] 
      \node[inner sep = #1,
            draw,
            fit=(#2),
            fill      = red!30] (tw){};  
      \end{scope}}}}]

      \node[draw,fill=blue!30,text=black] (a) {Inside} ;
      \node[wrapper={4ex}{a},above] at (tw.north) {Wrapper} ;
    \end{tikzpicture}  

\item   \begin{tikzpicture} [wrapper/.style 2 args={%
      execute at end scope={ 
      insert path={%
      \pgfextra{%
      \begin{scope}[on background layer] 
      \node[inner sep = #1,
            draw,
            fit=#2,
            fill      = red!30](tw){};  
      \end{scope}}}}}] 

    \begin{scope}[wrapper={4ex}{(s)(e)}]
        \node[draw,fill=blue!30]  (s) {start};
        \node[draw,fill=green!30] (e) at (2,1) {end}; 
    \end{scope}
    \node[above] at (tw.north) {Wrapper} ; 
    \end{tikzpicture}  
\end{enumerate}
\end{document} 

and I got

enter image description here

My question is : how to get something simpler ?

In the case 1, I need to use label distance=.5cm, it's not very elegant. I need to specify twice one value.

In the case 2, I need to use add reference/.styleand it's complex.

In the case 3, I try to replace a rectangle by a node but as you can see there is a problem.

In the case 4, I try to replace a rectangle by a node but I need two lines to get the result and I think I need more arguments. I don't like the use of (tw).

In the last case 5, I try with a set of nodes. Here I need to specify the nodes in argument but It's difficult to avoid this. I don't like the use of (tw).

share|improve this question
add comment

2 Answers

up vote 7 down vote accepted

I'm not quite sure what you want exactly. The following takes elements from several of your tries and combines them into something that seems pretty minimal and flexible to me:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,backgrounds}
\begin{document}

\begin{tikzpicture}[
    wrapper/.style 2 args={%
      local bounding box=localbb,
      execute at end scope={ 
      \begin{scope}[on background layer] 
      \node[inner sep = #1,
            draw,
            fit=(localbb),
            fill = red!30,
            label = {above:#2}
            ]{};  
      \end{scope}}}] 

    \begin{scope}[wrapper={4ex}{Wrapper}]
        \node[draw,fill=blue!30]  (s) {start};
        \node[draw,fill=green!30] (e) at (2,1) {end}; 
    \end{scope}
    \end{tikzpicture}
\end{document}

The only drawback that I can think of is that this way you cannot nest wrappers. For that you would have to name the bounding boxes differently.

result

You might also be interested in the question TikZ: Execute code at end of scope OR picture and access its bounding box.


Here is a fancier version that allows nesting (except that the inner boxes don't influence the size of the outer boxes). All the wrapping boxes are drawn at the very end so that they appear in the expected order. Sorry for the obscene amount of \noexpands. I can't think of a better way to fix the count for the local bounding box at the right time.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,backgrounds}

\makeatletter
\newcount\tsx@wrapperdepth
\tsx@wrapperdepth=0
\newcount\tsx@wrappercount
\tsx@wrappercount=0

\gdef\tsx@wrappercode{}

\tikzset{wrap/.style={
      local bounding box/.expanded={localbb\number\tsx@wrappercount},
      execute at begin scope={
        \global\advance\tsx@wrapperdepth by 1\relax
        \global\advance\tsx@wrappercount by 1\relax},
      execute at end scope/.expanded={
        \noexpand\global\noexpand\advance\noexpand\tsx@wrapperdepth by -1\noexpand\relax
        %
        % store the wrapper drawing code for later use
        \noexpand\toks@\noexpand\expandafter{\noexpand\tsx@wrappercode}
        \noexpand\xdef\noexpand\tsx@wrappercode{%
          \noexpand\noexpand\noexpand\node[fit=(localbb\number\tsx@wrappercount),
            every wrap,
            #1
            ]{};
          \noexpand\the\noexpand\toks@
        }
        %
        % if we are at depth 0, draw all the wrappers
        \noexpand\ifnum\noexpand\tsx@wrapperdepth=0
          \noexpand\begin{scope}[on background layer]
            \noexpand\tsx@wrappercode
          \noexpand\end{scope}
          \noexpand\gdef\noexpand\tsx@wrappercode{}
        \noexpand\fi
        }}
}

\tikzset{every wrap/.style={draw, fill=red!30}}
\makeatother

\begin{document}
\begin{tikzpicture}
    \begin{scope}[wrap={label={below:a big box}}]
        \node[draw,fill=blue!30] at (0,0) {start 1};
        \begin{scope}[wrap={label={above:a small box}, inner sep=2ex,fill=black!30}]
            \node[draw,fill=blue!30] at (2,1) {start 2};
            \node[draw,fill=green!30] at (3,2) {end 2};
        \end{scope}
        \node[draw,fill=green!30] at (4,4) {end 1};
    \end{scope}
\end{tikzpicture}
\end{document}

nested boxes

share|improve this answer
    
Fine solution ! only two remarks label = {#2} with [wrapper={4ex}{above:Wrapper}] is more flexible and I don't why but I try something like that I needed scopes library to use local bounding box ? –  Alain Matthes Apr 21 '12 at 6:02
    
I find the problem with scopesit's because I use it outside a scope, in this case we need `scopes' libraries !! –  Alain Matthes Apr 21 '12 at 6:05
    
One request : it would be interesting to add a key : wrapper options for example. It's more flexible if a user wants to change the color, or add draw=none, add fill opacity etc. –  Alain Matthes Apr 21 '12 at 6:33
add comment

This is a partially working example. See below.

The syntax command is relatively convenient. Suppose we need 4 nodes in a decorated rectangle. We start by declaring a \draw[options] and put all the nodes that should be on top of it (or in it). In the last node options we trigger our home-brewed style wrap with some certain input and some outer sep value dictated by with padding x cm. The first coordinate is the lower left one.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}[
wrap/.style args={#1 and #2 with padding #3}{
                    append after command={
                    ([shift={(-#3,-#3)}]#1) rectangle ([shift={(#3,#3)}]#2)
                    }
          }
]
\node (D) at (2,0) {painted}; %Behind the wrapper
\draw[fill=blue!50,decoration=zigzag,decorate]% <-- Add this     ,opacity=0.1
%Regular nodes
node[draw,rounded corners,fill=red] at (2,2) (A) {bar} 
node[draw=blue,dashed,thick,fill=yellow!60,align={center}] at (1,1) (C) {Not painted\\over}
node[align=center] at (0.3cm,2.1cm) (E) {Nodding\\Here}
%Last one wraps
node [draw,thick,wrap=B and A with padding 1cm] at (0,0) (B) {foo};
\end{tikzpicture}
\end{document}

enter image description here

There is a hidden node behind the wrapper to test if it works as expected. When you change the opacity option of the rectangle you should be able to see it. The wrapper opacity is inherited by the nodes inside and I don't see a quick fix yet. Some of the options are not inherited but opacity (maybe some others too) seems to be. In the mean time, I will try to understand why. Please let me know if you see the fix.

share|improve this answer
    
I think it's normal the nodes inside your path inherited some options like opacity, line width, colors etc. You can add every node/.style={fill opacity=1} but there is another problem : It's difficult to add a title to the wrapper with this method like in my example. –  Alain Matthes Apr 21 '12 at 6:29
    
@Altermundus Aha I see! You are right. I thought that it's just for description. Let me try to find some other way. –  percusse Apr 21 '12 at 20:27
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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