Tikzmark
Tikzmark
Andrew Stacey
[email protected]
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{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
\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}
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.
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:
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.
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.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.
• \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.
5 Examples
The \tikzmark command has been used in numerous answers on TeX-SX.
9
\tikzset{tikzmark prefix=ex1-}
\[
\tikzmark{a} e^{i \pi/2} = i
\]
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}
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}
\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}};
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.
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 }
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}
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
final depth
right margin
left margin
Multiple lines
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:
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 }%
\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 }
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 }
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 }
\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 }
27
304 }
305 }{}
\pgfmark<>
306 \@ifclassloaded{beamer}{
307 \renewcommand<>{\pgfmark}[1]{\only#2{\beameroriginal{\pgfmark}{#1}}}
308 }{}
\iftikzmark
314 \newif\iftikzmark@
315 \newcommand\iftikzmark[3]{%
316 \@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
317 #3%
318 }{%
319 #2%
320 }%
321 }%
\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 }
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 }
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 }
\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}
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 }
\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 }
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 }
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 }
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}{%
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