4

Apologies for flooding the site with tikzmark problems ... :)

I know that with \iftikzmark I can test if a given tikzmark exists in general. Is there a way to test if a particular tikzmark exists on the same page?

Use case: I'm trying to design macros that I can insert anywhere in a text that would draw a line between them –- a \linestart and a \linefinish command. However, when the \linefinish command happens to fall on a subsequent page, the line gets drawn to where the \linestart command was on the previous page. I would rather have it instead "do something else", here, just for purpose of illustration, draw me a black square – or, ideally "point across" the page in the direction to where the other mark is sitting.

In the code below, I've tried to construct what I'm envisioning using \iftikzmark but that does not work.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\newcounter{tikzmkstart}\setcounter{tikzmkstart}{0} % 
\newcounter{tikzmkfinish}\setcounter{tikzmkfinish}{0} % 

\newcommand{\linestart}{%
\stepcounter{tikzmkfinish}\iftikzmark{b\thetikzmkfinish}{% tikzmark exists on same page
\stepcounter{tikzmkstart}\tikzmarknode{a\thetikzmkstart}{\vphantom{x}}\addtocounter{tikzmkfinish}{-1}}
{% tikzmark doesn't exist on page
\begin{tikzpicture} \draw [line width=4] (0,0) -- (.1,0); \end{tikzpicture}\addtocounter{tikzmkfinish}{-1}}}% black square if linefinish on next page

\newcommand{\linefinish}{%
\iftikzmark{a\thetikzmkstart}{% tikzmark exists on same page
\stepcounter{tikzmkfinish}\tikzmarknode{b\thetikzmkfinish}{\vphantom{x}}\begin{tikzpicture}[remember picture]  \draw[overlay] (a\thetikzmkstart.west) -- (b\thetikzmkfinish.west); \end{tikzpicture}}
{% tikzmark doesn't exist on page
\begin{tikzpicture} \draw [line width=4] (0,0) -- (.1,0); \end{tikzpicture}}}

\begin{document} 
Text \linestart text text 

Text text text 
%\newpage

Text text \linefinish text
\end{document}

Any ideas of how else I might accomplish something like this would be very welcome!


Update: Based on @marmot's suggestion to look at this answer, I've now come up with the following. However, I'm stuck with how to make the lines "point across" the page breaks ...

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

\newcounter{tmp}
\newcommand\tikzmark[1]{%
  \tikz[overlay,remember picture] \node (#1) {};}

\newcommand\linestart{%
  \stepcounter{tmp}%
  \tikzmark{a}\label{a\thetmp}%
  \ifnum\getpagerefnumber{a\thetmp}=\getpagerefnumber{b\thetmp} \else
  \begin{tikzpicture}[overlay, remember picture]
    \draw [thick]     
      (a.west) -- (b.west); 
  \end{tikzpicture}%
  \fi%
}


\newcommand\linefinish{%
\tikzmark{b}\label{b\thetmp}
  \ifnum\getpagerefnumber{a\thetmp}=\getpagerefnumber{b\thetmp}
  \begin{tikzpicture}[overlay, remember picture]
    \draw [thick]
      (a.west) -- (b.west); 
  \end{tikzpicture}%
  \else
  \begin{tikzpicture}[overlay, remember picture]
    \draw [thick]
      (a.west) -- (b.west); 
  \end{tikzpicture}%
  \fi
}

\newcommand\Squ[1]{\linestart#1\linefinish}

\begin{document}

Text \linestart text text

Text text text

Text text \linefinish text

Text \linestart text text

Text text text
\newpage

Text text \linefinish text

\end{document}
jan
  • 2,236
  • The way you write the questions may indicate that you are about to construct a tikzmar version of something like this answer. The basic trick is that you build in the page number. –  Apr 06 '19 at 16:51
  • @marmot Oh, you mean incorporating the pagenumber into the label for the node. Ha, that's clever. – jan Apr 06 '19 at 16:53
  • Yes, basically. If you also want the line to also run over page breaks, you may need refcount, like in Gonzalo's answer. –  Apr 06 '19 at 16:56
  • 1
    tikzmark already saves the page number on which it is defined (see https://tex.stackexchange.com/q/79121/86 for a use of this, and look at next page in the documentation). There isn't a current direct interface to that information; it is stored as \save@pg@<picture id of the tikzmark> so you could do a test on that. I'm not going to attempt to get the expansions right in a comment, but something like \ifnum\csname save@pg@\pgfpictureid\endcsname=\csname save@pg@\csname save@pt@\tmk@label\endcsname\endcsname – Andrew Stacey Apr 06 '19 at 17:10
  • @LoopSpace Hmm, that looks fairly complex. Would you be able to explain where I incorporate that? – jan Apr 06 '19 at 17:14
  • @marmot Yes, well, initially I thought it would be way too complex to get the line go over pagebreaks, but that would be an ideal solution ... – jan Apr 06 '19 at 17:15
  • But Gonzalo's answer accomplishes that. I believe all you need to do is to use the \tikzmark or \tikzmarknode command from @LoopSpace's stellar library and otherwise Gonzalo's way of running the line to the bottom of the page (or whatever you have in mind). –  Apr 06 '19 at 17:18
  • @marmot Let me try, I'll post back if I run into trouble ... – jan Apr 06 '19 at 17:20
  • Gonzalo's answer is quite old and a few of those bits are now in the official tikzmark code. I think that https://tex.stackexchange.com/q/79121/86 might be quite close to what you're after (note that this now works with the official tikzmark code). – Andrew Stacey Apr 06 '19 at 17:44
  • @marmot I've now added above code modified from Gonzalo's answer, but couldn't figure out how to make the lines point into the right direction ... would you be able to "point me into the right direction" :) how to get that right ... – jan Apr 06 '19 at 18:03

1 Answers1

6

I can see the point of having a \iftikzmarkonpage conditional, so I've added it to the tikzmark package (download tikzmark.dtx and run tex tikzmark.dtx to get the latest version). This introduces a new conditional, \iftikzmarkoncurrentpage{<tikzmark name>}. That copes with the issue about the lines being drawn on both pages when needed.

\documentclass{article}
\usepackage[a6paper]{geometry}
%\url{https://tex.stackexchange.com/q/483547/86}
\usepackage{tikz}
\usepackage{tikzpagenodes}
\usetikzlibrary{tikzmark}
\newcounter{tikzmarklines}\setcounter{tikzmarklines}{0} % 

\tikzset{
  tikzmark prefix=prefix-,
  tikzmark suffix=-suffix
}

\newcommand{\linestart}{%
  \stepcounter{tikzmarklines}%
  \tikzmark{a\thetikzmarklines}%
  \iftikzmarkoncurrentpage{b\thetikzmarklines}%
  \else
  \begin{tikzpicture}[remember picture,overlay,next page=below]%
  \clip (current page text area.south west) rectangle (current page text area.north east);
  \draw[line width=4] (pic cs:a\thetikzmarklines) -- (pic cs:b\thetikzmarklines);
  \end{tikzpicture}%
  \fi
}

\newcommand{\linefinish}{%
  \tikzmark{b\thetikzmarklines}%
  \begin{tikzpicture}[remember picture,overlay,next page=below]%
  \clip (current page text area.south west) rectangle (current page text area.north east);
  \draw[line width=1] (pic cs:a\thetikzmarklines) -- (pic cs:b\thetikzmarklines);
  \end{tikzpicture}%
  }

\begin{document} 
Text \linestart text text 

Text text text 

Text text \linefinish text

\newpage

Text text text 

Text \linestart text text 

Text text text 
\newpage

Text text text

Text text \linefinish text
\end{document}

lines between pages

Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
  • That looks like it does what I'm after :) thank you ... and if you incorporate a conditional into the package, even better :) Although ... didn't Gonzalo's answer solve that? Why would his solution be bad? – jan Apr 06 '19 at 18:28
  • Please feel free to revert my edit. +1 –  Apr 06 '19 at 18:29
  • @marmot, I like the gifs ;) – jan Apr 06 '19 at 18:30
  • 1
    @jan convert -density 300 -delay 144 -loop 0 -alpha remove multipage.pdf animated.gif, see https://tex.stackexchange.com/a/136919/121799. –  Apr 06 '19 at 18:31
  • One more question to the experts here. Any way to get the lines to stop at the pagemargins? BTW, @marmot, you are right that I'm building something "more fancy" (hence the other questions) but I'm trying to keep my MWE's in the questions most general and minimal ... maybe not the best idea as I then have to patch stuff back together ... – jan Apr 06 '19 at 18:35
  • 1
    @jan You can use tikz-pagenodes, which has the current page text area node. And I think you are doing it right because in their present form the questions and answers are useful for many, which they are not if you do some highly specialized things. (Will be off now.) –  Apr 06 '19 at 18:37
  • Two more questions: (a) any way to stop the lines at text margins (marmot suggests using pagenodes but I'm stuck at how to modify your code. (b) I'm trying to combine this with a solution to a previous question here where I use \fill instead of \draw. Would you be able to help me get that to work? – jan Apr 06 '19 at 19:11
  • Gonzalo's answer was fine, it was just that most of the extra was already incorporated into the tikzmark package so it could be simplified. I've now added the conditionals into the package. The pagenodes idea is a good one. I'm not sure what the problem with \fill is, can you elaborate on what's not working? – Andrew Stacey Apr 06 '19 at 20:40
  • @LoopSpace installed the updated package iftikzmarkoncurrentpage works great, thank you! -- What I was trying to do is use \fill[overlay,brace={pic cs:a\thetikzmarklines}{pic cs:b\thetikzmarklines}]; instead of \draw, brace being defined like in the addendum to marmot's answere here. No errors, but no braces drawn :( – jan Apr 07 '19 at 08:13
  • Oh, and one more thing: I was also using tikzmarknode instead of just tikzmark in order to be able to specify the location of the mark west of a phantom "x" \tikzmarknode{a\thetikzmarklines}{\vphantom{x}} (purpose just to define the vertical location of the beginning of the line relative to the text). But iftikzmarkoncurrentpage doesn't seem to work with tikzmarknode? – jan Apr 07 '19 at 08:25
  • I'll take a look. Could you send me your current best code? Either use the email from the docs or create an issue on github. Thanks! – Andrew Stacey Apr 07 '19 at 09:09
  • @LoopSpace Oops, sorry I didn't see your comment ... I sent you an email :) thanks so much for looking into this – jan Apr 07 '19 at 15:47