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.

I want to draw something like the following (photoshop'd) rendering: photoshop'd
This image consists of three \nodes, each using a different border. The whole thing is pinned on a chain, because in my actual situation I am creating something like the syntax diagram in the TikZ tutorial (p60).

Right now, I have a MWE that renders borders between the L, C and R \nodes as well, but I want those to disappear without a change to the 'outside' borders.

My actual code:
actual

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{chains,scopes,shapes.misc}

\begin{document}

\begin{tikzpicture}[start chain,
    node distance=5mm,
    every node/.style={on chain},
    connect/.style={join=by ->},
    point/.style={coordinate},
    l/.style={draw, fill=cyan!50, rounded rectangle, rounded rectangle right arc=0},
    c/.style={draw, fill=green!50},
    r/.style={draw, fill=orange!50, rounded rectangle, rounded rectangle left arc=0},
    cozy/.style={node distance=-\pgflinewidth}]
\node[point] (p1) {};
\node [l, connect] (l) {L};
{[cozy]
\node [c] (c) {C};
\node [r] (r) {R};
}
\node[point, connect] (p2) {};
\end{tikzpicture}
\end{document}

Custom Borders (revised)

I have followed this example, @Harish Kumar's answer, and this answer. I tried drawing the borders manually, using slightly different approaches for each section of my shape. All of them have their own drawbacks:

  • applied in L: leaving the \node's line width at the default (\pgflinewidth), draw=none will cause the \node to contain surrounding space of width 0.5*\pgflinewidth. In order to draw a border within the \node's dimensions, the border must not grow beyond this space. Unfortunately, part of the the border's inside is drawn behind the filler, leaving it looking too slim. Additionally, the eastern anchor points now look as if they're off by a bit.
  • applied in C: setting the \node's line width=0 at least makes sure all the anchor points (esp. eastern & western) in the right place. However, this way, the entire border is drawn behind the filler.
  • applied in R: setting the \node's line width=0, and drawing the border outside of the filler. This causes the border to be outside the \node's dimensions, making it overlap with connecting objects.

custom borders

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,chains,scopes,shapes.misc,backgrounds}
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfdeclarelayer{foreforeground}
\pgfsetlayers{background,main,foreground,foreforeground}

\begin{document}

\begin{tikzpicture}[start chain,
    node distance=5mm,
    every node/.style={on chain},
    connect/.style={join=by ->},
    point/.style={coordinate},
    l/.style={line width=\pgflinewidth, fill=cyan!50, rounded rectangle, rounded rectangle right arc=0, append after command={% <= for the border
        \pgfextra{\begin{pgfinterruptpath}\begin{pgfonlayer}{foreground}
            \draw[] let \p1=($(\tikzlastnode.north east)+(-0.5\pgflinewidth,-0.5\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0,-0.5\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0,0.5\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(-0.5\pgflinewidth,0.5\pgflinewidth)$),
                \n1={0.5*(\y2-\y3)} in
                (\p1) -- (\p2) arc(90:270:\n1) -- (\p4);
        \end{pgfonlayer}\end{pgfinterruptpath}}
    }},
    c/.style={line width=0, fill=green!50, append after command={% <= for the border
        \pgfextra{%                 
            \begin{pgfinterruptpath}\begin{pgfonlayer}{foreground}
                \draw[] let \p1=($(\tikzlastnode.north east)+(0,-0.5\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0,-0.5\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0,0.5\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(0,0.5\pgflinewidth)$) in
                (\p1) -- (\p2) (\p3) -- (\p4);
            \end{pgfonlayer}\end{pgfinterruptpath}
        }
    }},
    r/.style={line width=0, fill=orange!50, rounded rectangle, rounded rectangle left arc=0, append after command={% <= for the border
        \pgfextra{%                 
            \begin{pgfinterruptpath}
            \draw[] let \p1=($(\tikzlastnode.north east)+(0,0.5\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0,0.5\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0,-0.5\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(0,-0.5\pgflinewidth)$),
                \n1={0.5*(\y1-\y4)} in
                (\p3) -- (\p4) arc(-90:90:\n1) -- (\p2);
            \end{pgfinterruptpath}
        }
    }}
]
\node[point] (p1) {};
\node [l, connect] (l) {L};
{[node distance=-0.5\pgflinewidth]
\node [c] (c) {C};}
{[node distance=0]
\node [r] (r) {R};}
\node[point, connect] (p2) {};

\node[font=\tiny, cyan, below=of l] (lbl l-se) {l.se};
\draw[red,->] (lbl l-se) -- (l.south east);

\begin{pgfonlayer}{foreforeground}%apparently, using layer 'foreground' in 'append after command' brings the entire node to the front, which we don't want!
\node[font=\tiny, green, below=of c, yshift=2mm] (lbl c-ne) {c.ne};
\draw[red,->] (lbl c-ne) -- (c.north east);
\end{pgfonlayer}

\node[font=\tiny, orange, below=of r] (lbl r-sw) {r.sw};
\draw[red,->] (lbl r-sw) -- (r.south west);
\end{tikzpicture}
\end{document}

How do I make sure my custom borders are within the \node's borders, and drawn on top of \node's filler color? I have attempted to use \begin{pgfonlayer}{foreground} to bring borders to the foreground, but all that seems to do in append after command is bring the entire \node to the foreground, with the border still behind the filler.

share|improve this question

2 Answers 2

up vote 4 down vote accepted

You can reduce/increase them by 0.5\pgflinewidth:

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,chains,scopes,shapes.misc,calc}

\begin{document}

\begin{tikzpicture}[start chain,
    node distance=5mm,
    every node/.style={on chain},
    connect/.style={join=by ->},
    point/.style={coordinate},
    l/.style={fill=cyan!50, rounded rectangle, rounded rectangle right arc=0, append after command={% <= for the border
        \pgfextra{%
            \begin{pgfinterruptpath}
            \draw[] let \p1=(\tikzlastnode.north west), \p2=(\tikzlastnode.south east), \n1={0.5*(\y1-\y2)} in
                ($(\tikzlastnode.north east)+(-0.5\pgflinewidth,0)$) -- (\tikzlastnode.north west) arc(90:270:\n1) -- ($(\tikzlastnode.south east)+(-0.5\pgflinewidth,0)$);
            \end{pgfinterruptpath}
        }
    }},
    c/.style={fill=green!50, append after command={% <= for the border
        \pgfextra{%
            \begin{pgfinterruptpath}
            \draw[] ($(\tikzlastnode.north east)+(-0.5\pgflinewidth,0)$) -- ($(\tikzlastnode.north west)+(0.5\pgflinewidth,0)$) ($(\tikzlastnode.south west)+(0.5\pgflinewidth,0)$) -- ($(\tikzlastnode.south east)+(-0.5\pgflinewidth,0)$);
            \end{pgfinterruptpath}
        }
    }},
    r/.style={fill=orange!50, rounded rectangle, rounded rectangle left arc=0, append after command={% <= for the border
        \pgfextra{%
            \begin{pgfinterruptpath}
            \draw[] let \p1=(\tikzlastnode.north west), \p2=(\tikzlastnode.south east), \n1={0.5*(\y1-\y2)} in
                ($(\tikzlastnode.north west)+(0.5\pgflinewidth,0)$) -- (\tikzlastnode.north east) arc(90:-90:\n1) -- ($(\tikzlastnode.south west)+(0.5\pgflinewidth,0)$);
            \end{pgfinterruptpath}
        }
    }},
    cozy/.style={node distance=-\pgflinewidth}]
\node[point] (p1) {};
\node [l, connect] (l) {L};
% introduced space here on purpose, to demonstrate too long borders
\node [c] (c) {C};
{%[cozy]
\node [r] (r) {R};
}
\node[point, connect] (p2) {};
\end{tikzpicture}
\end{document}

enter image description here

Response to Revised OP:

May be I don't understand your requirement properly, but is this what you want?

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,chains,scopes,shapes.misc,backgrounds}
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
%\pgfdeclarelayer{foreforeground}
\pgfsetlayers{background,main,foreground}%,foreforeground}

\begin{document}

\begin{tikzpicture}[start chain,
    node distance=5mm,
    every node/.style={on chain},
    connect/.style={join=by ->},
    point/.style={coordinate},
    l/.style={line width=\pgflinewidth, fill=cyan!50, rounded rectangle, rounded rectangle right arc=0, append after command={% <= for the border
        \pgfextra{\begin{pgfinterruptpath}\begin{pgfonlayer}{foreground}
            \draw[] let \p1=($(\tikzlastnode.north east)+(-0.5\pgflinewidth,-\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0,-\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0,\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(-0.5\pgflinewidth,\pgflinewidth)$),
                \n1={0.5*(\y2-\y3)} in
                (\p1) -- (\p2) arc(90:270:\n1) -- (\p4);
        \end{pgfonlayer}\end{pgfinterruptpath}}
    }},
    c/.style={line width=0, fill=green!50, append after command={% <= for the border
        \pgfextra{%
            \begin{pgfinterruptpath}\begin{pgfonlayer}{foreground}
            \draw[] let \p1=($(\tikzlastnode.north east)+(-0.5\pgflinewidth,-0.5\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0.5\pgflinewidth,-0.5\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0.5\pgflinewidth,0.5\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(-0.5\pgflinewidth,0.5\pgflinewidth)$) in
                (\p1) -- (\p2) (\p3) -- (\p4);
            \end{pgfonlayer}\end{pgfinterruptpath}
        }
    }},
    r/.style={line width=0, fill=orange!50, rounded rectangle, rounded rectangle left arc=0, append after command={% <= for the border
        \pgfextra{%
            \begin{pgfinterruptpath}
            \begin{pgfonlayer}{foreground}
            \draw[] let \p1=($(\tikzlastnode.north east)+(0,-0.5\pgflinewidth)$),
                \p2=($(\tikzlastnode.north west)+(0,-0.5\pgflinewidth)$),
                \p3=($(\tikzlastnode.south west)+(0,0.5\pgflinewidth)$),
                \p4=($(\tikzlastnode.south east)+(0,0.5\pgflinewidth)$),
                \n1={0.5*(\y1-\y4)} in
                (\p3) -- (\p4) arc(-90:90:\n1) -- (\p2);
            \end{pgfonlayer}
            \end{pgfinterruptpath}
        }
    }}
]
\node[point] (p1) {};
\node [l, connect] (l) {L};
{[node distance=-0.5\pgflinewidth]
\node [c] (c) {C};}
{[node distance=0]
\node [r] (r) {R};}
\node[point, connect] (p2) {};

%\node[font=\tiny, cyan, below=of l] (lbl l-se) {l.se};
%\draw[red,->] (lbl l-se) -- (l.south east);
%
%\begin{pgfonlayer}{foreforeground}%apparently, using layer 'foreground' in 'append after command' brings the entire node to the front, which we don't want!
%\node[font=\tiny, green, below=of c, yshift=2mm] (lbl c-ne) {c.ne};
%\draw[red,->] (lbl c-ne) -- (c.north east);
%\end{pgfonlayer}

%\node[font=\tiny, orange, below=of r] (lbl r-sw) {r.sw};
%\draw[red,->] (lbl r-sw) -- (r.south west);
\end{tikzpicture}
\end{document}

enter image description here

Changing c/.style to

c/.style={line width=0, fill=green!50, append after command={% <= for the border
    \pgfextra{%
        \begin{pgfinterruptpath}\begin{pgfonlayer}{foreground}
        \draw[] let \p1=($(\tikzlastnode.north east)+(-0\pgflinewidth,-0.5\pgflinewidth)$),
            \p2=($(\tikzlastnode.north west)+(0\pgflinewidth,-0.5\pgflinewidth)$),
            \p3=($(\tikzlastnode.south west)+(0\pgflinewidth,0.5\pgflinewidth)$),
            \p4=($(\tikzlastnode.south east)+(-0\pgflinewidth,0.5\pgflinewidth)$) in
            (\p1) -- (\p2) (\p3) -- (\p4);
        \end{pgfonlayer}\end{pgfinterruptpath}
    }
}},

gives

enter image description here

But you'll need TikZ 3 for this. TikZ 2 will draw the borders behind the filling colors.

share|improve this answer
    
I have used you answer to revise the "Custom Borders" section of my question. I'm having trouble with backgrounds/foregrounds now, as well as appropriate anchor point positions. –  derabbink Feb 21 at 9:13
    
I want a continuous border around the LCR-combination. But on my system (MiKTeX-pdfTeX 2.9.4902 (1.40.14) (MiKTeX 2.9 64-bit)) your updated answer does not produce a visible border. The border ends up behind the fill color. In my revised question I was merely experimenting with 3 different ways of creating a "custom border". –  derabbink Feb 21 at 13:36
    
I did a fresh install of MiKTeX 2.9.5105. Now pdflatex --version tells me MiKTeX-pdfTeX 2.9.4902 (1.40.14). \listfiles reveals that I have tikz.sty 2010/10/13 v2.10 (rcs-revision 1.76) and pgf.sty 2008/01/15 v2.10 (rcs-revision 1.12). But the borders are still behind the fill color. –  derabbink Feb 21 at 14:23
    
@derabbink It seems, it won't work with tikz v2.1, I don't have enough time to test. Can you install tikz v3 manually? –  Harish Kumar Feb 21 at 14:54

One possibility would be to use a multipart rectangle from the shapes.multipart library:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}

\tikzset{
mynode/.style={
  rectangle split,
  rectangle split parts=3,
  rectangle split horizontal,
  draw,
  rounded corners=6pt,
  rectangle split part fill={cyan!50, green!50,orange!50},
  rectangle split draw splits=false
  }
} 

\begin{document}

\begin{tikzpicture}
\node[mynode] at (2,3) {L\nodepart{two}C\nodepart{three}R};
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
I have investigated this option, but it appears that I cannot use coordinates such as c.south west in other \nodes. For me, that is a requirement. Maybe I'm overlooking something? –  derabbink Feb 21 at 13:42

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.