Using TikZ Chains Library with labeled edges extension
The other day I need to create a diagram, and went in the TikZ way. I was using the chains library to produce the diagram. But I face some problems, I needed to add labels to the edges created by the chain. However, this is not supported natively by the library.
I found a cool code that exemplifies how to add the edges to the chain, but it removes the old notation
\chainin (node) [join=with srcNode by style]
and make you use a new definition. However, I still need to use the styles and the source node notation. So, I start digging in the chains library code and modify it to allow the use of the label notation from other examples. The fix is
\makeatletter
\def\tikz@lib@parse@join#1{%
\def\tikz@temp{#1}%
\ifx\tikz@temp\pgfutil@empty%
\tikz@lib@parse@join@by by \pgf@stop%
\else%
\pgfutil@in@{with }{#1}%
\ifpgfutil@in@% 'with [by] [label]'
\pgfutil@in@{by }{#1}%
\ifpgfutil@in@% 'with by [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'with by label'
\tikz@lib@parse@join@with@by@label#1\pgf@stop%
\else% 'with by'
\tikz@lib@parse@join@with@by#1\pgf@stop%
\fi%
\else% 'with [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'with label'
\tikz@lib@parse@join@with@label#1\pgf@stop%
\else% with
\tikz@lib@parse@join@with@by#1 by \pgf@stop%
\fi%
\fi%
\else% '[by] [label]'
\pgfutil@in@{by }{#1}%
\ifpgfutil@in@% 'by [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'by label'
\tikz@lib@parse@join@by@label#1\pgf@stop%
\else% 'by'
\tikz@lib@parse@join@by#1\pgf@stop%
\fi%
\else% '[label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'label'
\tikz@lib@parse@join@label#1\pgf@stop%
\else%
\tikz@lib@parse@join@by#1 by \pgf@stop%
\fi%
\fi%
\fi%
\fi%
}
\def\tikz@lib@parse@join@with@by@label with #1 by #2 label #3\pgf@stop{%
\tikzset{after node path={(#1)edge[every join,#2]#3(\tikzchaincurrent)}}%
}
\def\tikz@lib@parse@join@with@label with #1 label #2\pgf@stop{%
\tikzset{after node path={(#1)edge[every join]#2(\tikzchaincurrent)}}%
}
\def\tikz@lib@parse@join@by@label by #1 label #2\pgf@stop{%
\tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join,#1]#2(\tikzchaincurrent)\fi}}%
}
\def\tikz@lib@parse@join@label label #1\pgf@stop{%
\tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join]#1(\tikzchaincurrent)\fi}}%
}
\makeatother
This allows one to use the chains like:
\chainin (node) [join=with anotherNode by myStyle label {node[above] {some Tag}}];
\chainin (node) [join=by myStyle label {node[above] {some Tag}}];
Note that the order needs to be maintained, so you can use [with] [label] [tag] and omit any of those, while the order is maintained. A minimal working example is below:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes,% for the rectangle
chains,% provides the chains
scopes}% allows to replace \begin{scope} \end{scope} with {}
\makeatletter
\def\tikz@lib@parse@join#1{%
\def\tikz@temp{#1}%
\ifx\tikz@temp\pgfutil@empty%
\tikz@lib@parse@join@by by \pgf@stop%
\else%
\pgfutil@in@{with }{#1}%
\ifpgfutil@in@% 'with [by] [label]'
\pgfutil@in@{by }{#1}%
\ifpgfutil@in@% 'with by [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'with by label'
\tikz@lib@parse@join@with@by@label#1\pgf@stop%
\else% 'with by'
\tikz@lib@parse@join@with@by#1\pgf@stop%
\fi%
\else% 'with [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'with label'
\tikz@lib@parse@join@with@label#1\pgf@stop%
\else% with
\tikz@lib@parse@join@with@by#1 by \pgf@stop%
\fi%
\fi%
\else% '[by] [label]'
\pgfutil@in@{by }{#1}%
\ifpgfutil@in@% 'by [label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'by label'
\tikz@lib@parse@join@by@label#1\pgf@stop%
\else% 'by'
\tikz@lib@parse@join@by#1\pgf@stop%
\fi%
\else% '[label]'
\pgfutil@in@{label }{#1}%
\ifpgfutil@in@% 'label'
\tikz@lib@parse@join@label#1\pgf@stop%
\else%
\tikz@lib@parse@join@by#1 by \pgf@stop%
\fi%
\fi%
\fi%
\fi%
}
\def\tikz@lib@parse@join@with@by@label with #1 by #2 label #3\pgf@stop{%
\tikzset{after node path={(#1)edge[every join,#2]#3(\tikzchaincurrent)}}%
}
\def\tikz@lib@parse@join@with@label with #1 label #2\pgf@stop{%
\tikzset{after node path={(#1)edge[every join]#2(\tikzchaincurrent)}}%
}
\def\tikz@lib@parse@join@by@label by #1 label #2\pgf@stop{%
\tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join,#1]#2(\tikzchaincurrent)\fi}}%
}
\def\tikz@lib@parse@join@label label #1\pgf@stop{%
\tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join]#1(\tikzchaincurrent)\fi}}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[
nonterminal/.style={
rectangle,
minimum size=6mm,
very thick,
draw=red!50!black!50,
top color=white, % a shading that is white at the top...
bottom color=red!50!black!20, % and something else at the bottom
font=\itshape
},
terminal/.style={
rectangle,minimum size=6mm,rounded corners=3mm,
very thick,draw=black!50,
top color=white,bottom color=black!20,
font=\ttfamily
},
every on chain/.style={join}, every join/.style={->}
]
\matrix[column sep=4mm] {
% First row:
& & & & \node (plus) [terminal] {+};&\\
% Second row:
\node (ui1) [nonterminal] {unsigned integer};&
\node (dot) [terminal] {.}; &
\node (digit) [terminal] {digit}; &
\node (e) [terminal] {E}; &
& % space in between
\node (ui2) [nonterminal] {unsigned integer};\\
% Third row:
& & & & \node (minus)[terminal] {-};&\\
};
{ [start chain]
\chainin (ui1);
\chainin (dot);
\chainin (digit);
\chainin (e);
{ [start branch=plus]
\chainin (plus) [join=label {node[above left]{a label}}];
}
{ [start branch=minus]
\chainin (minus);
}
\chainin (ui2) [join=with chain/plus-end label {node[above right] {plus label}}, join=with chain/minus-end by dashed label {node [below right]{minus label}}];
}
\end{tikzpicture}
\end{document}
PS. This post was inspired by this TeX.SX question, and I put this answer also there. You can found more about (La)TeX there.








Talking