# Issues and potentiality of the tikzmark macro: dynamic box adaptation

Since I discovered the tikzmark macro I've been enthusiastic about it.

I think that it is possible to distinguish at least two versions of the command:

One answer in which both versions are used is http://tex.stackexchange.com/a/51590/13304.

Assume to use now the improved version. For what concern Highlight a column in equation or math environment the basic definition is:

\newcommand{\tikzmarkin}[1]{%
\tikz[remember picture with id=#1]
\draw[line width=1pt,rectangle,rounded corners,fill=\fillcol]
(pic cs:#1) ++(0.065,-0.15) rectangle (-0.05,0.32)
;}

\newcommand<>{\boxto}[1]{%
\only#2{\tikz[remember picture,overlay]
\draw[myframe,line width=1pt,fill=mybrown,,rectangle,rounded corners]
(pic cs:#1) ++(1.4,-.25) rectangle (-.2,0.4)
;}%
}


They have in common one thing, the fact that the rectangle is defined a priori. In the following example I will point out that this could be not convenient when used multiple times:

\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}

% to change colors
\newcommand{\fillcol}{white}
\newcommand{\bordercol}{red}

%% code by Andrew Stacey
% http://tex.stackexchange.com/questions/51582/background-coloring-with-overlay-specification-in-algorithm2e-beamer-package#51582

\makeatletter
\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
draw=\bordercol,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
},
if picture id/.code args={#1#2#3}{%
\@ifundefined{save@pt@#1}{%
\pgfkeysalso{#3}%
}{
\pgfkeysalso{#2}%
}
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
\def\tmk@label{#1}%
\def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\pgfutil@in@,{#1}%
\ifpgfutil@in@%
\tmk@labeldef#1\@nil
\else
\tmk@labeldef#1,(0pt,0pt)\@nil
\fi
\@ifundefined{save@pt@\tmk@label}{%
\tikz@scan@one@point\pgfutil@firstofone\tmk@def
}{%
\pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}
\makeatother

\newcommand{\tikzmarkin}[1]{%
\tikz[remember picture,overlay]
\draw[line width=1pt,rectangle,rounded corners,fill=\fillcol, draw=\bordercol]
(pic cs:#1) ++(0.065,-0.42) rectangle (-0.05,0.52) node [anchor=base] (#1){}
;}

\newcommand\tikzmarkend[2][]{%
\tikz[remember picture with id=#2] #1;}

\begin{document}
\begin{align*}
&x+\tikzmarkin{a}\dfrac{z}{y}\tikzmarkend{a}=100 \hspace{1cm} \text{perfect alignment}\\
\end{align*}

\end{document}


This is due to the fact that the rectangle has been defined to be suitable for the fraction and not for a single term.

To improve the method proposed based on the \tikzmark, my question is: it is possible to make those dimensions dynamic?

I mean not only for a math case, but also for simple text. For example:

\begin{document}

\begin{itemize}
\item this is a text to be \tikzmarkin{a}highlighted\tikzmarkend{a}
\item \tiny{this is a text to be \tikzmarkin{b}highlighted\tikzmarkend{b}}
\end{itemize}

\end{document}


where the tikzmark has been defined as:

\newcommand{\tikzmarkin}[1]{%
\tikz[remember picture,overlay]
\draw[line width=1pt,rectangle,rounded corners,fill=\fillcol, draw=\bordercol]
(pic cs:#1) ++(0.065,-0.16) rectangle (-0.05,0.32) node [anchor=base] (#1){}
;}


but when the text is \tiny, the rectangle dimensions could have been reduced a bit.

-
Perhaps this question helps in which I computed the precise height and width: A \boxed alternative with minimal spacing?, which is an improved version of A \boxed alternative with nicer spacing? – Peter Grill May 27 '12 at 19:36
Thanks, that's exactly the point. :) – Claudio Fiandrino May 28 '12 at 6:47

While I adore the power of the \tikzmark concept, too, it seems (with the necessity to compile twice) to be overkill for this situation. Why not just box the content and measure its size?

The following implements this idea based on some code I originally developed for this answer to a question about highlighting elements in a lstlisting environment while also keeping the syntax highlighting. The result is the \btHL command, which works like a font-changing command (such as \color or \bfseries) in that it affects everything until the end of the group (not across line breaks); this was a requirement for playing together with listings. The basic idea is to box the content and then typeset it inside a TikZ node. The bounding box of the tikzpicture, however, is adjusted to the size of the content, so that the highlighting does not take extra space (to prevent "jumping content" if used with beamer overlays).

As a quick solution, I have implemented your \tikzhighlight macro on this base; the code, however, could be simplified quite a bit if the content to highlight is always given as a macro parameter.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{amsmath}

\makeatletter
\newenvironment{btHighlight}[1][]
{\begingroup\tikzset{bt@Highlight@par/.style={#1}}\begin{lrbox}{\@tempboxa}}
{\end{lrbox}\bt@HL@box[bt@Highlight@par]{\@tempboxa}\endgroup}

\newcommand\btHL[1][]{%
\begin{btHighlight}[#1]\bgroup\aftergroup\bt@HL@endenv%
}
\def\bt@HL@endenv{%
\end{btHighlight}%
\egroup
}
\newcommand{\bt@HL@box}[2][]{%
\tikz[#1]{%
\pgfpathrectangle{\pgfpoint{0pt}{0pt}}{\pgfpoint{\wd #2}{\ht #2}}%
\pgfusepath{use as bounding box}%
\node[anchor=base west, fill=orange!30,outer sep=0pt,inner xsep=0.2em, inner ysep=0.1em,  #1]{\usebox{#2}};
}%
}
\makeatother

\newcommand{\tikzhighlight}[2][red]{%
{\btHL[fill=#1!10,draw=#1,rounded corners]#2}%
}

\begin{document}

\begin{itemize}
\item this is \tikzhighlight[yellow]{a text to be highlighted}
\item {\tiny{this is a text to be \tikzhighlight{highlighted}}}
\item \huge{this is a text to be \tikzhighlight{highlighted}}
\end{itemize}

\begin{align*}
&\tikzhighlight[green]{\ensuremath{x+\dfrac{z}{y}}}=100\\
&x+\tikzhighlight[blue]{\ensuremath{y}}=100
\end{align*}

\end{document}


Some additional fine tuning could be applied to the dimensioning of the boxes and the bounding box.

-
I see your point because you definitely did the job in a simpler way. However my question was not about how to highlight text, but how to improve the \tikzmark macro as defined in tex.stackexchange.com/questions/51582/… (that's my first reference :)) to adapt the width of boxes. The reason is explained in comments of tex.stackexchange.com/questions/57538/…. Anyway, +1 since you demonstrate me that exist also other methods to do so ;) – Claudio Fiandrino May 30 '12 at 19:01
@ClaudioFiandrino: Hm... I obviously have difficulties to understand what you actually want to achieve. The \tikzmark macro per se has nothing to do with boxes (it just marks a point), so it cannot 'adapt' to a width or a height of whatever. The questions you refer to all just use it as a vehicle to implement some sort of highlighting. Now you write that highlighting is not what you are after, so ... what exactly is it you are after? – Daniel May 30 '12 at 20:13
Maybe I wasn't clear. :) I'd like to study possible applications of the macro and of course the highlighting is one of them. Now, based on those questions, I saw the problem of box adaptation and my question, hope to be clear, was how to improve the method that uses as base the \tikzmark macro. – Claudio Fiandrino May 30 '12 at 21:16
@ClaudioFiandrino: Then I'd suggest to make very explicit that your question is of academic nature: You are not looking for a certain result, but a for a way to achieve a result under certain constraints in order to learn and explore. ("I want to learn about hammers. So given I have only a hammer: How to use it to drill a hole"). Note that, IMHO, this is perfectly okay. It's just that one should be explicit about it, as otherwise the question might be seen as an X-Y question, which are generally disouraged. – Daniel May 31 '12 at 8:09

Thanks to Peter Grill suggestion I developed a reasonable solution based on:

• Andrew's code to save the position of the picture;

• Peter's code to compute the height and the width of the box.

Here is my MWE:

\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{calc}

%% code by Andrew Stacey
% http://tex.stackexchange.com/questions/51582/background-coloring-with-overlay-specification-in-algorithm2e-beamer-package#51582

\makeatletter
\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
},
if picture id/.code args={#1#2#3}{%
\@ifundefined{save@pt@#1}{%
\pgfkeysalso{#3}%
}{
\pgfkeysalso{#2}%
}
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
\def\tmk@label{#1}%
\def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\pgfutil@in@,{#1}%
\ifpgfutil@in@%
\tmk@labeldef#1\@nil
\else
\tmk@labeldef#1,(0pt,0pt)\@nil
\fi
\@ifundefined{save@pt@\tmk@label}{%
\tikz@scan@one@point\pgfutil@firstofone\tmk@def
}{%
\pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}

% code by Peter Grill <modified>
%http://tex.stackexchange.com/questions/35319/a-boxed-alternative-with-minimal-spacing/35357#35357

\newcommand*{\@DrawBoxHeightSep}{0.1em}%
\newcommand*{\@DrawBoxDepthSep}{0.08em}%
\newcommand{\@DrawBox}[6][red]{%#1= style, #2=height, #3=depth, #4 left marker, #5 right marker, #6 text
\tikz[overlay,remember picture,baseline]
\draw[fill=#1!10,draw=#1,rounded corners]
($(pic cs:#4)+(-0.2em,#2+\@DrawBoxHeightSep)$) rectangle
($(pic cs:#5)+(0.2em,-#3-+\@DrawBoxDepthSep)$);
\tikz[overlay,remember picture,baseline]\node[anchor=base] at ($(pic cs:#4)!0.5!(pic cs:#5)$) {#6};
}

\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}

\newcounter{image}
\setcounter{image}{1}
\newdimen\@myBoxHeight%
\newdimen\@myBoxDepth%
\newcommand{\tikzhighlight}[2][red]{%
\settoheight{\@myBoxHeight}{#2}% Record height of box
\settodepth{\@myBoxDepth}{#2}% Record height of box
\tikzmark{l\theimage}#2\tikzmark{r\theimage}\@DrawBox[#1]{\@myBoxHeight}{\@myBoxDepth}{l\theimage}{r\theimage}{#2}% Draw the box
\stepcounter{image}
}
\makeatother

\begin{document}

\begin{itemize}
\item this is \tikzhighlight[yellow]{a text to be highlighted}
\item {\tiny{this is a text to be \tikzhighlight{highlighted}}}
\item \huge{this is a text to be \tikzhighlight{highlighted}}
\end{itemize}

\begin{align*}
&\tikzhighlight[green]{\ensuremath{x+\dfrac{z}{y}}}=100\\
&x+\tikzhighlight[blue]{\ensuremath{y}}=100
\end{align*}

\end{document}


which gives:

One remark: in math mode \ensuremath inside \tikzhighlight is fundamental to avoid errors.

Solution with extensible markers

The previous solution had, as a drawback, the necessity of inserting the content to be highlighted inside the command.

Another approach is to make the markers extendible in some sense, that is allowing the user to shift them to better fit the area to be highlighted.

This could be achieved declaring something like

\NewDocumentCommand{\tikzmarkin}{m D(){0.1,-0.18} D(){-0.1,0.35}}{%
\tikz[remember picture,overlay]
\draw[line width=1pt,rectangle,rounded corners,fill=\fillcol,draw=\bordercol]
(pic cs:#1) ++(#2) rectangle (#3)
;}


What are #2 and #3? If we consider:

\tikzmarkin{a}x+\dfrac{z}{y}=400\tikzmarkend{a}


#2 is the end marker while #3 is the in marker. Now the user can change the dimension of the box as he wants since it's not computed automatically: that's the cost of not having things inside the command.

Let's make a complete example:

\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{calc}

% to change colors
\newcommand{\fillcol}{blue!20}
\newcommand{\bordercol}{blue}


%% code by Andrew Stacey
% http://tex.stackexchange.com/questions/51582/background-coloring-with-overlay-specification-in-algorithm2e-beamer-package#51582

\makeatletter
\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
},
if picture id/.code args={#1#2#3}{%
\@ifundefined{save@pt@#1}{%
\pgfkeysalso{#3}%
}{
\pgfkeysalso{#2}%
}
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
\def\tmk@label{#1}%
\def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\pgfutil@in@,{#1}%
\ifpgfutil@in@%
\tmk@labeldef#1\@nil
\else
\tmk@labeldef#1,(0pt,0pt)\@nil
\fi
\@ifundefined{save@pt@\tmk@label}{%
\tikz@scan@one@point\pgfutil@firstofone\tmk@def
}{%
\pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}

\NewDocumentCommand{\tikzmarkin}{m D(){0.1,-0.18} D(){-0.1,0.35}}{%
\tikz[remember picture,overlay]
\draw[line width=1pt,rectangle,rounded corners,fill=\fillcol,draw=\bordercol]
(pic cs:#1) ++(#2) rectangle (#3)
;}

\newcommand\tikzmarkend[2][]{%
\tikz[remember picture with id=#2] #1;}

\begin{document}
\begin{align}
\tikzmarkin{a1}(0.05,-0.1)(-0.05,0.23)a_i\tikzmarkend{a1} + b_j = 10 \\
\tikzmarkin{c}c_j + d_j + a_i >= 30 \tikzmarkend{c}
\end{align}

$\tikzmarkin{a}x+\dfrac{z}{y}=400\tikzmarkend{a} \qquad\qquad \tikzmarkin{a2}(0.1,-0.4)(-0.1,0.5)x+\dfrac{z}{y}=400\tikzmarkend{a2}$
\vspace{1cm}
A integral:
\setfillcolor{red!10}
\setbordercolor{red}
$$V(z)=\sum_{\kappa=0}^{\infty}{\; \tikzmarkin{k}(0.1,-0.7)(-0.1,0.8) \int_{0}^{\infty}{\dfrac{\mathrm{e}^{-\lambda x}\cdot (\lambda x)^\kappa}{\kappa!} \, b(x)\,\mathrm{d} x}\cdot z^\kappa \tikzmarkend{k}}$$

\vspace{1cm}
\setfillcolor{green!10}
\setbordercolor{green!50!black}
\begin{equation*}
\left.\begin{array}{cc}
-2\cdot \tikzmarkin{r}2=& -4 \\
-2\cdot 1=& -2 \\
-2\cdot 0\tikzmarkend{r}=& 0
\end{array}\right\}
\left.\begin{array}{cc}
-2\cdot \tikzmarkin{r1}(0.035,-0.2)(-0.035,0.35)2=& -4 \\
-2\cdot 1=& -2 \\
-2\cdot 0\tikzmarkend{r1}=& 0
\end{array}\right\}
\end{equation*}
\end{document}


The result:

-
I seem to get Package tikz Error: Cannot parse this coordinate. with this and the MWE in the question?? – Peter Grill May 28 '12 at 19:12
Did you compile twice? – Claudio Fiandrino May 28 '12 at 19:13
Yes, I did compile twice – Peter Grill May 28 '12 at 19:13
I've just verified of not having made error with the cut and paste. For me works: I get ! Package tikz Error: Cannot parse this coordinate. the first time then the second time all goes right. – Claudio Fiandrino May 28 '12 at 19:17
Are you perhaps using an older version of tikz? I am using the latest libraries (updated this week) with TeXLive2011. – Peter Grill May 28 '12 at 19:19