I would like to be able to detect if a particular mark was made with
-
\tikzmark
(which requires the use ofpic cs:
) or if it was made with -
\tikzmarknode
(which requires thatpic cs:
is not used).
Below is a contrived example which draws between two points: one created with \tikzmark
and the other created with \tikzmarknode
. Currently the first case works as the \DrawPicture
invokes the first coordinate with pic cs:
and the second one with out the pic cs:
.
Question: How do I change the \DrawPicture
macro so that both \DrawPicture{MarkA}{MarkB}
and \DrawPicture{MarkB}{MarkA}
(with the two marks reversed) will work?
I has orginally thought that using \iftikzmark
would solve this problem, but seems that \iftikzmark
only works as I expected on the second run, not the first run (even though the drawing code is invoked after the \tikzmark
and \tikzmarknode
. Even then, \tikzmarknode
also creates a \tikzmark
, so not really appropriate here to detect between the two cases.
Code:
\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\newcommand*{\DrawPicture}[2]{%
\par#1: \iftikzmark{#1}{tikzmark}{tikzmarknode}%
\par#2: \iftikzmark{#2}{tikzmark}{tikzmarknode}%
%% -------------
\begin{tikzpicture}[overlay,remember picture]
\draw [ultra thick, red, -] (pic cs:#1) to[out=120, in=50, distance=1cm] (#2);
\end{tikzpicture}%
}%
\begin{document}
\[
\tikzmark{MarkA} a + \tikzmarknode{MarkB}{b}
\]
\DrawPicture{MarkA}{MarkB}% <-- This works.
%\DrawPicture{MarkB}{MarkA}% <-- Want this also to be able to work
\end{document}
Best Answer
There are quite a few edge cases here so the best solution will depend on what you want to happen in these situations. To understand the edge cases, it's worth looking at what a tikzmark and tikzmarknode are. (I'm sure the OP knows this, so this is partially for the wider audience.)
A tikzmark records the location of a point on the page. To do this, it must write something to the aux file which is read in on the next compilation. It must work this way because its position can only be known after shipout.
A node records its anchors relative to its origin in the current tikzpicture. If that picture has the
remember picture
key set, then that origin is remembered using essentially the same underlying mechanism as a tikzmark. In particular, although the node's relative position is available straightaway then to actually use its position on the page requires an additional compilation. However, the node information is only available after the node has been defined in the current compilation (the tikzmark package does provide a way around that, but I view that as orthogonal to this discussion).A tikzmarknode combines these two so that both the node's anchors are available in the usual way and the origin (of the coordinate system in which the node is defined) is available as a tikzmark.
So the only difference between a tikzmarknode and a regular node is in how the information is made available. It is also not very difficult to set up all the information available from a tikzmarknode using other commands.
So the edge cases are:
\tikzmarknode
command. What should the test do in this case?On the basis that the simplest is usually the best until it breaks, here's my first go at this. It uses the same underlying information as in Jasper's first answer: testing
save@pt@<name>
andpgf@sh@ns@<name>
. The main difference is that rather than nesting the tests I keep them separate. This way, I can test for four options:save@pt@<name>
true butpgf@sh@ns@<name>
false: tikzmarksave@pt@<name>
false butpgf@sh@ns@<name@
true: nodeIn the following code then I have it wrapped in a classification function, but it would be simple to make it a genuine conditional - this is really me testing the waters to see what you actually want.
On first run this outputs:
On subsequent runs, this changes to:
In terms of using the coordinates, this seems the correct behaviour as it tells you what can be used at each stage. So the fact that
B
is a tikzmarknode is irrelevant prior to its definition: you can only use that fact afterwards.Update: 7/12/2023
Here's how to use
tikzmark
'ssave node
facility to make it possible to classify a\tikzmarknode
correctly even before it is defined.This stabilises to:
Update: 2023-12-10 One of the issues with combining
save node
with a\tikzmarknode
is that my code to save a node requires two steps: one which adds a node name to a list and another that processes that list and stores the node details in some location. When using this in a tikzpicture, the first step is usually invoked on the node itself and then the second happens at the end of the picture. This needs (at least) two keys: one on the tikzpicture that installs the end-of-picture code, and one on each node to be saved.A
\tikzmarknode
only provides immediate access to the options on its node, to get at the surrounding tikzpicture requires using theevery tikzmarknode picture
style, such as:but that hooks into every
\tikzmarknode
. While it's safe to do so (the saving node code only executes if there are nodes to save), I'm not overly happy about needing to do that if only wanting to save one or two nodes.But
\tikzmarknode
s are quite simple compared to general tikzpictures so we can hook in after the node has been defined rather than waiting until the picture finishes. So here's a key that seems to work, and if it genuinely does then I'll add it to thetikzmark
library.