0% found this document useful (0 votes)
17 views57 pages

Tikzmark

The tikzmark package allows users to mark points on a page using the TikZ system, making it easy to reference these points later in documents. It requires loading the TikZ package and provides simple commands for marking and using these coordinates, including features for compatibility with the beamer class. The package has evolved since its original creation in 2009, adding various functionalities and commands to enhance its usability in LaTeX documents.

Uploaded by

sensatezy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views57 pages

Tikzmark

The tikzmark package allows users to mark points on a page using the TikZ system, making it easy to reference these points later in documents. It requires loading the TikZ package and provides simple commands for marking and using these coordinates, including features for compatibility with the beamer class. The package has evolved since its original creation in 2009, adding various functionalities and commands to enhance its usability in LaTeX documents.

Uploaded by

sensatezy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 57

The tikzmark package

Andrew Stacey
[email protected]

v1.15 from 2022/08/24

1 Introduction
The \tikzmark macro burst onto the scene in a blaze of glory on TeX-SX. Since
then, it has proved embarrassingly (to its original author) popular. The idea
behind it is extremely simple: that the machinery underneath TikZ provides a
way to “mark” a point on a page for further use. This functionality is already
provided by several other packages. The point of this one is that as TikZ can
provide this feature, if already loading TikZ then it makes sense to use the TikZ
version than another version. Moreover, if the goal is to use these marks with
some TikZ code then this version is already set up for that purpose (not that it
would be exactly difficult to add this to any of the other implementations).

2 Use
Using the \tikzmark is extremely simple. You need to load the tikz package and
then load tikzmark as a tikzlibrary. Thus in your preamble you should have
something like:
\usepackage{tikz}
\usetikzlibrary{tikzmark}

In your document, you can now type \tikzmark{<name>} at a point that you
want to remember. This will save a mark with name <name> for use later (or
earlier). To use it in a \tikz or tikzpicture, simply use the pic coordinate
system:
\tikz[remember picture] \draw[overlay] (0,0) -- (pic cs:<name>);
There are two important points to note:

1. The enveloping \tikz or tikzpicture must have the key remember picture
set.
This is because of how TikZ coordinates work. The coordinates inside a
TikZ picture are relative to its origin, so that origin can move around on
the page and not affect the internals of the picture. To use a point outside
the picture, therefore, the current picture not only has to know where that
point is on the page it also has to know where it itself is on the page. Hence
the remember picture key must be set.

1
2. The drawing command must have the overlay key set (or be in a scope or
picture where it is set).
This is to keep the bounding box of the current picture under control. Oth-
erwise, it would grow to encompass the remembered point as well as the
current picture. (This isn’t necessary if the remembered point is inside the
current picture.)

3 History
I wrote the original \tikzmark macro in 2009 for use in lecture slides prepared
with the beamer package. Its original definition was:
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}
Its first use was in the (inelegant) code:
\begin{frame}
\frametitle{Structure of Continuous Functions}

\begin{tikzpicture}[overlay, remember picture]


\useasboundingbox (0,0);
\draw<2-|trans: 0|handout: 0>[red,->] (bsp) .. controls +(-1,-1) and
($(cnvs.north)+(1,1)$) .. ($(cnvs.north)+(0,1)$) .. controls
($(cnvs.north)+(-1,1)$) and +(-1,0) .. (cnvs.north);
\draw<3-|trans: 0|handout: 0>[green!50!black,->] (cplt) .. controls
+(-1,-1) and +(-1,0) .. (mcplt.north);
\draw<4-|trans: 0|handout: 0>[blue,->] (norm) .. controls +(-1,-.5) and
($(nvs.north)+(0,1.5)$) .. ($(nvs.north)+(0,1.5)$) .. controls
($(nvs.north)+(-1.5,1.5)$) and +(-1.5,0) .. (nvs.north);
\draw<5-|trans: 0|handout: 0>[purple,->] (vector) .. controls +(-1,-1) and
($(vsp.north)+(2,2)$) .. ($(vsp.north)+(0,2)$) .. controls
($(vsp.north)+(-2,2)$) and +(-2,0) .. (vsp.north);
\end{tikzpicture}

\begin{theorem}
\centering
\(\big(C([0,1],\R),d_\infty\big)\) \\
is a \\
\alert{Banach\tikzmark{bsp} space}
\end{theorem}

\pause
\bigskip

\begin{itemize}
\item[\tikzmark{cnvs}]
{\color<.(2)->{green!50!black}Comp\tikzmark{cplt}lete}
{\color<.(3)->{blue}nor\tikzmark{norm}med}
{\color<.(4)->{purple}vector\tikzmark{vector} space}.

\bigskip
\bigskip
\pause

2
Structure of Continuous Functions

Theorem
 
C([0, 1], R), d∞
is a
Banach space

Complete normed vector space.

Cauchy sequences converge.


Metric from a norm.
Functions behave like vectors.

Figure 1: First use of tikzmark

\begin{itemize}[<+->]
\item[\tikzmark{mcplt}] {\color{green!50!black}Cauchy sequences converge.}
\medskip
\item[\tikzmark{nvs}] {\color{blue}Metric from a norm.}
\medskip
\item[\tikzmark{vsp}] {\color{purple}Functions behave like vectors.}
\end{itemize}
\end{itemize}

\end{frame}

This produced, on the final slide, Figure 1.


Its first appearance on TeX-SX was in an answer to a question about how
to put overlapping braces on a mathematical text. This was in July 2010. The
opening statement of the answer was not overly encouraging: “This may not be the
best solution. . . ”. And for a macro that would go on to become quite ubiquitous,
its initial appearance only garnered it 2 votes.
However, it started out in life as a useful macro for me and as such I found
more uses for it in my own code and thus more opportunity for using it to answer
questions on TeX-SX. The one that seems to have been where it got noticed came
in August 2010, again about putting braces in text but in a more complicated
fashion. From this answer, it got picked up, picked over, and picked apart. A
common use was in highlighting or adding marks to text.
Gradually, as it got used, it developed. A major revision dates from an answer

3
given in March 2012 where the question was actually about \tikzmark. This
version added two important features: a TikZ coordinate system for referencing
saved marks directly and the ability to refer to marks earlier in the document
than they are defined (the mechanism for remembering points uses the aux file
anyway so this was more about exposing the information earlier than anything
complicated). Then in October 2012 there was a question where it would have been
useful to remember which page the mark was on and a question where for some
reason using the \tikz macro didn’t work so the \pgfmark macro was introduced.
By this point, the \tikzmark command had morphed considerably from its
original definition. Experience has shown that on the TeX-SX site it has con-
tinued to be used in its original form as well as its current form. I’ve there-
fore taken the decision to reintroduce a form of the original command, now
called \tikzmarknode. It goes beyond the original version in that it uses some
\mathchoice trickery (inspired by this answer from Heiko Oberdiek) to hopefully
correctly choose the correct math style.
The original reason for not using nodes inside \tikzmark was to be able to
use the information from a \tikzmark before the point where it was defined (via
information saved into the aux file). Thanks to a question on TeX-SX about saving
node information, I’ve developed code that solves that issue with nodes. As it fits
in the general concept of this package, I’ve added that code to the \tikzmark
package.

4 Usage
This package defines the following commands and usable stuff.

4.1 Core Commands


1. \tikzmark[hdrawing commandi]{hnamei}
The mandatory argument is the name of the mark to be used to refer back
to this point later.
The \tikzmark command can take an optional parameter which is some
drawing command that can be put in a \tikz ... ; command. This draw-
ing command can be used to place a node or something similar at the marked
point, or to set some \tikzset keys. Sometimes this can be useful. Note,
though, that if this is used to define an offset coordinate then this will only
be available in the document after the \tikzmark command, even on later
runs.
If the beamer class is loaded then this command is made overlay-aware.

2. \tikzmark{hnamei}{hcoordinatei}
v1.2 of the tikzmark package introduced a new variant of \tikzmark which
works inside a tikzpicture. One feature of \tikzmark which isn’t part
of TikZ’s normal coordinate remembering system is the ability to use a
\tikzmark coordinate before it is defined (due to the use of the aux file).
This is potentially useful to have inside a tikzpicture and so it is now
possible to use \tikzmark inside a tikzpicture. The syntax is slightly
different as we need to specify the coordinates of a point to remember.

4
This was inspired by the question Refer to a node in tikz that will be defined
“in the future” (two passes)? on TeX-SX.

3. \pgfmark{hnamei}
This is a more basic form of the \tikzmark which doesn’t use any of the
\tikz overhead. One advantage of this command is that it doesn’t create
an hbox. It does, however, insert a whatsit into the stream so it will, for
example, stop two vertical spaces either side of it being merged. This can’t
be avoided.
If the beamer class is loaded then this command is made overlay-aware.
4. \iftikzmark{hnamei}{htrue codei}{hfalse codei}
This is a conditional to test if a particular mark is available. It executes
true code if it is and false code if not.

5. \iftikzmarkexists{hnamei}
This is a conditional to test if a particular mark is available which works
with the lower level TEX \else and \fi.
6. \iftikzmarkoncurrentpage{hnamei}
This is a conditional to test if a particular mark is on the current page; it
works with the lower level TEX \else and \fi.
7. \iftikzmarkonpage{hnamei}{hpagei}
This is a conditional to test if a particular mark is on a given page; it works
with the lower level TEX \else and \fi.

8. \tikzmarknode[hoptionsi]{hnamei}{hcontentsi}
This is a reincarnation of the original \tikzmark command which places its
contents inside a \tikz node. It also defines a tikzmark with the same name.
Using a sneaky trick with \mathchoice, it works inside a math environment.
The spacing either side might not be quite right as although it detects the
math style it doesn’t got beyond that. The options are passed to the node.
Two styles are attempted, one on the surrounding picture and one on the
node, which are:

• every tikzmarknode picture


• every tikzmarknode

To refer to the node, use usual TikZ coordinates. To refer to the underlying
tikzmark, use the special tikzmark coordinates (see below).
9. (pic cs:<name>) or (pic cs:<name>,<coordinate>)
This is the method for referring to a position remembered by \tikzmark
(or \pgfmark) as a coordinate in a tikzpicture environment (or \tikz
command). If the extra coordinate is specified then this is used in case
the mark name has not yet been defined (this can be useful for defining code
that does something sensible on the first run).

5
10. /tikz/save picture id=<name>
This is the TikZ key that is used by \tikzmark to actually save the con-
nection between the name and the picture coordinate. It can be used on an
arbitrary picture to save its origin as a tikzmark.
11. /tikz/check picture id
There are circumstances where, behind the scenes, a tikzpicture is ac-
tually placed in a box and processed several times (often this involves
\mathchoice). In such a situation, when defining nodes then the last one
“wins” in that each node remembers the id of the last processed picture.
However, only the one that is actually used has its location remembered on
the page (since the others don’t have a position). This can lead to the sit-
uation whereby a node becomes disassociated from its picture and so using
it for later reference fails. This key tries to get around that situation by
checking the aux file to see if the current picture was actually typeset last
time (by checking for the presence of the remembered location) and if it finds
that it wasn’t, it quietly appends the string discard- to each node name.
The idea being that the version of the picture that is actually typeset will
not have this happen and so its nodes “survive”.
12. /tikz/maybe define node=#1
The previous key can lead to undefined nodes on the first time that the
picture is processed. Using this key will ensure that the specified node is
aliased to its discard- version providing it doesn’t already exist. This is
purely to get rid of pointless error messages, and also should only be used
in conjunction with check picture id.
Note that due to the order in which code gets executed, check picture id
should be before any maybe define node keys.
13. /tikz/if picture id=#1#2#3
This is a key equivalent of the \iftikzmark command.

14. /tikz/if tikzmark on current page=#1#2#3


This is a key equivalent of the \iftikzmarkoncurrentpage command. If
true, the keys in #2 are executed, otherwise the keys in #3.
15. /tikz/if tikzmark on page=#1#2#3#4
This is a key equivalent of the \iftikzmarkonpage command.

16. /tikz/next page, /tikz/next page vector


It is possible to refer to a mark on a different page to the current page.
When this is done, the mark is offset by a vector stored in the key
/tikz/next page vector. The key /tikz/next page can be used to set
this to certain standard vectors by specifying where the “next page” is con-
sidered as lying corresponding to the current page. Possible values are (by
default) above, below, left, right, and ignore. (The last one sets the
vector to the zero vector.)
Previous versions of tikzmark tried to make this work correctly with the
mark being on, say, 5 pages further on but this got too fiddly so this version

6
just pretends that the mark is on the next or previous page and points to it
as appropriate.
17. /tikz/tikzmark prefix=<prefix> and /tikz/tikzmark suffix=<suffix>
These keys allow for the automatic addition of a prefix and/or suffix to each
\tikzmark name. The prefix and suffix are added both at time of definition
and of use, so providing one is in the same scope there is no difference in
at the user level when using prefixes and suffixes. What it can be useful for
is to make the \tikzmark names unique. In particular, if the beamer class
is loaded then an automatic suffix is added corresponding to the overlay.
This means that if a slide consists of several overlays with \tikzmarks on
them, and the positions of the \tikzmarks move then the resulting pictures
should look right. Without the automatic suffix, only the final positions of
the marks would be used throughout.
This was inspired by the question using tikzmark subnode with overlays
beamer on TeX-SX.

4.2 Pic and Scope Positioning


scope anchor, pic anchor, and surround pic.
These keys can be used to enable advanced positioning of scopes and pics. The
standard positioning of a pic places its internal origin at the location specified
on the \pic command. This is more limited than what is available to a node
whereby any of the defined anchors can be placed at the given position. The
key pic anchor allows a little more flexibility to pic positioning by allowing a
pic anchor to be defined and used as the point to place at the given position.
When invoking the pic the key pic anchor={coordinate} can be used to
specify a point inside the pic to use as the anchor. This point is evaluated inside
the pic so if using a node then the node name should be specified as if inside the
pic.
The node positioning syntax, things like below and below=5pt of, sets the
anchor of the following node. Using pic anchor without a coordinate uses this
anchor on the bounding box of the pic when positioning the pic.
Internally, this works by adjusting the location of the pic’s surrounding scope.
So the code can equally be used on scopes. For a scope, use the scope anchor
version on the scope directly. The keys name and anchor can be used on the scope
as if on a node with the same effect on the positioning.
The key surround pic saves the bounding box of the pic as if it were the
boundary of a rectangular node, using the name of the pic as the name of the
node.
This was inspired by the questions Anchoring TiKZ pics and Reposition Tikz
Scope After Size Known.

4.3 Subnodes
\subnode[options]{name}{content}
This produces a pseudo-node named name around the content. The design
purpose of this is to create a “subnode” inside a TikZ node. As far as TikZ is
concerned, the contents of a node is just a box. It therefore does not know anything
about it beyond its external size and so cannot easily determine the coordinates of

7
pieces inside. The \subnode command boxes its contents and saves the position
of that box and its dimensions. This information is stored in the same way that
PGF stores the necessary information about a node. It is therefore possible to use
ordinary node syntax (within a tikzpicture) to access this information. Thus
after \node {a \subnode{a}{sub} node}; it is possible to use a as a node. The
options are passed to the node construction mechanism, but note that the only
sensible options are those that affect the size and shape of the node: drawing
options are ignored (except in so far as they affect the size – as an example,
line width affects the node size).
There are two important points to make about this. The first is that, as with all
the tikzmark macros, the information is always one compilation old. The second
is that the pseudo-node is purely about coordinates: the path information is not
used and the contents are not moved. This is partly for reasons of implementation:
the pseudo-node is constructed when TikZ is not in “picture mode”. But also
interleaving the background path of the pseudo-node and any containing node
would be problematic and so is best left to the user.
The simplest way to turn a pseudo-node into a more normal node is to use the
fit library. Using the above example, \node[fit=(a),draw,inner sep=0pt] {};
would draw a rectangle around the word sub of exactly the same size as would
appear had a normal node been created.
Using a sneaky trick with \mathchoice, subnode works inside a math envi-
ronment. The spacing either side might not be quite right as although it detects
the math style it doesn’t got beyond that.
Note that because of the way that this works, the outer tikzpicture must
have the remember picture option set.

4.4 Node saving


The node saving system takes the information stored about a node and saves it for
later use. That later use can be in the same document, in which case it should be
saved just to the memory of the current TeX process, or it can be used earlier in
the same document or another document altogether (in particular, if the nodes are
defined in a tikzpicture that has been externalised, this can be used to import
the node information into the main file) in which cases the node data is saved to
a file.
When working with files, nodes are saved and restored in bulk. When working
in memory, nodes are saved and restored in named lists. Nodes are not actually
saved until the end of the tikzpicture in which they are defined, meaning that if
saving to memory then all the nodes in a tikzpicture will belong to the same list.
The keys for working with saving and restoring nodes are as follows.

• save node, save node=<name>


This is the key that indicates a node to be saved. The version with no
argument is to be used directly in the keys for a node and it saves that node.
With an argument then it saves a node that has been declared somewhere
in the current tikz picture (it may not always be convenient to issue the
save node key directly on the node itself). Since the list is saved up to the
end of the picture, this can be invoked before the node is defined.

• \SaveNode[group name]{name}

8
This command is for outside a tikzpicture and saves the named node directly.
The optional argument is a group name for saving to a group. If this is not
specified then the node is saved to a file.

• set node group=<name>


Nodes are grouped together into a list that can be saved either to a file or
for use later on in the document. This sets the name for the current group.
• restore nodes from list=<name>
This restores the node information from the named list to the current
tikzpicture. This is required both for when the node information comes
from a file or from earlier in the same document.
• save nodes to file
This is a true/false key which determines whether to save the node infor-
mation to a file.
• set saved nodes file name=<name>
This sets the file name for the saved nodes (the extension will be .nodes.
The default is to use the current TEX filename. This is set globally, and
once the file is opened then changing the name will have no effect. (The
file is not opened until it is actually needed to avoid creating empty files
unnecessarily.)
• restore nodes from file=<name>
This loads the node information from the file into the current document.
The <name> can have the syntax [options]{name}, where options can be
used to influence how the nodes are restored. The key transform saved nodes
(see below) can be given here. Another useful key is the name prefix key
which is applied to all restored nodes.
• transform saved nodes
A particular use-case for restoring saved nodes is to safely include one
tikzpicture inside another by creating an image out of the inner picture
and including it back in as a picture inside a node. In that situation, restoring
the nodes from the inner picture can make it possible to refer to coordinates
from the inner picture to the outer one. If there is a transformation in place
on the containing node, this key applies that transformation to all the nodes
in the inner picture.

5 Examples
The \tikzmark command has been used in numerous answers on TeX-SX.

5.1 Basic Examples


A simple example of the \tikzmark macro is the following.

9
\tikzset{tikzmark prefix=ex1-}
\[
\tikzmark{a} e^{i \pi/2} = i
\]

This\tikz[remember picture,overlay,baseline=0pt] \draw[->] (0,1em)


to[bend left] ([shift={(-1ex,1ex)}]pic cs:a); is an important
equation.

eiπ/2 = i
This is an important equation.

\tikzset{tikzmark prefix=ex2-}
\begin{itemize}
\item A first item,\tikzmark{b}
\item A second item,\tikzmark{c}
\item A third item.\tikzmark{d}
\end{itemize}
\begin{tikzpicture}[remember picture,overlay]
\draw[decorate,decoration={brace}] ({pic cs:c} |- {pic cs:b})
+(0,1em) -- node[right,inner sep=1em] {some items} ({pic cs:c}
|- {pic cs:d});
\end{tikzpicture}

• A first item,
• A second item, some items

• A third item.

\tikzset{tikzmark prefix=ex3-}
\begin{tikzpicture}[remember picture]
\node (a) at (0,0) {This has a \subnode{sub}{subnode} in it};
\draw[->] (0,-1) to[bend right] (sub);
\end{tikzpicture}

This has a subnode in it

An example using \tikzmark inside a tikzpicture

10
\tikzset{tikzmark prefix=ex4-}
\begin{tikzpicture}[remember picture,overlay]
\draw[->,line width=1mm,cyan] (pic cs:a) to[bend left] (pic cs:b);
\end{tikzpicture}

By placing the \tikzmark{a}code before the marks, the arrow goes


under the subsequent text and picture.

\begin{tikzpicture}
\filldraw[fill=gray] (0,0) circle[radius=1cm];
\tikzmark{b}{(-1,-1)}
\end{tikzpicture}

By placing the code before the marks, the arrow goes under the subsequent
text and picture.

The \tikmarknode puts a node around some text, which can be referred to
later, and adds a \tikzmark at its origin.

\tikzset{tikzmark prefix=ex5-}
Putting a node around \tikzmarknode{txt}{some text} means we can
connect text together, including in maths:
\[
\tikzmarknode{a}{\sum_{k=1}^n} k^{\tikzmarknode{b}{2}}
\]

\begin{tikzpicture}[remember picture,overlay]
\draw[->] (txt) -- (a);
\draw[->] (a.south) to[out=-90,in=-45] (b.south east);
\end{tikzpicture}

Putting a node around some text means we can connect text together,
including in maths:
X n
k2
k=1

The syntax for saving node data is illustrated by the following example.
File firstpicture.tex:

11
\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{tikzmark,shapes.geometric}
\begin{document}
\begin{tikzpicture}[save nodes to file]
\node[draw,rotate=-30,save node](1) at (-2,0) {1};
\draw[->] (0,0) -- (1);
\node[draw,ellipse,save node] (c) at (current bounding box.center)
{};
\end{tikzpicture}
\end{document}

File secondpicture.tex:

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{tikzmark,shapes.geometric}
\begin{document}
\begin{tikzpicture}[save nodes to file]
\node[draw,rotate=-70,save node] (2) at (2,0) {2};
\draw[->] (0,0) -- (2);
\node[draw,ellipse,save node] (c) at (current bounding box.center)
{};
\end{tikzpicture}
\end{document}

Main file:

12
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark}

\begin{document}
\begin{tikzpicture}

\node[draw,
rotate=30,
restore nodes from file={[transform saved nodes,name
prefix=pic-1-]{firstpicture}}
] (a-1) at (-2,-3) {\includegraphics{firstpicture.pdf}};

\node[draw,
rotate=70,
restore nodes from file={[transform saved nodes,name
prefix=pic-2-]{secondpicture}}
] (a-2) at (+2,+2) {\includegraphics{secondpicture.pdf}};

\draw[red] (pic-1-1.north west) -- (pic-1-1.north east) --


(pic-1-1.south east) -- (pic-1-1.south west) -- cycle;
\draw[red] (pic-2-2.north west) -- (pic-2-2.north east) --
(pic-2-2.south east) -- (pic-2-2.south west) -- cycle;

\node[red] at (pic-1-1) {1};


\node[red] at (pic-2-2) {2};

\draw (a-1) circle[radius=5pt];


\draw (a-2) circle[radius=5pt];

\draw (pic-1-1) -- (pic-2-2);


\end{tikzpicture}
\end{document}

This produces:

13
2

6 Additional Libraries
Some of the more ambitious uses of \tikzmark involve a fair bit of extra code and
so are worth gathering in to extra libraries of their own. These can be loaded via
\usetikzmarklibrary.
At present, there are three libraries: one for code listings which works with the
listings package, one for AMSMath equations, and one for highlighting.

6.1 Code Listings


If the listings package has been loaded then issuing
\usetikzmarklibrary{listings}
will load in some code to add marks to lstlisting environments. This code
places a mark at three places on a line of code in a listings environment. The
marks are placed at the start of the line, the first non-whitespace character, and
the end of the line (if the line is blank the latter two are not placed). (This has not
been extensively tested, it works by adding code to various “hooks” that are made
available by the listings package; it is quite possible that the hooks chosen are
both wrong and insufficient to cover all desired cases.)
These are inspired by questions such as Marking lines in listings and Macros
for code annotations.
In more detail, the listings library places lots of marks around the code. The
marks are:
• line-<name>-<number>-start at the start of each line.
• line-<name>-<number>-end at the end of each line.
• line-<name>-<number>-first at the first non-space character of the line
(assuming it exists).

14
The line numbers should match up with the line numbers in the code in that
any initial offset is also applied.
Not every mark is available on every line. If a line is blank, in particular, it
will only have a start mark. The following example shows this, where the red
dots are the start, the blue are end, and the green are first.

\tikzset{tikzmark prefix=ex6-}
\begin{tikzpicture}[remember picture]
\foreach \k in {0,...,7} {
\iftikzmark{line-code-\k-start}{\fill[red,overlay] (pic
cs:line-code-\k-start) circle[radius=4pt];}{\message{No start
for \k}}
\iftikzmark{line-code-\k-end}{\fill[blue,overlay] (pic
cs:line-code-\k-end) circle[radius=2pt];}{\message{No end for
\k}}
\iftikzmark{line-code-\k-first}{\fill[green,overlay] (pic
cs:line-code-\k-first) circle[radius=2pt];}{\message{No first
for \k}}
}
\draw[->,overlay] (0,0) -- (pic cs:line-code-5-first);
\draw[->,overlay] (0,0) -- (pic cs:line-code-5-start);
\draw[->,overlay] (0,0) -- (pic cs:line-code-5-end);
\node[above] at (0,0) {Line 5};
\end{tikzpicture}

\begin{lstlisting}[language=c,name=code,numbers=left]
#include <stdio.h>

int main(void)
{
printf("hello, world\n");
return 0;
}
\end{lstlisting}

Line 5

1 #include <stdio.h>
2
3 int main(void)
4 {
5 printf("hello,␣world\n");
6 return 0;
7 }

This example puts a fancy node behind certain lines of the code, computing
the necessary extents.

15
\balloon{comment}{more code}{3}{3}
\balloon{comment}{more code}{7}{8}
\begin{lstlisting}[language=c,name=more
code,numbers=left,firstnumber=3]
#include <stdio.h>

int main(void)
{
printf("hello, world\n");
return 0;
}
\end{lstlisting}

3 #include <stdio.h>
4
5 int main(void)
6 {
7 printf("hello,␣world\n");
8 return 0;
9 }

6.2 AMS Equation Environments


This is an experimental library.
If the amsmath package has been loaded then issuing
\usetikzmarklibrary{ams}
loads some code that places pseudo-nodes around the boxes that are used in
AMSMath’s various equation alignment environments, such as align and gather.
These environments work by constructing boxes with each of the pieces of the
equations that are then put together into the grid. This library hooks in to the
unboxing code, before the box is typeset then it measures it and stores that infor-
mation in various macros as if it were a TikZ node. The aim is that this doesn’t
disturb the placement, but as far as TikZ is concerned then there is a node there
that can be referred to later.
As it is experimental, even if this library is loaded then it isn’t automat-
ically switched on. To do that, use either the tikzmarkmath environment or
the \tikzmarkmath command. Each has an optional argument which is a pre-
fix for the node names (the default is equation). The node names are then
of the form <prefix>-<number>. The numbering is held in a counter called
tikzmarkequation and is reset when the command is invoked or the environ-
ment is started. As usual, redefining \thetikzmarkequation changes the styling
of the <number>.
To disable the marking, either end the environment or use \endtikzmarkmath.
The ending command explicitly removes the hook rather than rely on TEX group-
ings. It also prints out the number of nodes created to the log file and terminal.
This can be useful with figuring out which nodes to use, since the box that this li-
brary hooks into is used many times. For example, equation numbers are included
with this.
The box is also used when assembling a \sqrt[3]{4} command, and as that

16
uses \mathchoice then there are more boxes created than used. So the count of
number of nodes created can be more than are actually there.

\begin{tikzmarkmath}[pythagoras]

\begin{gather}
a^2 = b^2 + c^2
\end{gather}

\begin{gather}
a = \sqrt[2]{b^2 + c^2}
\end{gather}
\end{tikzmarkmath}

\begin{tikzpicture}[remember picture, overlay]


\foreach \k in {1,2,3,7,8} {
\draw[red] (pic cs:pythagoras-\k) -- ++(135:1)
node[draw,red,circle,font=\tiny,above left] {\k};
\node[draw,blue,fit=(pythagoras-\k),inner sep=0pt] {};
}
\end{tikzpicture}
1 2

a2 = b2 + c2 (1)

7 3 8

p
2
a= b2 + c2 (2)

6.3 Highlighting
I’ve returned to the highlighting library. The LATEX3 hook mechanism makes a
couple of things possible that were tricky before.
The idea of the highlighting mechanism is to use two \tikzmarks to mark a
start and end of a region to be highlighted. The region is considered to be formed
by lines of text, with the first mark at the baseline of the start and the second at
the baseline of the end.
The highlighting itself is done by inserting code in the shipout routine before
the page itself is laid out. So the highlighting is on a separate layer to the text itself,
which can be either behind or in front of the text layer. The hook mechanisem
also makes it relatively simple to support page breaks between the start and end
of highlighting.
Since the highlighting is separate to the flow of the text, it doesn’t make sense to
use an environment to mark the start and end of the highlighting so instead there
are two commands: \StartHighlighting[options] and \StopHighlighting, or
a single command \Highlight[options]{text} that just highlights the text. At
the moment, nesting highlighting is not supported.
The optional argument to \StartHighlighting (or \Highlight) consists of
key-value pairs that control the behaviour of the highlighted region. There are

17
particular keys in the /tikz/highlighter family which control the size of the
highlighted region.
The keys are as follows:

• direction
• layer
• initial height
• initial depth
• initial offset
• final height
• final depth
• final offset
• left margin
• right margin
• height
• depth
• offset
• margin

The highlighting code draws a region which can be styled with standard TikZ
keys, more of which in a moment. Although it is a single region, the intention is
to simulate using an actual highlighter. The first key, direction, is used to draw
the region as if the highlighter were used in a particular direction. The options
are horizontal, vertical, or box. The default is horizontal.
The second key, layer, determines whether the highlighter is rendered on the
background or foreground layer. Using the background layer puts the highlight-
ing underneath the text, which will make the text easier to read. The foreground
option puts the highlighting over the text, which can be used to fade the text.
The default is background.
The shape of the region depends on a few things, such as whether the high-
lighting starts and ends on the same line.
initial height
initial offset final offset

Single line

final depth

18
initial height
initial offset

Split line

final height

initial depth

Split line final offset

final depth
right margin

initial offset initial height

left margin
Multiple lines

final depth final offset

The vertical regions and the box are defined similarly. With the vertical
regions then the meaning of the height, depth, and offset are rotated 90◦ , and
the vertial regions don’t stretch to the page boundaries. The box region is always
a rectangle.
Once the region is defined, it can be styled using options directly on the
StartHighlighting or \Highlight command and by using the following styles:

• every highlight picture


• every <direction> highlight picture
• every <layer> highlight picture
• every highlight path
• every <direction> highlight path
• every <layer> highlight path
• highlight path
• <direction> highlight path
• <layer> highlight path

19
The picture keys are for the surrounding tikzpicture, while the path keys
are for the path itself.
Lastly, a word about scoping the options. Since the code that actually renders
the highlighting is processed when the page is shipped out, it may well be that the
settings in force when the highlighting was defined have changed. The keys that
adjust the size of the region (in the highlighter family) are saved at the moment
of invocation but keys such as the colour or whether to fill or draw the path are
not. Therefore, it is wise to use styles that persist to set the rendering styles.

The sun was shining on the sea, shining with all its might.
\StartHighlighting[fill=cyan!50]
And this was very odd because it was the middle of the night.
\StopHighlighting
The moon was up there sulkily because she thought the sun had no
business to be there after the day was done.
\StartHighlighting[fill=magenta!50]
‘‘It’s very rude of him,’’ she said, ‘‘to come and spoil the fun.’’
\StopHighlighting

\noindent The sun was shining on the sea, shining with all its
might.
And this was very odd because it was the middle of the night.
\StartHighlighting[fill=yellow!50]
The moon was up there sulkily because she thought the sun had no
business to be there after the day was done\StopHighlighting.
‘‘It’s very rude of him,’’ she said, ‘‘to come and spoil the fun.’’

The sun was shining on the sea, shining with all its might. And this was
very odd because it was the middle of the night. The moon was up there
sulkily because she thought the sun had no business to be there after the
day was done. “It’s very rude of him,” she said, “to come and spoil the
fun.”
The sun was shining on the sea, shining with all its might. And this was
very odd because it was the middle of the night. The moon was up there
sulkily because she thought the sun had no business to be there after the
day was done. “It’s very rude of him,” she said, “to come and spoil the
fun.”

7 Acknowledgements
The \tikzmark macro has been used and abused by many users of TeX-SX. Of
particular note (but in no particular order) are Peter Grill, Gonzalo Medina, Clau-
dio Fiandrino, percusse, and marmot. I would also like to mention David Carlisle
whose knowledge of TikZ continues to astound us all.

8 Implementation
8.1 Main Code
The save nodes code uses LATEX3.

20
1 \ProvidesFile{tikzlibrarytikzmark.code.tex}[%
2 2022/08/24
3 v1.15
4 TikZ library for marking positions in a document]
5 \RequirePackage{expl3, l3keys2e, xparse}

6 \tikzset{%
7 remember picture with id/.style={%
8 remember picture,
9 overlay,
10 save picture id=#1,
11 },
Not totally happy with using every picture here as it’s too easily overwritten
by the user. Maybe it would be better to patch endtikzpicture directly.
12 every picture/.append style={%
13 execute at end picture={%
14 \ifpgfrememberpicturepositiononpage%
15 \edef\pgf@temp{%
16 \noexpand\write\noexpand\pgfutil@auxout{%
17 \string\savepicturepage%
18 {\pgfpictureid}{\noexpand\arabic{page}}%
19 }%
20 }%
21 \pgf@temp
22 \fi%
23 },
24 },
There are times when some code is executed and then discarded, such as in
\mathchoice. This can seriously mess with how TikZ pictures are remembered as
the last pgfpictureid to be processed is the one that is used, but it is the one that
is used that is recorded in the aux file. This isn’t particularly a tikzmark issue,
but does come up from time to time with tikzmark as it’s all about remembering
locations.
In actual fact, it only occurs with \tikzmarknode since the issue is about how
nodes are associated with pictures.
The solution is to check to see if the pgfpictureid has been recorded in the
aux file and if it hasn’t, quietly prefix the node names with a discard term. This
needs to be used after remember picture has been invoked. It probably messes
with some other stuff so should only be used under controlled conditions, such as
\tikzmarknode.
25 check picture id/.code={
26 \ifpgfrememberpicturepositiononpage
27 \@ifundefined{pgf@sys@pdf@mark@pos@\pgfpictureid}{%
28 \tikzset{%
29 name prefix/.get=\tzmk@name@prefix,
30 name prefix/.prefix=discard-,
31 execute at end picture={%
32 \tikzset{name prefix/.expand once=\tzmk@name@prefix}%
33 },
34 }%
35 }{}%
36 \fi

21
37 },
We also want a failsafe that quietly handles the case where the document hasn’t
been compiled enough times (once) to get the information into the aux file. There
will already be messages about needing reruns so we don’t need to add to that.
We simply ensure that the node exists.
38 maybe define node/.style={%
39 execute at end picture={%
40 \ifpgfrememberpicturepositiononpage
41 \@ifundefined{pgf@sh@pi@\tikz@pp@name{#1}}{%
42 \pgfnodealias{\tikz@pp@name{#1}}{discard-\tikz@pp@name{#1}}%
43 }{}%
44 \fi
45 }%
46 },
The positions are already recorded in the aux file, all we really need to do is
provide them with better names.
47 save picture id/.code={%
48 \protected@write\pgfutil@auxout{}{%
49 \string\savepointas%
50 {\tikzmark@pp@name{#1}}{\pgfpictureid}{0pt}{0pt}}%
51 },
Provides a way to test if a picture has already been saved (in particular, can avoid
errors on first runs)
52 if picture id/.code args={#1#2#3}{%
53 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
54 \pgfkeysalso{#3}%
55 }{
56 \pgfkeysalso{#2}%
57 }
58 },
Page handling
59 next page/.is choice,
60 next page vector/.initial={\pgfqpoint{0pt}{0pt}},
61 next page/below/.style={%
62 next page vector={\pgfqpoint{0pt}{-\the\paperheight}}%
63 },
64 next page/above/.style={%
65 next page vector={\pgfqpoint{0pt}{\the\paperheight}}%
66 },
67 next page/left/.style={%
68 next page vector={\pgfqpoint{-\the\paperwidth}{0pt}}%
69 },
70 next page/right/.style={%
71 next page vector={\pgfqpoint{\the\paperwidth}{0pt}}%
72 },
73 next page/ignore/.style={%
74 next page vector={\pgfqpoint{0pt}{0pt}}%
75 },
76 if tikzmark on current page/.code n args={3}{%
77 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
78 \pgfkeysalso{#3}%

22
79 }{%
80 \@ifundefined{%
81 save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname
82 }{%
83 \pgfkeysalso{#3}%
84 }{%
85 \ifnum\csname save@pg@%
86 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
87 \endcsname=\the\value{page}\relax%
88 \pgfkeysalso{#2}%
89 \else
90 \pgfkeysalso{#3}%
91 \fi
92 }%
93 }%
94 },
95 if tikzmark on page/.code n args={4}{%
96 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
97 \pgfkeysalso{#4}%
98 }{%
99 \@ifundefined{%
100 save@pg@\csname save@pt@\tikzmark@pp@name{#1}@label\endcsname%
101 }{%
102 \pgfkeysalso{#4}%
103 }{%
104 \ifnum\csname save@pg@%
105 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
106 \endcsname=#2\relax%
107 \pgfkeysalso{#3}%
108 \else
109 \pgfkeysalso{#4}%
110 \fi
111 }%
112 }%
113 },
Prefix and suffix for tikzmark names, shamelessly borrowed from the main tikz
code
114 tikzmark prefix/.initial=,%
115 tikzmark suffix/.initial=,%
116 tikzmark clear ixes/.style={
117 tikzmark prefix={},
118 tikzmark suffix={}
119 },
Tikzmarks can be used to adjust the position of a scope or pic so that an internally
defined coordinate is used to locate the scope or pic.
The key used to adjust the location is scope anchor={coordinate} for scopes
and pic anchor={coordinate} for pics, where coordinate is evaluated inter-
nally to the scope or pic, so can use node names.
120 scope anchor location/.initial={(0,0)},
121 scope anchor location/.default=@auto,
122 pic anchor/.style={
123 scope anchor location={#1},
124 next pic/.append style={

23
125 adjust scope position,
126 }
127 },
128 scope anchor/.style={
129 scope anchor location={#1},
130 adjust scope position,
131 },
The code that does the adjustment is added to the pic on its enclosing scope using
the every pic key.
132 adjust scope position/.code={%
133 \pgfutil@ifundefined{tikz@fig@name}%
134 {\let\tikz@fig@name=\pgfutil@empty}{}%
135 \tikz@resetexpandcount%
136 \tikz@fig@mustbenamed
137 \pgfkeysgetvalue{/tikz/scope anchor location}\tkzmk@anchor
138 \ifx\tkzmk@anchor\tikz@auto@text
139 \tikzset{local bounding box/.expanded=\tikz@fig@name}%
140 \def\tkzmk@anchor{(\tikz@fig@name.\tikz@anchor)}%
141 \fi
142 \tikz@scan@one@point
143 \pgfutil@firstofone(pic cs:\tikz@fig@name-origin)\relax
144 \pgf@xa=\pgf@x
145 \pgf@ya=\pgf@y
146 \tikz@scan@one@point
147 \pgfutil@firstofone(pic cs:\tikz@fig@name-anchor)\relax
148 \advance\pgf@xa by -\pgf@x
149 \advance\pgf@ya by -\pgf@y
150 \tikzset{
151 shift={(\the\pgf@xa,\the\pgf@ya)},
152 execute at end scope={%
153 \tikzmark{\tikz@fig@name-origin}{(0,0)}%
154 \tikzmark{\tikz@fig@name-anchor}{\tkzmk@anchor}%
155 }
156 }
157 },
To install this code on a pic, we hook in to the pic’s enclosing scope using
the every pic key. To avoid this bubbling down to pics within pics, we clear
it once it has been executed. So any code that triggers this adjustment adds
adjust pic position to the !next pic! style.
158 every pic/.append style={
159 next pic/.try,
160 next pic/.style={}
161 },
This code remembers the bounding box of a pic, saving it as if it were a node.
162 save pic bounding box/.code={
163 \tikz@fig@mustbenamed
164 \tikzset{local bounding box/.expanded=\tikz@fig@name}
165 },
166 surround pic/.style={
167 next pic/.append style={
168 save pic bounding box
169 }

24
170 },
171 }

\tikzmark@pp@name
172 \def\tikzmark@pp@name#1{%
173 \csname pgfk@/tikz/tikzmark prefix\endcsname%
174 #1%
175 \csname pgfk@/tikz/tikzmark suffix\endcsname%
176 }%

\savepointas This is what gets written to the aux file.


177 \def\savepointas#1#2#3#4{%
178 \expandafter\gdef\csname save@pt@#1\endcsname{#2}%
179 \expandafter\gdef\csname save@pt@#1@offset\endcsname%
180 {\pgfqpoint{#3}{#4}}%
181 }
182 \def\savepicturepage#1#2{%
183 \expandafter\gdef\csname save@pg@#1\endcsname{#2}%
184 }

\tikzmarkalias Alias a tikzmark to another name (used in tikzmarknode). The alias is saved to
the aux-file so that it is available prior to the definition. The private one doesn’t
use the prefix-suffix for greater internal flexibility. The public one does.
185 \def\@tikzmarkalias#1#2{%
186 \@ifundefined{save@pt@#2}{}{%
187 \pgf@node@gnamelet{save@pt@#1}{save@pt@#2}%
188 \pgf@node@gnamelet{save@pt@#1@offset}{save@pt@#2@offset}%
189 \protected@write\pgfutil@auxout{}{%
190 \string\savepointas%
191 {#1}{\csname save@pt@#2\endcsname}%
192 \expandafter\expandafter\expandafter
193 \@gobble\csname save@pt@#2@offset\endcsname
194 }%
195 }%
196 }
197 \def\tikzmarkalias#1#2{%
198 \@tikzmarkalias{\tikzmark@pp@name{#1}}{\tikzmark@pp@name{#2}}%
199 }

\tmk@labeldef Auxiliary command for the coordinate system.


200 \def\tmk@labeldef#1,#2\@nil{%
201 \edef\tmk@label{\tikzmark@pp@name{#1}}%
202 \def\tmk@def{#2}%
203 }

pic This defines the new coordinate system.


204 \tikzdeclarecoordinatesystem{pic}{%
205 \pgfutil@in@,{#1}%
206 \ifpgfutil@in@%
207 \tmk@labeldef#1\@nil
208 \else
209 \tmk@labeldef#1,(0pt,0pt)\@nil
210 \fi

25
211 \@ifundefined{save@pt@\tmk@label}{%
212 \expandafter\tikz@scan@one@point
213 \expandafter\pgfutil@firstofone\tmk@def\relax
214 }{%
215 \pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}%
216 \save@orig@pic%
217 \pgfsys@getposition{\pgfpictureid}\save@this@pic%
218 \pgf@process{\pgfpointorigin\save@this@pic}%
219 \pgf@xa=\pgf@x
220 \pgf@ya=\pgf@y
221 \pgf@process{\pgfpointorigin\save@orig@pic}%
222 \advance\pgf@x by -\pgf@xa
223 \advance\pgf@y by -\pgf@ya
224 \pgf@xa=\pgf@x
225 \pgf@ya=\pgf@y
226 \pgf@process%
227 {\pgfpointorigin\csname save@pt@\tmk@label @offset\endcsname}%
228 \advance\pgf@xa by \pgf@x
229 \advance\pgf@ya by \pgf@y
230 \@ifundefined{save@pg@\csname save@pt@\tmk@label\endcsname}{}{%
231 \@ifundefined{save@pg@\pgfpictureid}{}{%
232 \pgfkeysvalueof{/tikz/next page vector}%
233 \edef\tmk@pg{%
234 \the\numexpr \csname save@pg@%
235 \csname save@pt@\tmk@label\endcsname\endcsname%
236 -
237 \csname save@pg@\pgfpictureid\endcsname\relax%
238 }%
239 \ifnum \tmk@pg > 0 \relax
240 \advance \pgf@xa by \pgf@x\relax
241 \advance \pgf@ya by \pgf@y\relax
242 \fi
243 \ifnum \tmk@pg < 0 \relax
244 \advance \pgf@xa by -\pgf@x\relax
245 \advance \pgf@ya by -\pgf@y\relax
246 \fi
247 }%
248 }%
249 \pgf@x=\pgf@xa
250 \pgf@y=\pgf@ya
251 \pgftransforminvert
252 \pgf@pos@transform{\pgf@x}{\pgf@y}%
253 }%
254 }

\tikzmark The active/non-active semi-colon is proving somewhat hazardous to \tikzmark


(see Tikzmark and french seem to conflict and Clash between tikzmark, babel
package (french) and babel tikzlibrary) so \tikzmark now uses the brace-delimited
version of the \tikz command.
This version is for when we’re outside a tikzpicture environment
255 \newcommand\tikzmark@outside[2][]{%
256 \tikzset{external/export next/.try=false}%
257 \tikz[remember picture with id=#2]{#1}%
258 }

26
This is for when we’re inside a tikzpicture environment
259 \def\tikzmark@inside#1#2{%
260 \tikzset{remember picture}%
261 \tikz@resetexpandcount%
262 \tikz@scan@one@point\pgfutil@firstofone#2\relax
263 \pgf@pos@transform{\pgf@x}{\pgf@y}%
264 \protected@write\pgfutil@auxout{}{%
265 \string\savepointas%
266 {\tikzmark@pp@name{#1}}{\pgfpictureid}{\the\pgf@x}{\the\pgf@y}}%
267 }

And finally, the ultimate invoker:


268 \def\tikzmark{%
269 \ifx\pgfpictureid\@undefined
270 \let\tikzmark@next=\tikzmark@outside
271 \else
272 \relax
273 \ifx\scope\tikz@origscope\relax
274 \let\tikzmark@next=\tikzmark@outside
275 \else
276 \let\tikzmark@next=\tikzmark@inside
277 \fi
278 \fi
279 \tikzmark@next%
280 }

\pgfmark
281 \newcommand\pgfmark[1]{%
282 \bgroup
283 \global\advance\pgf@picture@serial@count by1\relax%
284 \edef\pgfpictureid{pgfid\the\pgf@picture@serial@count}%
285 \pgfsys@markposition{\pgfpictureid}%
286 \edef\pgf@temp{%
287 \noexpand\write\noexpand\pgfutil@auxout{%
288 \string\savepicturepage
289 {\pgfpictureid}{\noexpand\arabic{page}}%
290 }%
291 }%
292 \pgf@temp
293 \protected@write\pgfutil@auxout{}{%
294 \string\savepointas
295 {\tikzmark@pp@name{#1}}{\pgfpictureid}{0pt}{0pt}}%
296 \egroup
297 }

If the beamer class is used, make the commands overlay aware.


\tikzmark<>
298 \@ifclassloaded{beamer}{
299 \renewcommand<>{\tikzmark@outside}[2][]{%
300 \only#3{\beameroriginal{\tikzmark@outside}[{#1}]{#2}}%
301 }
302 \renewcommand<>{\tikzmark@inside}[2]{%
303 \only#3{\beameroriginal{\tikzmark@inside}{#1}{#2}}%

27
304 }
305 }{}

\pgfmark<>
306 \@ifclassloaded{beamer}{
307 \renewcommand<>{\pgfmark}[1]{\only#2{\beameroriginal{\pgfmark}{#1}}}
308 }{}

If beamer is loaded, add a suffix based on the frame number


309 \@ifclassloaded{beamer}{
310 \tikzset{
311 tikzmark suffix=-\the\beamer@slideinframe
312 }
313 }{}

\iftikzmark
314 \newif\iftikzmark@
315 \newcommand\iftikzmark[3]{%
316 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
317 #3%
318 }{%
319 #2%
320 }%
321 }%

A version suitable for \if ... \else ... \fi.


322 \newcommand\iftikzmarkexists[1]{%
323 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
324 \tikzmark@false%
325 }{%
326 \tikzmark@true%
327 }%
328 \iftikzmark@
329 }%

\iftikzmarkonpage
330 \newcommand\iftikzmarkonpage[2]{%
331 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
332 \tikzmark@false
333 }{%
334 \@ifundefined{save@pg@%
335 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
336 }{%
337 \tikzmark@false
338 }{%
339 \ifnum\csname save@pg@%
340 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
341 \endcsname=#2\relax%
342 \tikzmark@true
343 \else
344 \tikzmark@false
345 \fi
346 }%
347 }%

28
348 \iftikzmark@
349 }

\iftikzmarkoncurrentpage
350 \newcommand\iftikzmarkoncurrentpage[1]{%
351 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
352 \tikzmark@false
353 }{%
354 \@ifundefined{save@pg@%
355 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
356 }{%
357 \tikzmark@false
358 }{%
359 \ifnum\csname save@pg@%
360 \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
361 \endcsname=\the\value{page}\relax%
362 \tikzmark@true
363 \else
364 \tikzmark@false
365 \fi
366 }%
367 }%
368 \iftikzmark@
369 }

\subnode Note: much of this code was inevitably adapted from the node defining code in
the TikZ/PGF sources.
The \pgfmark applies the current tikzmark prefix/suffix. The current node
prefix/suffix is applied by using the name= key.
370 \def\subnode@#1#2#3{%
371 \begingroup
372 \pgfmark{#2}%
373 \setbox\pgfnodeparttextbox=\hbox\bgroup #3\egroup
374 \tikzset{every subnode/.try,#1,name=#2}%
375 \pgfpointorigin
376 \tikz@scan@one@point\pgfutil@firstofone(pic cs:#2)\relax
377 \advance\pgf@x by .5\wd\pgfnodeparttextbox
378 \advance\pgf@y by .5\ht\pgfnodeparttextbox
379 \advance\pgf@y by -.5\dp\pgfnodeparttextbox
380 \pgftransformshift{}%
381 \setbox\@tempboxa=\hbox\bgroup
382 {%
383 \let\pgf@sh@savedmacros=\pgfutil@empty% MW
384 \let\pgf@sh@savedpoints=\pgfutil@empty%
385 \def\pgf@sm@shape@name{rectangle}% CJ % TT added prefix!
386 \pgf@sh@s@rectangle%
387 \pgf@sh@savedpoints%
388 \pgf@sh@savedmacros% MW
389 \pgftransformshift{%
390 \pgf@sh@reanchor{rectangle}{center}%
391 \pgf@x=-\pgf@x%
392 \pgf@y=-\pgf@y%
393 }%
394 \expandafter\pgfsavepgf@process

29
395 \csname pgf@sh@sa@\tikz@fig@name\endcsname{%
396 \pgf@sh@reanchor{rectangle}{center}% FIXME : this is double work!
397 }%
398 % Save the saved points and the transformation matrix
399 \edef\pgf@node@name{\tikz@fig@name}%
400 \ifx\pgf@node@name\pgfutil@empty%
401 \else%
402 \expandafter\xdef
403 \csname pgf@sh@ns@\pgf@node@name\endcsname{rectangle}%
404 \edef\pgf@sh@@temp{%
405 \noexpand\gdef\expandafter
406 \noexpand\csname pgf@sh@np@\pgf@node@name\endcsname}%
407 \expandafter\pgf@sh@@temp\expandafter{%
408 \pgf@sh@savedpoints}%
409 \edef\pgf@sh@@temp{%
410 \noexpand\gdef\expandafter
411 \noexpand\csname pgf@sh@ma@\pgf@node@name\endcsname}% MW
412 \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedmacros}% MW
413 \pgfgettransform\pgf@temp
414 \expandafter\xdef
415 \csname pgf@sh@nt@\pgf@node@name\endcsname{\pgf@temp}%
416 \expandafter\xdef
417 \csname pgf@sh@pi@\pgf@node@name\endcsname{\pgfpictureid}%
418 \fi%
419 }%
420 \egroup
421 \box\pgfnodeparttextbox
422 \endgroup
423 }
424
425 \newcommand\subnode[3][]{%
426 \ifmmode
427 \mathchoice{%
428 \subnode@{#1}{#2-d}{\(\displaystyle #3\)}%
429 }{%
430 \subnode@{#1}{#2-t}{\(\textstyle #3\)}%
431 }{%
432 \subnode@{#1}{#2-s}{\(\scriptstyle #3\)}%
433 }{%
434 \subnode@{#1}{#2-ss}{\(\scriptscriptstyle #3\)}%
435 }%
436 \let\pgf@nodecallback\pgfutil@gobble
437 \def\tzmk@prfx{pgf@sys@pdf@mark@pos@pgfid}%
438 \edef\tzmk@pic{\tzmk@prfx\the\pgf@picture@serial@count}
439 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
440 \edef\tzmk@pic%
441 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-1\relax}%
442 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
443 \edef\tzmk@pic%
444 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-2\relax}%
445 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
446 \edef\tzmk@pic%
447 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-3\relax}%
448 \expandafter\ifx\csname\tzmk@pic\endcsname\relax

30
449 \pgfutil@ifundefined{pgf@sh@ns@\tikz@pp@name{#2}}{%
450 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
451 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
452 }{}%
453 \else
454 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-d}}%
455 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-d}}%
456 \fi
457 \else
458 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
459 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
460 \fi
461 \else
462 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-s}}%
463 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-s}}%
464 \fi
465 \else
466 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-ss}}%
467 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-ss}}%
468 \fi
469 \else
470 \subnode@{#1}{#2}{#3}%
471 \fi
472 }
473

\tikzmarknode The \tikzmark macro has changed considerably since its first inception, but there
does still seem to be a use for the original version which put stuff inside a node.
This command reintroduces that command.
It does its best to work inside a math environment by a sneaky trick involving
\mathchoice: the remember picture key means that only the picture id of the
typeset box is saved to the aux file. So comparing the possible picture ids of the
four options with the one read from the aux file, we can figure out which box was
actually used.
474 \def\tikzmarknode@#1#2#3{%
475 \tikzset{external/export next/.try=false}%
476 \tikz[%
477 remember picture,
478 save picture id={#2},
479 check picture id,
480 maybe define node={#2},
481 baseline=(#2.base),
482 every tikzmarknode picture/.try
483 ] {
484 \node[
485 anchor=base,
486 inner sep=0pt,
487 minimum width=0pt,
488 name={#2},
489 node contents={#3},
490 every tikzmarknode/.try,
491 #1
492 ]}%

31
493 }
494
495 \newcommand\tikzmarknode[3][]{%
496 \ifmmode
497 \mathchoice{%
498 \tikzmarknode@{#1}{#2-d}{\(\displaystyle #3\)}%
499 }{%
500 \tikzmarknode@{#1}{#2-t}{\(\textstyle #3\)}%
501 }{%
502 \tikzmarknode@{#1}{#2-s}{\(\scriptstyle #3\)}%
503 }{%
504 \tikzmarknode@{#1}{#2-ss}{\(\scriptscriptstyle #3\)}%
505 }%
506 \let\pgf@nodecallback\pgfutil@gobble
507 \def\tzmk@prfx{pgf@sys@pdf@mark@pos@pgfid}%
508 \edef\tzmk@pic{\tzmk@prfx\the\pgf@picture@serial@count}%
509 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
510 \edef\tzmk@pic%
511 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-1\relax}%
512 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
513 \edef\tzmk@pic%
514 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-2\relax}%
515 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
516 \edef\tzmk@pic%
517 {\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-3\relax}%
518 \expandafter\ifx\csname\tzmk@pic\endcsname\relax
519 \pgfutil@ifundefined{pgf@sh@ns@\tikz@pp@name{#2}}{%
520 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
521 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
522 }{}%
523 \else
524 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-d}}%
525 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-d}}%
526 \fi
527 \else
528 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
529 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
530 \fi
531 \else
532 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-s}}%
533 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-s}}%
534 \fi
535 \else
536 \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-ss}}%
537 \@tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-ss}}%
538 \fi
539 \else
540 \tikzmarknode@{#1}{#2}{#3}%
541 \fi
542 }

\tikzmark@box This macro takes a name and a box. It pretends that there is a tight-fitting rect-
angular PGF node around that box with the given name, and saves the required
information so that that node can be used later on in a tikzpicture drawing.

32
It does not actually build a node, and it doesn’t create a TikZ drawing. Rather,
it measures the box and uses that information to define the various macros that
store the information about the node.
Apart from assigning a load of macros, it does also place a \pgfmark just before
the box. This is needed to be able to locate the node on the page.
The command is defined with an @ because it is more likely to be used in other
packages than by a user.
543 \def\tikzmark@box#1#2{%
544 \begingroup
545 \pgfmark{#1}%
546 \let\pgfnodeparttextbox=#2%
547 \edef\pgfpictureid{pgfid\the\pgf@picture@serial@count}%
548 \def\tikz@fig@name{#1}%
549 \pgfpointorigin
550 \advance\pgf@x by .5\wd\pgfnodeparttextbox
551 \advance\pgf@y by .5\ht\pgfnodeparttextbox
552 \advance\pgf@y by -.5\dp\pgfnodeparttextbox
553 \pgftransformshift{}%
554 \setbox\@tempboxa=\hbox\bgroup
555 {%
556 \tikzset{
557 inner sep=0pt,
558 minimum size=0pt,
559 outer sep=0pt,
560 anchor=base
561 }%
562 \let\pgf@sh@savedmacros=\pgfutil@empty% MW
563 \let\pgf@sh@savedpoints=\pgfutil@empty
564 \def\pgf@sm@shape@name{rectangle}% CJ % TT added prefix!
565 \pgf@sh@s@rectangle
566 \pgf@sh@savedpoints
567 \pgf@sh@savedmacros% MW
568 \pgftransformshift{%
569 \pgf@sh@reanchor{rectangle}{center}%
570 \pgf@x=-\pgf@x
571 \pgf@y=-\pgf@y
572 }%
573 \expandafter\pgfsavepgf@process
574 \csname pgf@sh@sa@\tikz@fig@name\endcsname{%
575 \pgf@sh@reanchor{rectangle}{center}% FIXME : this is double work!
576 }%
577 % Save the saved points and the transformation matrix
578 \edef\pgf@node@name{\tikz@fig@name}%
579 \ifx\pgf@node@name\pgfutil@empty
580 \else
581 \expandafter\xdef
582 \csname pgf@sh@ns@\pgf@node@name\endcsname{rectangle}%
583 \edef\pgf@sh@@temp{%
584 \noexpand\gdef\expandafter
585 \noexpand\csname pgf@sh@np@\pgf@node@name\endcsname}%
586 \expandafter\pgf@sh@@temp\expandafter{%
587 \pgf@sh@savedpoints}%
588 \edef\pgf@sh@@temp{%

33
589 \noexpand\gdef\expandafter
590 \noexpand\csname pgf@sh@ma@\pgf@node@name\endcsname}% MW
591 \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedmacros}% MW
592 \pgfgettransform\pgf@temp
593 \expandafter\xdef
594 \csname pgf@sh@nt@\pgf@node@name\endcsname{\pgf@temp}%
595 \expandafter\xdef
596 \csname pgf@sh@pi@\pgf@node@name\endcsname{\pgfpictureid}%
597 \fi
598 }%
599 \egroup
600 \endgroup
601 \box#2%
602 }

\usetikzmarklibrary
603 \def\usetikzmarklibrary{%
604 \pgfutil@ifnextchar[{\use@tikzmarklibrary}{\use@@tikzmarklibrary}%
605 }%}
606 \def\use@tikzmarklibrary[#1]{\use@@tikzmarklibrary{#1}}
607 \def\use@@tikzmarklibrary#1{%
608 \edef\pgf@list{#1}%
609 \pgfutil@for\pgf@temp:=\pgf@list\do{%
610 \expandafter\pgfkeys@spdef
611 \expandafter\pgf@temp\expandafter{\pgf@temp}%
612 \ifx\pgf@temp\pgfutil@empty
613 \else
614 \expandafter\ifx
615 \csname tikzmark@library@\pgf@temp @loaded\endcsname\relax%
616 \expandafter\global\expandafter\let%
617 \csname tikzmark@library@\pgf@temp @loaded\endcsname
618 =\pgfutil@empty%
619 \expandafter\edef
620 \csname tikzmark@library@#1@atcode\endcsname{\the\catcode‘\@}
621 \expandafter\edef
622 \csname tikzmark@library@#1@barcode\endcsname{\the\catcode‘\|}
623 \catcode‘\@=11
624 \catcode‘\|=12
625 \pgfutil@InputIfFileExists{tikzmarklibrary\[email protected]}{}{
626 \PackageError{tikzmark}{
627 I did not find the tikzmark extras library ’\pgf@temp’.}{}
628 }%
629 \catcode‘\@=\csname tikzmark@library@#1@atcode\endcsname
630 \catcode‘\|=\csname tikzmark@library@#1@barcode\endcsname
631 \fi%
632 \fi
633 }%
634 }

The save node code is written in LATEX3.


635 \ExplSyntaxOn
636 \cs_new_protected:Nn \tikzmark_tl_put_right_braced:Nn
637 {
638 \tl_put_right:Nn #1 { { #2 } }

34
639 }
640 \cs_generate_variant:Nn \tikzmark_tl_put_right_braced:Nn { NV, cV, cv, Nx, cx }
This is how we handle return values from functions
641 \tl_new:N \g__sn_output_tl
We save our information in a “property list”, which is L3’s version of an associative
array or dictionary. They keys will give the ability to store several groups of nodes
and restore them at will.
642 \prop_new:N \g__sn_prop
We’ll need a couple of spare token lists
643 \tl_new:N \l__sn_tmpa_tl
644 \tl_new:N \l__sn_tmpb_tl
Another useful token list
645 \tl_new:N \l__open_bracket_tl
646 \tl_set:Nn \l__open_bracket_tl {[} %]

This token list is used for our current node group name
647 \tl_new:N \l__sn_group_tl
We store up the nodes in a list and save them at the end of a given tikzpicture.
Has to be global as we’re often in a group.
648 \clist_new:N \g__sn_nodes_clist
This boolean is for whether we save to a file or not.
649 \bool_new:N \l__sn_file_bool
This boolean is for whether we are in the preamble or not.
650 \bool_new:N \g__sn_preamble_bool
651 \bool_gset_true:N \g__sn_preamble_bool
Key interface for setting some of the options
652 \keys_define:nn {tikzmark / save nodes}
653 {
654 file .bool_set:N = \l__sn_file_bool,
655 group .tl_set:N = \l__sn_group_tl,
656 }

657 \msg_new:nnn {tikzmark} {no file} {File~ "#1"~ doesn’t~ exist.}


658 \msg_new:nnn {tikzmark} {loading nodes} {Loading~ nodes~ from~ "#1".}
Dimensions and token lists for shifting
659 \dim_new:N \l__sn_x_dim
660 \dim_new:N \l__sn_y_dim
661 \dim_new:N \l__sn_xa_dim
662 \dim_new:N \l__sn_ya_dim
663 \tl_new:N \l__sn_centre_tl
664
665 \tl_new:N \l__sn_transformation_tl
666 \tl_set:Nn \l__sn_transformation_tl {{1}{0}{0}{1}{0pt}{0pt}}
Set up a stream for saving the nodes data to a file
667 \iow_new:N \g__sn_stream
668 \bool_new:N \g__sn_stream_bool
669 \tl_new:N \g__sn_filename_tl
670 \tl_gset:Nx \g__sn_filename_tl {\c_sys_jobname_str}

35
671
672 \cs_new_nopar:Npn \sn_open_stream:
673 {
674 \bool_if:NF \g__sn_stream_bool
675 {
676 \iow_open:Nn \g__sn_stream {\tl_use:N \g__sn_filename_tl .nodes}
677 \bool_gset_true:N \g__sn_stream_bool
678 }
679 }
680
681 \AtEndDocument
682 {
683 \ExplSyntaxOn
684 \bool_if:NT \g__sn_stream_bool
685 {
686 \iow_close:N \g__sn_stream
687 }
688 \ExplSyntaxOff
689 }

LaTeX3 wrappers around some PGF functions (to avoid @-catcode issues)
690 \makeatletter
691 \cs_set_eq:NN \tikz_set_node_name:n \tikz@pp@name
692 \cs_set_eq:NN \tikz_fig_must_be_named: \tikz@fig@mustbenamed
693
694 \cs_new_nopar:Npn \tikz_scan_point:n #1
695 {
696 \tikz@scan@one@point\pgfutil@firstofone#1\relax
697 }
698
699 \cs_new_nopar:Npn \tikz_scan_point:NNn #1#2#3
700 {
701 \tikz@scan@one@point\pgfutil@firstofone#3\relax
702 \dim_set_eq:NN #1 \pgf@x
703 \dim_set_eq:NN #2 \pgf@y
704 }
705
706 \makeatother
707 \cs_generate_variant:Nn \tikz_scan_point:n {V}
708 \cs_generate_variant:Nn \tikz_scan_point:NNn {NNV}

\process_node:Nn This is the command that actually does the work. It constructs a token list
which contains the code that will restore the node data when invoked. The two
arguments are the token list to store this in and the node name to be saved.
709 \cs_new_nopar:Npn \__sn_process_node:n #1
710 {
711 \group_begin:
Clear our token list
712 \tl_clear:N \l__sn_tmpa_tl
Set the centre of the picture
713 \tikz_scan_point:NNn \l__sn_x_dim \l__sn_y_dim
714 {(current~ bounding~ box.center)}
715 \dim_set:Nn \l__sn_x_dim {-\l__sn_x_dim}

36
716 \dim_set:Nn \l__sn_y_dim {-\l__sn_y_dim}
717 \tl_set:Nx \l__sn_centre_tl {
718 {1}{0}{0}{1}{\dim_use:N \l__sn_x_dim}{\dim_use:N \l__sn_y_dim}
719 }
Test to see if the node has been defined
720 \tl_if_exist:cT {pgf@sh@ns@#1}
721 {
The node information is stored in a series of macros of the form \pgf@sh@XX@nodename
where XX is one of the following.
722 \clist_map_inline:nn {ns,np,ma,pi}
723 {
Our token list will look like:
\tl_set:cn {pgf@sh@XX@nodename} <current contents of that macro>
This will restore \pgf@sh@XX@nodename to its current value when this list is
invoked.
This part puts the \tl_set:cn {pgf@sh@XX@nodename} in place
724 \tl_put_right:Nn \l__sn_tmpa_tl
725 {
726 \tl_gset:cn {pgf@sh@##1@ \tikz_set_node_name:n{#1} }
727 }
Now we put the current contents in place. We’re doing this in an expansive
context to get at the contents. The \exp_not:v part takes the current value of
\pgf@sh@XX@nodename and puts it in place, preventing further expansion.
728 \tl_if_exist:cTF {pgf@sh@##1@#1}
729 {
730 \tl_put_right:Nx \l__sn_tmpa_tl {
731 {\exp_not:v {pgf@sh@##1@ \tikz_set_node_name:n {#1}}}
732 }
733 }
734 {
735 \tl_put_right:Nx \l__sn_tmpa_tl {{}}
736 }
737 }
738 \tl_put_right:Nn \l__sn_tmpa_tl
739 {
740 \tl_gset:cn {pgf@sh@nt@ \tikz_set_node_name:n{#1} }
741 }
742 \compose_transformations:NVv
743 \l__sn_tmpb_tl \l__sn_centre_tl {pgf@sh@nt@#1}
744 \tl_put_right:Nx \l__sn_tmpa_tl {{\exp_not:V \l__sn_tmpb_tl}}
745 \tl_put_right:Nn \l__sn_tmpa_tl {
746 \transform_node:Nn \l__sn_transformation_tl {
747 \tikz_set_node_name:n{#1}
748 }
749 }
750 }
Once we’ve assembled our token list, we store it in the given token list
751 \tl_gset_eq:NN \g__sn_output_tl \l__sn_tmpa_tl
752 \group_end:
753 }

37
754 \cs_new_protected_nopar:Npn \process_node:Nn #1#2
755 {
756 \__sn_process_node:n {#2}
757 \tl_set_eq:NN #1 \g__sn_output_tl
758 \tl_gclear:N \g__sn_output_tl
759 }
760 \cs_new_protected_nopar:Npn \process_gnode:Nn #1#2
761 {
762 \__sn_process_node:n {#2}
763 \tl_gset_eq:NN #1 \g__sn_output_tl
764 \tl_gclear:N \g__sn_output_tl
765 }

\save_nodes_to_list:nn Save the nodes to a list, given a key


766 \cs_new_nopar:Npn \save_nodes_to_list:nn #1#2
767 {
768 \tl_clear:N \l__sn_tmpa_tl
769 \clist_map_inline:nn {#2}
770 {
771 \process_node:Nn \l__sn_tmpb_tl {##1}
772 \tl_put_right:NV \l__sn_tmpa_tl \l__sn_tmpb_tl
773 }
774 \prop_gput:NnV \g__sn_prop {#1} \l__sn_tmpa_tl
775 }

\save_nodes_to_file:n Save the nodes to a file


776 \cs_generate_variant:Nn \iow_now:Nn {NV}
777 \cs_new_nopar:Npn \save_nodes_to_file:n #1
778 {
779 \sn_open_stream:
780 \clist_map_inline:nn {#1}
781 {
782 \process_node:Nn \l__sn_tmpa_tl {##1}
Save the token list to the nodes file so that on reading it back in, we restore the
node definitions
783 \iow_now:Nx \g__sn_stream
784 {
785 \iow_newline:
786 \exp_not:V \l__sn_tmpa_tl
787 }
788 }
789 }

790 \cs_generate_variant:Nn \save_nodes_to_list:nn {VV, Vn}


791 \cs_generate_variant:Nn \save_nodes_to_file:n {V}

\restore_nodes_from_list:n
792 \cs_new_nopar:Npn \restore_nodes_from_list:n #1
793 {
Restoring nodes is simple: look in the property list for the key and if it exists,
invoke the macro stored there.
794 \prop_get:NnNT \g__sn_prop {#1} \l__sn_tmpa_tl
795 {

38
796 \tl_use:N \l__sn_tmpa_tl
797 }
798 }

\restore_nodes_from_file:n
799 \cs_new_nopar:Npn \restore_nodes_from_file:n #1
800 {
801 \file_if_exist:nTF {#1.nodes}
802 {
803 \msg_log:nnn {tikzmark} {loading nodes} {#1}
804 \ExplSyntaxOn
805 \file_input:n {#1.nodes}
806 \ExplSyntaxOff
807 }
808 {
809 \msg_warning:nnn {tikzmark} {no file} {#1}
810 }
811 }
812 \cs_generate_variant:Nn \restore_nodes_from_file:n {x}
813 \AtBeginDocument{\bool_gset_false:N \g__sn_preamble_bool}

\compose_transformations:Nnn Compose PGF transformations #2 * #3, storing the result in #1


I think the PGF Manual might be incorrect. It implies that the matrix is
stored row-major, but experimentation implies column-major.
That is, {a}{b}{c}{d}{s}{t} is:
 
a c
b d
814 \cs_new_nopar:Npn \compose_transformations:Nnn #1#2#3
815 {
816 \tl_gset:Nx #1
817 {
818 {\fp_eval:n {
819 \tl_item:nn {#2} {1}
820 * \tl_item:nn {#3} {1}
821 +
822 \tl_item:nn {#2} {3}
823 * \tl_item:nn {#3} {2}
824 }
825 }
826 {\fp_eval:n {
827 \tl_item:nn {#2} {2}
828 * \tl_item:nn {#3} {1}
829 +
830 \tl_item:nn {#2} {4}
831 * \tl_item:nn {#3} {2}
832 }
833 }
834 {\fp_eval:n {
835 \tl_item:nn {#2} {1}
836 * \tl_item:nn {#3} {3}
837 +
838 \tl_item:nn {#2} {3}

39
839 * \tl_item:nn {#3} {4}
840 }
841 }
842 {\fp_eval:n {
843 \tl_item:nn {#2} {2}
844 * \tl_item:nn {#3} {3}
845 +
846 \tl_item:nn {#2} {4}
847 * \tl_item:nn {#3} {4}
848 }
849 }
850 {\fp_to_dim:n {
851 \tl_item:nn {#2} {1}
852 * \tl_item:nn {#3} {5}
853 +
854 \tl_item:nn {#2} {3}
855 * \tl_item:nn {#3} {6}
856 +
857 \tl_item:nn {#2} {5}
858 }
859 }
860 {\fp_to_dim:n {
861 \tl_item:nn {#2} {2}
862 * \tl_item:nn {#3} {5}
863 +
864 \tl_item:nn {#2} {4}
865 * \tl_item:nn {#3} {6}
866 +
867 \tl_item:nn {#2} {6}
868 }
869 }
870 }
871 }

872 \cs_generate_variant:Nn \compose_transformations:Nnn


873 {cVv,NVv,NVn,NvV,NnV}

\transform_node:Nn
874 \cs_new_nopar:Npn \transform_node:Nn #1#2
875 {
876 \compose_transformations:cVv {pgf@sh@nt@#2} #1 {pgf@sh@nt@#2}
877 }

\set_transform_from_node:n
878 \cs_new_nopar:Npn \set_transform_from_node:n #1
879 {
880 \tl_set_eq:Nc \l__sn_transformation_tl {pgf@sh@nt@#1}
881 \tikz_scan_point:NNn \l__sn_x_dim \l__sn_y_dim {(#1.center)}
882
883 \dim_set:Nn \l__sn_x_dim {
884 \l__sn_x_dim - \tl_item:cn {pgf@sh@nt@#1}{5}
885 }
886 \dim_set:Nn \l__sn_y_dim {
887 \l__sn_y_dim - \tl_item:cn {pgf@sh@nt@#1}{6}

40
888 }
889
890 \compose_transformations:NnV \l__sn_transformation_tl {
891 {1}{0}{0}{1}{\dim_use:N \l__sn_x_dim}{\dim_use:N \l__sn_y_dim}
892 } \l__sn_transformation_tl
893 }

894 \cs_generate_variant:Nn \set_transform_from_node:n {v}


Set the TikZ keys for access to the above commands.
895 \tikzset{
896 set~ saved~ nodes~ file~ name/.code={
897 \tl_gset:Nx \g__sn_filename_tl {#1}
898 },
899 transform~ saved~ nodes/.code={
900 \set_transform_from_node:v {tikz@last@fig@name}
901 },
902 set~ node~ group/.code={
903 \tl_set:Nn \l__sn_group_tl {#1}
904 \pgfkeysalso{
905 execute~ at~ end~ scope={
906 \maybe_save_nodes:
907 }
908 }
909 },
Are we saving to a file?
910 save~ nodes~ to~ file/.code={
911 \tl_if_eq:nnTF {#1}{false}
912 {
913 \bool_set_false:N \l__sn_file_bool
914 }
915 {
916 \bool_set_true:N \l__sn_file_bool
917 }
918 \pgfkeysalso{
919 execute~ at~ end~ scope={
920 \maybe_save_nodes:
921 }
922 }
923 },
Append current node or named node to the list of nodes to be saved
924 save~ node/.code={
925 \tl_if_eq:nnTF {#1} {\pgfkeysnovalue}
926 {
927 \tikz_fig_must_be_named:
928 \pgfkeysalso{
929 append~ after~ command={
930 \pgfextra{
931 \clist_gput_right:Nv \g__sn_nodes_clist {tikz@last@fig@name}
932 }
933 }
934 }
935 }

41
936 {
937 \clist_gput_right:Nn \g__sn_nodes_clist {#1}
938 }
939 },
Restore nodes from file
940 restore~ nodes~ from~ file/.code={
941 \bool_if:NTF \g__sn_preamble_bool
942 {
943 \restore_nodes_from_file:x {#1}
944 }
945 {
946 \tikz_fig_must_be_named:
947 \pgfkeysalso{append~ after~ command={
948 \pgfextra{
949 \scope
950 \split_argument:NNn \tikzset \restore_nodes_from_file:x {#1}
951 \endscope
952 }
953 }
954 }
955 }
956 },
957 restore~ nodes~ from~ file/.default = \g__sn_filename_tl,
Restore nodes from list
958 restore~ nodes~ from~ list/.code={
959 \tikz_fig_must_be_named:
960 \pgfkeysalso{append~ after~ command={
961 \pgfextra{
962 \scope
963 \split_argument:NNn \tikzset \restore_nodes_from_list:n {#1}
964 \endscope
965 }
966 }
967 }
968 }
969 }
970 \cs_generate_variant:Nn \clist_gput_right:Nn {Nv}

\split_argument:NNn
971 \cs_new_nopar:Npn \split_argument:NNn #1#2#3
972 {
973 \tl_set:Nx \l__sn_tmpa_tl {\tl_head:n {#3}}
974 \tl_if_eq:NNTF \l__sn_tmpa_tl \l__open_bracket_tl
975 {
976 \split_argument_aux:NNp #1#2#3
977 }
978 {
979 #2 {#3}
980 }
981 }

\split_argument_aux:NNp
982 \cs_new_nopar:Npn \split_argument_aux:NNp #1#2[#3]#4

42
983 {
984 #1 {#3}
985 #2 {#4}
986 }

\maybe_save_nodes:
987 \cs_new_nopar:Npn \maybe_save_nodes:
988 {
989 \clist_if_empty:NF \g__sn_nodes_clist
990 {
991 \bool_if:NTF \l__sn_file_bool
992 {
993 \save_nodes_to_file:V \g__sn_nodes_clist
994 }
995 {
996 \tl_if_empty:NF \l__sn_group_tl
997 {
998 \save_nodes_to_list:VV \l__sn_group_tl \g__sn_nodes_clist
999 }
1000 }
1001 \clist_gclear:N \g__sn_nodes_clist
1002 }
1003 }

\SaveNode Command for saving a node outside a TikZ picture.


1004 \DeclareDocumentCommand \SaveNode { o m }
1005 {
1006 \group_begin:
1007 \IfNoValueF {#1}
1008 {
1009 \keys_set:nn {tikzmark / save nodes}
1010 {
1011 file=false,
1012 group=#1
1013 }
1014 }
1015 \bool_if:NTF \l__sn_file_bool
1016 {
1017 \save_nodes_to_file:n {#2}
1018 }
1019 {
1020 \tl_if_empty:NF \l__sn_group_tl
1021 {
1022 \save_nodes_to_list:Vn \l__sn_group_tl {#2}
1023 }
1024 }
1025 \group_end:
1026 }

1027 \ExplSyntaxOff

8.2 Listings
From http://tex.stackexchange.com/q/79762/86

43
1028 \@ifpackageloaded{listings}{%

\iflst@linemark A conditional to help with placing the mark at the first non-whitespace character.
Should be set to true so that we notice the first line of the code.
1029 \newif\iflst@linemark
1030 \lst@linemarktrue

EveryLine This hook places the mark at the start of the line.
1031 \lst@AddToHook{EveryLine}{%
1032 \begingroup
1033 \advance\c@lstnumber by 1\relax
1034 \pgfmark{line-\lst@name-\the\c@lstnumber-start}%
1035 \endgroup
1036 }

EOL This hook places the mark at the end of the line and resets the conditional for
placing the first mark.
1037 \lst@AddToHook{EOL}{\pgfmark{line-\lst@name-\the\c@lstnumber-end}%
1038 \global\lst@linemarktrue
1039 }

OutputBox Experimenting shows that this is the right place to set the mark at the first non-
whitespace character. But we only want to do this once per line.
1040 \lst@AddToHook{OutputBox}{%
1041 \iflst@linemark
1042 \pgfmark{line-\lst@name-\the\c@lstnumber-first}%
1043 \global\lst@linemarkfalse
1044 \fi
1045 }

\tikzmk@lst@fnum An auxiliary macro to figure out if the firstnumber key was set. If so, it has the
form <number>\relax. If not, it expands to a single token.
1046 \def\tkzmk@lst@fnum#1\relax#2\@STOP{%
1047 \def\@test{#2}%
1048 \ifx\@test\@empty
1049 \def\tkzmk@lst@start{0}%
1050 \else
1051 \@tempcnta=#1\relax
1052 \advance\@tempcnta by -1\relax
1053 \def\tkzmk@lst@start{\the\@tempcnta}%
1054 \fi
1055 }

Init Adds a mark at the start of the listings environment.


1056 \lst@AddToHook{Init}{%
1057 \expandafter\tkzmk@lst@fnum\lst@firstnumber\relax\@STOP
1058 \pgfmark{line-\lst@name-\tkzmk@lst@start-start}%
1059 }

1060 }{%
1061 \PackageError{tikzmark listings}%
1062 {The listings package has not been loaded.}{}
1063 }

44
8.3 AMS Math
This tikzmark library defines a routine that puts a pseudo-node (using \tikzmark@box)
around all the pieces used in constructing the various math environments that the
AMS Math package provides, such as gather and align. All of these (and their
labels) work by putting various pieces into a box and then typesetting that box
in the cells of an halign. By using \tikzmark@box, this can be infiltrated to put
nodes around each of those boxes as it is placed.
1064 \@ifpackageloaded{amsmath}{%

tikzmarkmath Defines an environment in which any AMS mathematical aligned environments


get nodes around each piece of their contents.
Start by saving the original \boxz@ command.
1065 \let\tikzmark@ams@boxz@=\boxz@
We’ll need a counter to keep track of the nodes.
1066 \newcounter{tikzmarkequation}
The nodes will be labelled <name>-<number>. By default the name is equation
but this can be customised.
1067 \def\tikzmark@ams@name{equation}
This is the substitute command. I don’t know if the \ifmeasuring@ actually
does anything, but it’s here just in case at the moment.
1068 \def\tikzmark@boxz@{%
1069 \ifmeasuring@
1070 \tikzmark@ams@boxz@
1071 \else
1072 \stepcounter{tikzmarkequation}%
1073 \tikzmark@box{\tikzmark@ams@name-\thetikzmarkequation}{\z@}%
1074 \fi
1075 }
This is the environment that sets the node name and swaps out the box code.
At the end of the environment we swap back the code so that the commands can
be used as standalone \tikzmarkmath and \endtikzmarkmath in occasions when
it isn’t appropriate to use an environment (for example, if it crosses sections, or
if it is wanted to turn on this feature for an entire document). At the end of the
environment, the number of nodes is written out to the terminal and log file to
make it easier to keep track.
1076 \newenvironment{tikzmarkmath}[1][equation]{%
1077 \def\tikzmark@ams@name{#1}%
1078 \setcounter{tikzmarkequation}{0}%
1079 \let\boxz@=\tikzmark@boxz@
1080 }{%
1081 \let\boxz@=\tikzmark@ams@boxz@
1082 \message{%
1083 Tikzmark math environment
1084 \tikzmark@ams@name\space had
1085 \the\value{tikzmarkequation} nodes in it
1086 }%
1087 }

45
1088 }{%
1089 \PackageError{tikzmark AMS}%
1090 {The amsmath package has not been loaded.}%
1091 {}
1092 }

8.4 Highlighting
An early use of \tikzmark was to add highlighting to text by drawing over or
under the text between two tikzmarks, for example the question How to "highlight"
text/formulas with tikz?.
I was never totally happy with the overall mechanism, so didn’t include it in
the main tikzmark package. Recently, I had occasion to revisit it and by using
the new LATEX3 hook facility I got something that I was sufficiently happy with
to add to the main package.
The key idea is to hook into the shipout/background routine to insert the
highlighting behind the text. This allows us to draw the highlighting before the
page is laid out and so is under the text.
LATEX3 makes life just that little bit easier.
1093 \ExplSyntaxOn
Since the code that draws the highlighting will probably be very separate from
the code that defines it, when storing the highlighting code then we want to expand
the tikzmark full name.
1094 \cs_new_protected_nopar:Npn \tikzmark_fix_name:Nn #1#2
1095 {
1096 \tl_set:Nx #1 {\tikzmark@pp@name{#2}}
1097 }

g,\EndHighlighting,\Highlight These are the user interfaces for highlighting a section. The first command inserts
the drawing code into the relevant hook and places a tikzmark at the current
location. The second command indicates when the highlighting should stop. The
third is a short cut for highlighting its argument.
These are commands rather than an environment to allow it to span, for ex-
ample, different parts of an aligned equation.
1098 \tl_new:N \g__tikzmark_highlighter_tl
1099 \tl_set:Nn \g__tikzmark_highlighter_tl {tikzmark~ highlighter~}
1100 \int_new:N \g__tikzmark_highlighter_int
1101 \tl_new:N \l__tikzmark_start_tl
1102 \tl_new:N \l__tikzmark_end_tl
1103 \tl_new:N \l__tikzmark_highlighter_name_tl
1104 \tl_new:N \l__tikzmark_tmpa_tl
1105 \tl_new:N \l__tikzmark_tmpb_tl
1106 \tl_new:N \l__tikzmark_tmpc_tl
1107
1108 \cs_new_protected_nopar:Npn \tikzmark_bake_highlighter:N #1
1109 {
1110 \tl_clear:N #1
1111 \clist_map_inline:nn {direction,layer}
1112 {
1113 \tl_put_right:Nx #1 {
1114 /tikz/highlighter/##1=\pgfkeysvalueof{/tikz/highlighter/##1},

46
1115 }
1116 }
1117 \clist_map_inline:nn {
1118 initial~ height,
1119 initial~ depth,
1120 initial~ offset,
1121 final~ height,
1122 final~ depth,
1123 final~ offset,
1124 left~ margin,
1125 right~ margin,
1126 top~ margin,
1127 bottom~ margin,
1128 }
1129 {
1130 \tl_put_right:Nx #1 {
1131 /tikz/highlighter/##1=\dim_eval:n {\pgfkeysvalueof{/tikz/highlighter/##1}},
1132 }
1133 }
1134 }
1135
1136 \cs_new_protected_nopar:Npn \tikzmark_start_highlighting:n #1
1137 {
1138 \int_gincr:N \g__tikzmark_highlighter_int
1139 \tl_set:Nx \l__tikzmark_highlighter_name_tl
1140 {
1141 \tl_use:N \g__tikzmark_highlighter_tl
1142 \int_use:N \g__tikzmark_highlighter_int
1143 }
1144 \tl_set:Nn \l__tikzmark_tmpb_tl
1145 {
1146 every~ highlighter/.try,
1147 }
1148 \tikzmark_bake_highlighter:N \l__tikzmark_tmpc_tl
1149 \tl_put_right:NV \l__tikzmark_tmpb_tl \l__tikzmark_tmpc_tl
1150 \tl_put_right:Nn \l__tikzmark_tmpb_tl {#1}
1151 \tikzmark_process_highlighting:VV
1152 \l__tikzmark_tmpb_tl
1153 \l__tikzmark_highlighter_name_tl
1154 \tikzmark{highlight-start-\tl_use:N \l__tikzmark_highlighter_name_tl}
1155 }
1156 \cs_new_protected_nopar:Npn \tikzmark_end_highlighting:
1157 {
1158 \tl_set:Nx \l__tikzmark_highlighter_name_tl
1159 {
1160 \tl_use:N \g__tikzmark_highlighter_tl
1161 \int_use:N \g__tikzmark_highlighter_int
1162 }
1163 \tikzmark{highlight-end-\tl_use:N \l__tikzmark_highlighter_name_tl}
1164 }
1165
1166 \NewDocumentCommand \StartHighlighting {O{}}
1167 {%
1168 \tikzmark_start_highlighting:n {#1}

47
1169 }
1170 \NewDocumentCommand \StopHighlighting {}
1171 {%
1172 \tikzmark_end_highlighting:
1173 }
1174 \NewDocumentCommand \Highlight {O{} m}
1175 {%
1176 \tikzmark_start_highlighting:n {#1}
1177 #2
1178 \tikzmark_end_highlighting:
1179 }

The following code inserts the drawing command into the shipout hook.
We need an ordinary colon, rather than a LATEX3 one
1180 \tl_const:Nx \c__tikzmark_colon_tl
1181 {
1182 \char_generate:nn {‘:} {12}
1183 }
1184
1185 \cs_generate_variant:Nn \hook_gput_next_code:nn {nV}
1186 \cs_new_protected_nopar:Npn \tikzmark_highlight_or_shunt:nnnn #1#2#3#4
1187 {
First, test to check if the tikzmarks are actually defined yet, if not then bail out.
1188 \bool_lazy_all:nT
1189 {
1190 {\tl_if_exist_p:c {save@pt@\tikzmark@pp@name{#2}}}
1191 {\tl_if_exist_p:c {save@pg@\tl_use:c{save@pt@\tikzmark@pp@name{#2}}}}
1192 {\tl_if_exist_p:c {save@pt@\tikzmark@pp@name{#3}}}
1193 {\tl_if_exist_p:c {save@pg@\tl_use:c{save@pt@\tikzmark@pp@name{#3}}}}
1194 }
1195 {
Okay, so all the tikzmarks are defined. Now see if we’re on the right page. Is our
start tikzmark in the future?
1196 \int_compare:nTF
1197 {
1198 \tl_use:c {save@pg@\tl_use:c{save@pt@\tikzmark@pp@name{#2}}}
1199 >
1200 \the\value{page}
1201 }
1202 {
It is, so we just punt our highlighting down the line
1203 \hook_gput_next_code:nn {#1} {
1204 \tikzmark_highlight_or_shunt:nnnn {#1}{#2}{#3}{#4}
1205 }
1206 }
1207 {
It isn’t, so we have some highlighting to do. We need to build our highlighting
code.
1208 \tl_set:Nn \l__tikzmark_tmpa_tl {#4}

48
Is our starting tikzmark on this page?
1209 \int_compare:nTF
1210 {
1211 \tl_use:c {save@pg@\tl_use:c{save@pt@\tikzmark@pp@name{#2}}}
1212 =
1213 \the\value{page}
1214 }
1215 {
It is, so we use the starting tikzmark as our first coordinate.
1216 \tl_put_right:Nx \l__tikzmark_tmpa_tl
1217 {
1218 {
1219 pic~ cs
1220 \tl_use:N \c__tikzmark_colon_tl
1221 #2
1222 }
1223 }
1224 }
1225 {
It isn’t, so we use the north west corner of the page
1226 \tl_put_right:Nn \l__tikzmark_tmpa_tl
1227 {
1228 {
1229 page.north~ west
1230 }
1231 }
1232 }
Is our ending tikzmark on this page?
1233 \int_compare:nTF
1234 {
1235 \tl_use:c {save@pg@\tl_use:c{save@pt@\tikzmark@pp@name{#3}}}
1236 =
1237 \the\value{page}
1238 }
1239 {
It is, so we use the ending tikzmark as our second coordinate.
1240 \tl_put_right:Nx \l__tikzmark_tmpa_tl
1241 {
1242 {
1243 pic~ cs
1244 \tl_use:N \c__tikzmark_colon_tl
1245 #3
1246 }
1247 }
1248 }
1249 {
It isn’t, so we use the south east corner of the page, and we have to shunt the code
to the next page.
1250 \tl_put_right:Nn \l__tikzmark_tmpa_tl
1251 {
1252 {

49
1253 page.south~ east
1254 }
1255 }
1256 \hook_gput_next_code:nn {#1} {
1257 \tikzmark_highlight_or_shunt:nnnn {#1}{#2}{#3}{#4}
1258 }
1259 }
We’ve built our highlighting code, now’s time to execute it.
1260 \tl_use:N \l__tikzmark_tmpa_tl
1261 }
1262 }
1263 }
1264 \cs_new_protected_nopar:Npn \tikzmark_process_highlighting:nn #1#2
1265 {
1266 \pgfkeys{/tikz/highlighter/configuration/.activate~ family}
1267 \pgfkeysfiltered{/tikz/.cd,highlighter/direction,highlighter/layer,#1}
1268
1269 \tikzmark_fix_name:Nn \l__tikzmark_start_tl {highlight-start-#2}
1270 \tikzmark_fix_name:Nn \l__tikzmark_end_tl {highlight-end-#2}
1271 \tl_set:Nx \l__tikzmark_tmpa_tl {\pgfkeysvalueof{/tikz/highlighter/direction}}
1272 \tl_clear:N \l__tikzmark_tmpb_tl
1273 \tl_clear:N \l__tikzmark_tmpc_tl
1274 \tl_if_eq:NnTF \l__tikzmark_tmpa_tl {vertical}
1275 {
1276 \tl_put_right:Nn \l__tikzmark_tmpb_tl
1277 {
1278 \vl@draw
1279 }
1280 }
1281 {
1282 \tl_if_eq:NnTF \l__tikzmark_tmpa_tl {box}
1283 {
1284 \tl_put_right:Nn \l__tikzmark_tmpb_tl
1285 {
1286 \box@draw
1287 }
1288 }
1289 {
1290 \tl_put_right:Nn \l__tikzmark_tmpb_tl
1291 {
1292 \hl@draw
1293 }
1294 }
1295 }
1296
1297 \tl_put_right:Nn \l__tikzmark_tmpb_tl
1298 {
1299 {tikzmark~ clear~ ixes,#1}
1300 }
1301
1302 \tl_set:Nx \l__tikzmark_tmpa_tl {\pgfkeysvalueof{/tikz/highlighter/layer}}
1303 \tl_set:Nn \l__tikzmark_tmpc_tl
1304 {

50
1305 \tikzmark_highlight_or_shunt:nnnn
1306 }
1307 \tl_if_eq:NnTF \l__tikzmark_tmpa_tl {foreground}
1308 {
1309 \tl_put_right:Nn \l__tikzmark_tmpc_tl {{shipout/foreground}}
1310 }
1311 {
1312 \tl_put_right:Nn \l__tikzmark_tmpc_tl {{shipout/background}}
1313 }
1314
1315 \tikzmark_tl_put_right_braced:NV \l__tikzmark_tmpc_tl \l__tikzmark_start_tl
1316 \tikzmark_tl_put_right_braced:NV \l__tikzmark_tmpc_tl \l__tikzmark_end_tl
1317 \tikzmark_tl_put_right_braced:NV \l__tikzmark_tmpc_tl \l__tikzmark_tmpb_tl
1318
1319 \tl_if_eq:NnTF \l__tikzmark_tmpa_tl {foreground}
1320 {
1321 \hook_gput_next_code:nV {shipout/foreground} \l__tikzmark_tmpc_tl
1322 }
1323 {
1324 \hook_gput_next_code:nV {shipout/background} \l__tikzmark_tmpc_tl
1325 }
1326 }
1327 \cs_generate_variant:Nn \tikzmark_process_highlighting:nn {nV,VV}
1328 \ExplSyntaxOff

The command that draws the horizontal highligher or fader. This fills a shape
determined by two coordinates assumed to be (in effect) on the baseline of the
start and end of the region to be highlighted.
1329 \def\hl@draw#1#2#3{%
1330 \pgfkeys{/tikz/highlighter/configuration/.activate family}
1331 \pgfkeysfiltered{/tikz/.cd,highlighter/direction,highlighter/layer,#1}
1332 \begin{tikzpicture}[
1333 remember picture,
1334 overlay,
1335 highlight picture action,
1336 #1,
1337 ]%
1338 %
1339 \page@node
1340 %
1341 \tikz@scan@one@point\pgfutil@firstofone(#2)\relax
1342 \pgf@ya=\pgf@y
1343 \tikz@scan@one@point\pgfutil@firstofone(#3)\relax
1344 \pgf@yb=\pgf@y
1345 %
1346 \ifdim\pgf@ya=\pgf@yb
1347 %
1348 \path (#2)
1349 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial offset},
1350 \pgfkeysvalueof{/tikz/highlighter/initial height})
1351 coordinate (start);
1352 %
1353 \path (#3)
1354 ++(\pgfkeysvalueof{/tikz/highlighter/final offset},

51
1355 -1*\pgfkeysvalueof{/tikz/highlighter/final depth})
1356 coordinate (end);
1357 %
1358 \path[
1359 highlight action,
1360 #1
1361 ] (start) rectangle (end);
1362 %
1363 \else
1364 %
1365 \path (page.east)
1366 ++(\pgfkeysvalueof{/tikz/highlighter/right margin},0pt)
1367 coordinate (east);
1368 %
1369 \path (page.west)
1370 ++(-1*\pgfkeysvalueof{/tikz/highlighter/left margin},0pt)
1371 coordinate (west);
1372 %
1373 \pgfmathsetlength\pgf@x{%
1374 \pgfkeysvalueof{/tikz/highlighter/initial height}%
1375 }%
1376 %
1377 \advance\pgf@yb by \pgf@x\relax
1378 %
1379 \pgfmathsetlength\pgf@x{%
1380 -1*\pgfkeysvalueof{/tikz/highlighter/final depth}%
1381 }%
1382 %
1383 \advance\pgf@ya by \pgf@x\relax
1384 %
1385 \ifdim\pgf@yb>\pgf@ya
1386 %
1387 \path (#2)
1388 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial offset},
1389 \pgfkeysvalueof{/tikz/highlighter/initial height})
1390 coordinate (start);
1391 %
1392 \path (#2)
1393 ++(0pt,-1*\pgfkeysvalueof{/tikz/highlighter/final depth})
1394 coordinate (end);
1395 %
1396 \path[
1397 highlight action,
1398 #1
1399 ] (start) rectangle (end -| east);
1400 %
1401 \path (#3)
1402 ++(0pt,\pgfkeysvalueof{/tikz/highlighter/initial height})
1403 coordinate (start);
1404 %
1405 \path (#3)
1406 ++(\pgfkeysvalueof{/tikz/highlighter/final offset},
1407 -1*\pgfkeysvalueof{/tikz/highlighter/final depth})
1408 coordinate (end);

52
1409 %
1410 \path[
1411 highlight action,
1412 #1
1413 ] (start -| west) rectangle (end);
1414 %
1415 \else
1416 %
1417 \path (#2)
1418 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial offset},
1419 \pgfkeysvalueof{/tikz/highlighter/initial height})
1420 coordinate (tl);
1421 %
1422 \path (#2)
1423 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial offset},
1424 -1*\pgfkeysvalueof{/tikz/highlighter/initial depth})
1425 coordinate (start);
1426 %
1427 \path (#3)
1428 ++(\pgfkeysvalueof{/tikz/highlighter/final offset},
1429 -1*\pgfkeysvalueof{/tikz/highlighter/final depth})
1430 coordinate (end);
1431 %
1432 \path (#3)
1433 ++(\pgfkeysvalueof{/tikz/highlighter/final offset},
1434 \pgfkeysvalueof{/tikz/highlighter/final height})
1435 coordinate (mr);
1436 %
1437 \path[
1438 highlight action,
1439 #1
1440 ] (start) -- (tl) -- (tl -| east) -- (mr -| east) -- (mr) --
1441 (end) -- (end -| west) -- (start -| west) -- cycle;
1442 %
1443 \fi
1444 \fi
1445 \end{tikzpicture}%
1446 }
This one draws a box.
1447 \def\box@draw#1#2#3{%
1448 \pgfkeys{/tikz/highlighter/configuration/.activate family}
1449 \pgfkeysfiltered{/tikz/.cd,highlighter/direction,highlighter/layer,#1}
1450 \begin{tikzpicture}[
1451 remember picture,
1452 overlay,
1453 highlight picture action,
1454 #1,
1455 ]%
1456 %
1457 \tikz@scan@one@point\pgfutil@firstofone(#2)\relax
1458 \pgf@xa=\pgf@x
1459 \tikz@scan@one@point\pgfutil@firstofone(#3)\relax
1460 \pgf@xb=\pgf@x
1461 %

53
1462 \def\tkmk@high@bscale{1}%
1463 \ifdim\pgf@xa>\pgf@xb
1464 \def\tkmk@high@bscale{-1}%
1465 \fi
1466 %
1467 \path (#2)
1468 ++({\tkmk@high@bscale*(-1)*\pgfkeysvalueof{/tikz/highlighter/initial offset}},
1469 \pgfkeysvalueof{/tikz/highlighter/initial height})
1470 coordinate (start);
1471 %
1472 \path (#3)
1473 ++(\tkmk@high@bscale*\pgfkeysvalueof{/tikz/highlighter/final offset},
1474 -1*\pgfkeysvalueof{/tikz/highlighter/final depth})
1475 coordinate (end);
1476 %
1477 \path[
1478 highlight action,
1479 #1
1480 ] (start) rectangle (end);
1481 \end{tikzpicture}%
1482 }
In this one the region is defined vertically.
1483 \def\vl@draw#1#2#3{%
1484 \pgfkeys{/tikz/highlighter/configuration/.activate family}
1485 \pgfkeysfiltered{/tikz/.cd,highlighter/direction,highlighter/layer,#1}
1486 \begin{tikzpicture}[
1487 remember picture,
1488 overlay,
1489 highlight picture action,
1490 #1,
1491 ]%
1492 %
1493 \tikz@scan@one@point\pgfutil@firstofone(#2)\relax
1494 \pgf@ya=\pgf@y
1495 \pgf@xa=\pgf@x
1496 \tikz@scan@one@point\pgfutil@firstofone(#3)\relax
1497 \pgf@yb=\pgf@y
1498 \pgf@xb=\pgf@x
1499 %
1500 \pgfmathsetlength\pgf@y{%
1501 \pgfkeysvalueof{/tikz/highlighter/initial offset}%
1502 }%
1503 \advance\pgf@yb by \pgf@y
1504 \pgfmathsetlength\pgf@y{%
1505 -1*\pgfkeysvalueof{/tikz/highlighter/final offset}%
1506 }%
1507 \advance\pgf@ya by \pgf@y
1508 %
1509 \ifdim\pgf@yb>\pgf@ya
1510 %
1511 \ifdim\pgf@xa>\pgf@xb
1512 %
1513 \path (#2)
1514 ++(\pgfkeysvalueof{/tikz/highlighter/initial height},

54
1515 \pgfkeysvalueof{/tikz/highlighter/initial offset})
1516 coordinate (start);
1517 %
1518 \path (#3)
1519 ++(-1*\pgfkeysvalueof{/tikz/highlighter/final depth},
1520 -1*\pgfkeysvalueof{/tikz/highlighter/final offset})
1521 coordinate (end);
1522 %
1523 \else
1524 %
1525 \path (#2)
1526 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial depth},
1527 \pgfkeysvalueof{/tikz/highlighter/initial offset})
1528 coordinate (start);
1529 %
1530 \path (#3)
1531 ++(\pgfkeysvalueof{/tikz/highlighter/final height},
1532 -1*\pgfkeysvalueof{/tikz/highlighter/final offset})
1533 coordinate (end);
1534 %
1535 \fi
1536 %
1537 \path[
1538 highlight action,
1539 #1
1540 ] (start) rectangle (end);
1541 %
1542 \else
1543 %
1544 \path (#2)
1545 ++(\pgfkeysvalueof{/tikz/highlighter/initial height},0)
1546 coordinate (tr);
1547 %
1548 \path (#2)
1549 ++(0,\pgfkeysvalueof{/tikz/highlighter/initial offset})
1550 coordinate (start);
1551 %
1552 \path (#2)
1553 ++(-1*\pgfkeysvalueof{/tikz/highlighter/initial depth},0)
1554 coordinate (tl);
1555 %
1556 \path (#3)
1557 ++(\pgfkeysvalueof{/tikz/highlighter/final height},0)
1558 coordinate (br);
1559 %
1560 \path (#3)
1561 ++(0,-1*\pgfkeysvalueof{/tikz/highlighter/final offset})
1562 coordinate (end);
1563 %
1564 \path (#3)
1565 ++(-1*\pgfkeysvalueof{/tikz/highlighter/final depth},0)
1566 coordinate (bl);
1567 %
1568 \tikz@scan@one@point\pgfutil@firstofone(#2)\relax

55
1569 \pgf@xa=\pgf@x
1570 \tikz@scan@one@point\pgfutil@firstofone(#3)\relax
1571 \pgf@xb=\pgf@x
1572 %
1573 \ifdim\pgf@xa<\pgf@xb
1574 %
1575 \path[
1576 highlight action,
1577 #1
1578 ] (tl) |- (start) -| (tr) -| (br) |- (end) -| (bl) -| cycle;
1579 %
1580 \else
1581 %
1582 \path[
1583 highlight action,
1584 #1
1585 ] (tl) |- (start) -| (tr) |- (br) |- (end) -| (bl) |- cycle;
1586 %
1587 \fi
1588 %
1589 \fi
1590 \end{tikzpicture}
1591 }
These set various options.
1592 \tikzset{%
1593 /tikz/highlighter/.is family,
1594 /tikz/highlighter/.unknown/.code={%
1595 \let\tk@searchname=\pgfkeyscurrentname%
1596 \pgfkeysalso{%
1597 /tikz/\tk@searchname=#1
1598 }
1599 },
1600 every highlight path/.style={
1601 fill=yellow!50,
1602 rounded corners,
1603 },
1604 every foreground highlight path/.style={
1605 fill opacity=.5,
1606 },
1607 highlight picture action/.style={
1608 every highlight picture/.try,
1609 every \pgfkeysvalueof{/tikz/highlighter/direction} highlight picture/.try,
1610 every \pgfkeysvalueof{/tikz/highlighter/layer} highlight picture/.try,
1611 },
1612 highlight action/.style={
1613 every highlight path/.try,
1614 every \pgfkeysvalueof{/tikz/highlighter/direction} highlight path/.try,
1615 every \pgfkeysvalueof{/tikz/highlighter/layer} highlight path/.try,
1616 highlight path/.try,
1617 \pgfkeysvalueof{/tikz/highlighter/direction} highlight path/.try,
1618 \pgfkeysvalueof{/tikz/highlighter/layer} highlight path/.try,
1619 },
1620 /tikz/highlighter/.cd,
1621 direction/.initial=horizontal,

56
1622 layer/.initial=background,
1623 direction/.default=horizontal,
1624 layer/.default=background,
1625 initial height/.initial=\baselineskip,
1626 initial depth/.initial=.5ex,
1627 initial offset/.initial=.5\baselineskip,
1628 final height/.initial=\baselineskip,
1629 final depth/.initial=.5ex,
1630 final offset/.initial=.5\baselineskip,
1631 left margin/.initial=.5\baselineskip,
1632 right margin/.initial=.5\baselineskip,
1633 top margin/.initial=.5\baselineskip,
1634 bottom margin/.initial=-.5\baselineskip,
1635 height/.style={
1636 initial height=#1,
1637 final height=#1
1638 },
1639 depth/.style={
1640 initial depth=#1,
1641 final depth=#1
1642 },
1643 offset/.style={
1644 initial offset=#1,
1645 final offset=#1
1646 },
1647 margin/.style={
1648 left margin=#1,
1649 right margin=#1,
1650 top margin=#1,
1651 bottom margin=#1,
1652 },
1653 /tikz/highlighter/configuration/.is family,
1654 /tikz/highlighter/direction/.belongs to family=/tikz/highlighter/configuration,
1655 /tikz/highlighter/layer/.belongs to family=/tikz/highlighter/configuration,
1656 }
1657 \def\page@node{
1658 \path (current page.north west)
1659 ++(\hoffset + 1in + \oddsidemargin + \leftskip,
1660 -\voffset - 1in - \topmargin - \headheight - \headsep)
1661 node[
1662 minimum width=\textwidth - \leftskip - \rightskip,
1663 minimum height=\textheight,
1664 anchor=north west,
1665 line width=0mm,
1666 inner sep=0pt,
1667 outer sep=0pt,
1668 ] (page) {};
1669 }

57

You might also like