Layer between a node and its text
The old and too localized solution where I defined an extra shape can be found in the history of this answer.
I can’t see a solution without re-using parts of the matrix.
Ideas:
Drawing and filling the rectangle shape on a background layer, similar to Cut one side of a rectangle node in TikZ, didn’t work: Apparently
\tikzlastnode
(or\tikzmatrixname-\tikzmatrixcurrentrow-\tikzmatriccurrentcolumn
) andpgfonlayer
don’t play nice and mess withinappend after command
.But, similar to solution 3, saving the draw and fill options for later use does work. Unfortunately, this deals differently with options that are given to
every even row
and the local|[<options>]|
which is the reason whyopacity=.5
anddraw
have to be given to them-2-1
again, but this can be made easier with a style that is given toevery even row
and as well to the local options.The
back
style re-uses its argument (#1
) with the optionopacity=0
; this serves the purpose of not changing the actual dimension of the nodes.Re-drawing the whole matrix where only the text is being typeset, realized be redefining PGF’s
\pgfusepath
or overwriting thefill
and thedraw
style, so that one can just re-use the same\matrix
call.This is the easiest solution, but re-draws the node’s content, therefore not usable when
text opacity
is applied.Saving the node’s text and typeset it again.
Unfortunatly, I couldn’t find a way to grab the node’s content and save it as plain text. (Reference: Using execute at begin node with \phantom and \pgfuseimage in TikZ?, Use node text as argument for a macro)
Maybe there is a solution that uses a few named saveboxes and the
lrbox
environment.- That is the reason I defined a
back
style that takes the node’s content, typesets it inside a\phantom
and saves it later with the node’s name to draw it on top of all (can be used inside apgflayer
, too, of course.
Code 1
\documentclass{beamer}
\usepackage{tikz,xparse,etoolbox,xstring}
\usetikzlibrary{matrix,backgrounds}
\definecolor{color3}{rgb}{0,1,0}\definecolor{color2}{rgb}{1,0,0}\definecolor{color1}{HTML}{999999}
\pgfdeclarelayer{myback}\pgfsetlayers{myback,background,main}
\tikzset{myfillcolor/.style = {draw=#1,fill=#1!50,rounded corners,line width=2pt}}
\NewDocumentCommand{\fhighlight}{O{color2} m m}{
\draw[myfillcolor=#1] ([shift={(.1cm,-.1cm)}]#2.north west)rectangle ([shift={(-.1cm,.1cm)}]#3.south east);
}
\def\backgroundtodrawlater{}
\newcommand*{\saveMe}[1]{%
\ifcsname iph\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname
\StrCount{\backgroundtodrawlater}{,}[\kommaCount]%
\StrBefore[\kommaCount]{\backgroundtodrawlater}{,}[\backgroundtodrawlater]
\fi
\ifx\backgroundtodrawlater\empty%
\xappto\backgroundtodrawlater{{#1}/\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn}%
\else%
\xappto\backgroundtodrawlater{,{#1}/\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn}%
\fi%
\expandafter\xdef\csname iph\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname{}%
}
\newcommand*{\drawMyBackBoxes}{%
\begin{pgfonlayer}{myback}
\foreach \opt/\name in \backgroundtodrawlater {
\expandafter\ifx\csname iph\name\endcsname\empty
% \typeout{opt="\opt", name="\name"}% debug
\expandafter\path\expandafter[\opt] (\name.south west) rectangle (\name.north east);
\expandafter\xdef\csname iph\name\endcsname{ }
\else
\expandafter\xdef\csname iph\name\endcsname{}
\fi
}
\end{pgfonlayer}
}
\tikzset{
back/.style={
#1,
opacity=0,
save path={#1},
},
save path/.code={\saveMe{#1}}
}
\begin{document}
\begin{frame}{Test frame}
\begin{tikzpicture}
\matrix [
ampersand replacement=\&,
matrix of nodes,
nodes={inner sep=0pt,text centered,opacity=.5,text opacity=1},
every even row/.style={nodes={
rectangle,
back={
draw,
fill=color1,
opacity=.5
},
minimum size=0.8cm,
font=\Large,
text height=2ex,
text depth=.25ex,
text centered,
text opacity=1,
}},
column 10/.style={nodes={text width=1cm}},
row 1/.style={minimum height=0.5cm},
row 5/.style={minimum height=0.5cm}
] (m) {
\& x \& x \& \& \\
|[back={fill=color1!50, draw, dashed}]| ~ \& x \& x \& x \& x \\
|[text height=0.2cm]| ~ \\
|[back={draw=none,fill=none}]| $x:$ \& x \& x \& x \& x \\
\& x \& \& \& \\
};
\begin{pgfonlayer}{background}
\only<2>{\fhighlight[color2]{m-2-2}{m-4-5}}
\only<3>{\fhighlight[color3]{m-2-1}{m-4-4}}
\end{pgfonlayer}
\drawMyBackBoxes
\end{tikzpicture}
\end{frame}
\end{document}
Code 2
\documentclass{beamer}
\usepackage{tikz,xparse}\usetikzlibrary{matrix,backgrounds}
\definecolor{color3}{rgb}{0,1,0}\definecolor{color2}{rgb}{1,0,0}\definecolor{color1}{HTML}{999999}
\tikzset{myfillcolor/.style = {draw=#1,fill=#1!50,rounded corners,line width=2pt}}
\NewDocumentCommand{\fhighlight}{O{color2} m m}{\draw[myfillcolor=#1] ([shift={(.1cm,-.1cm)}]#2.north west)rectangle ([shift={(-.1cm,.1cm)}]#3.south east);}
\newcommand{\repeatMeText}[1]{
#1%
\def\repeatMe{{% note the extra pair of braces, keeps changes local!
% \renewcommand{\pgfusepath}[1]{}% either this
\tikzset{
fill/.style={},% or this and
draw/.style={},% this
column sep=\pgflinewidth,% compensates for missing "draw"
row sep=.5\pgflinewidth% compensates for missing "draw"
}
#1
}}
}
\begin{document}
\begin{frame}{Test frame}
\begin{tikzpicture}
\repeatMeText{
\matrix [
ampersand replacement=\&,
matrix of nodes,
nodes={inner sep=0,text centered,opacity=.5,text opacity=1},
every even row/.style={nodes={
rectangle,
draw,
minimum size=0.8cm,
fill=color1,
font=\Large,
text height=2ex,
text depth=.25ex,
text centered,
}},
column 10/.style={nodes={text width=1cm}},
row 1/.style={minimum height=0.5cm},
row 5/.style={minimum height=0.5cm}
] (m) {
\& x \& x \& \& \\
|[fill=color1!50, dashed]|~ \& x \& x \& x \& x \\
|[text height=0.2cm]| ~ \\
|[draw=none,fill=none]| $x:$ \& x \& x \& x \& x \\
\& x \& \& \& \\
};
}
\only<2>{\fhighlight[color2]{m-2-2}{m-4-5}}
\only<3>{\fhighlight[color3]{m-2-1}{m-4-4}}
\only<2,3>{\repeatMe}
\end{tikzpicture}
\end{frame}
\end{document}
Code 3
\documentclass{beamer}
\usepackage{tikz,xparse,etoolbox,xstring}
\usetikzlibrary{matrix,backgrounds}
\definecolor{color3}{rgb}{0,1,0}\definecolor{color2}{rgb}{1,0,0}\definecolor{color1}{HTML}{999999}
\pgfdeclarelayer{myback}\pgfsetlayers{myback,background,main}
\tikzset{myfillcolor/.style = {draw=#1,fill=#1!50,rounded corners,line width=2pt}}
\NewDocumentCommand{\fhighlight}{O{color2} m m}{
\draw[myfillcolor=#1] ([shift={(.1cm,-.1cm)}]#2.north west)rectangle ([shift={(-.1cm,.1cm)}]#3.south east);
}
\def\backgroundtodrawlater{}
\newcommand*{\saveMe}[1]{%
\ifcsname iph\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname
\StrCount{\backgroundtodrawlater}{,}[\kommaCount]%
\StrBefore[\kommaCount]{\backgroundtodrawlater}{,}[\backgroundtodrawlater]
\fi
\ifx\backgroundtodrawlater\empty%
\xappto\backgroundtodrawlater{{#1}/\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn}%
\else%
\xappto\backgroundtodrawlater{,{#1}/\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn}%
\fi%
\expandafter\xdef\csname iph\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname{}%
}
\newcommand*{\drawMyBackBoxes}{%
\begin{pgfonlayer}{myback}
\foreach \opt/\name in \backgroundtodrawlater {
\expandafter\ifx\csname iph\name\endcsname\empty
% \typeout{opt="\opt", name="\name"}% debug
\expandafter\path\expandafter[\opt] (\name.south west) rectangle (\name.north east);
\expandafter\xdef\csname iph\name\endcsname{ }
\else
\expandafter\xdef\csname iph\name\endcsname{}
\fi
}
\end{pgfonlayer}
}
\tikzset{
back/.style={
#1,
opacity=0,
save path={#1},
},
save path/.code={\saveMe{#1}}
}
\begin{document}
\begin{frame}{Test frame}
\begin{tikzpicture}
\matrix [
ampersand replacement=\&,
matrix of nodes,
nodes={inner sep=0pt,text centered,opacity=.5,text opacity=1},
every even row/.style={nodes={
rectangle,
back={
draw,
fill=color1,
opacity=.5
},
minimum size=0.8cm,
font=\Large,
text height=2ex,
text depth=.25ex,
text centered,
text opacity=1,
}},
column 10/.style={nodes={text width=1cm}},
row 1/.style={minimum height=0.5cm},
row 5/.style={minimum height=0.5cm}
] (m) {
\& x \& x \& \& \\
|[back={fill=color1!50, draw, opacity=.5, dashed}]| ~ \& x \& x \& x \& x \\
|[text height=0.2cm]| ~ \\
|[back={draw=none,fill=none}]| $x:$ \& x \& x \& x \& x \\
\& x \& \& \& \\
};
\begin{pgfonlayer}{background}
\only<2>{\fhighlight[color2]{m-2-2}{m-4-5}}
\only<3>{\fhighlight[color3]{m-2-1}{m-4-4}}
\end{pgfonlayer}
\drawMyBackBoxes
\end{tikzpicture}
\end{frame}
\end{document}
Output 1
Output 2
Output 3
@Qrrbrbirlbel answer is very nice, but I think one could also proceed without saving the text. The trick is very simple: use at least three layers, myback
, highlight
and main
; in the main
layer there will be the text of the matrix, in the myback
layer the matrix fill and in the highlight
layer... the highlighting
. What is important here, is that the highlight
layer should be declared behind the main (text) but before the matrix fill (myback). Thus, with this approach, one should declare a posteriori how the matrix is filled and this is the only disadvantage I see.
The code:
\documentclass{beamer}
\usepackage{lmodern}
\usepackage{tikz,xparse}
\usetikzlibrary{matrix,backgrounds}
\definecolor{color3}{rgb}{0,1,0}
\definecolor{color2}{rgb}{1,0,0}
\definecolor{color1}{HTML}{999999}
\pgfdeclarelayer{myback} % layer to fill the matrix
\pgfdeclarelayer{highlight} % layer to highlight the matrix
\pgfsetlayers{myback,highlight,main}
\tikzset{my fill color/.style = {draw=#1,fill=#1!50,rounded corners,line width=2pt}}
\begin{document}
% For both commands the second argument could be used to select the layer: here
% is not really necessary since the default is required, but having this option may help
% for other purposes (I still have to think about them..)
\NewDocumentCommand{\fhighlight}{O{color2} O{highlight} m m}{
\begin{pgfonlayer}{#2}
\draw[my fill color=#1] ([shift={(.1cm,-.1cm)}]#3.north west)rectangle ([shift={(-.1cm,.1cm)}]#4.south east);
\end{pgfonlayer}
}
\NewDocumentCommand{\bhighlight}{O{black} O{myback} m m}{
\begin{pgfonlayer}{#2}
\draw[#1] (#3.north west)rectangle (#4.south east);
\end{pgfonlayer}
}
\begin{frame}{Test frame}
\begin{tikzpicture}
\matrix [
ampersand replacement=\&,
matrix of nodes,
nodes={inner sep=0,text centered},
every even row/.style={nodes={
minimum size=0.8cm,
%fill=color1,
font=\Large,
text height=2ex,
text depth=.25ex,
text centered,
}},
column 10/.style={nodes={text width=1cm}},
row 1/.style={minimum height=0.5cm},
row 5/.style={minimum height=0.5cm}
] (m) {
\& x\& x\&\&\\
~\&x\&x\&x\&x\\
|[text height=0.2cm]|~\\
$x:$\&x\&x\&x\&x\\
\& x\&\&\&\\
};
% the matrix fill always visible: put in last layer, myback
\bhighlight[fill=color1!50, dashed, opacity=0.5]{m-2-1}{m-2-1}
\foreach \i in {2,...,5}{
\pgfmathtruncatemacro\x{\i}
\bhighlight[draw,rectangle, opacity=0.5]{m-2-\x}{m-2-\x}
}
\foreach \i in {2,...,5}{
\pgfmathtruncatemacro\x{\i}
\bhighlight[draw,rectangle, opacity=0.5]{m-4-\x}{m-4-\x}
}
% matrix highlighting
\only<2>{\fhighlight[color2]{m-2-2}{m-4-5}}
\only<3>{\fhighlight[color3]{m-2-1}{m-4-4}}
\end{tikzpicture}
\end{frame}
\end{document}
The result: