3

I'm writing a double-paged document where I'm using pdfpages to insert a pdf on every other page, so that if you read it like a book, the page on the right shows the pdf, while the one on the left is reserved for comments. For these comments, I would like to draw some lines, or arrows, or boxes, or something like that, that connect the comments to stuff in the pdf. I thought I would probably have to use TikZ for that, but I have no idea how, as I have never used that before. Is something like that even possible?

I found this post, which is similar, but too complex for me to understand what's going on.

mapf
  • 207
  • Hello! It will help to produce a useful answer if you post some code that produces a document as described, with some pdf pages inserted and comments on the opposite page. – Simon Dispa Aug 05 '22 at 17:23
  • 1
    Somewhat related: https://tex.stackexchange.com/questions/363957/position-a-tikz-background-pattern-which-is-oversize-to-bleed-off-the-edge-of-t – John Kormylo Aug 05 '22 at 18:56
  • @SimonDispa that's fair. But I wasn't fast enough for Jasper Habicht's answer. – mapf Aug 06 '22 at 09:11

1 Answers1

4

As I understood your question, you have two pages next to each other, one on the right where you include a page from some PDF file, and one on the left where you want to state annotations. Then, you want to draw lines going from the left to the right, crossing the page boundaries.

With the following approach that works a bit like tikzmarks, you can use the macro \annotline to define the coordinate on the next page (the upper left corner of the page is the origin, unit is centimeters) where you want to draw a line to. The macro will then draw a line starting where you placed the macro that goes towards the right margin of the page where it turns up or down until it reaches the height of the coordinate on the next page where it turns to the right again. You can use the macro \annotlinebreakdist to define the distance from the right margin of the page to the vertical part of the line.

On the next page, you can use the macro \printannotlines to draw the remaining part of the lines that start form the left margin of the page and go to the relevant coordinate. The macro automatically draws all the lines that haven't been finished until then.

You can style the line using TikZ styles. In case the lines overlap, you can use the second optional argument to shift the vertical part of the line to the right or left. Using the first optional parameter, you can shift the starting point of the line to the left or right.

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

\tikzset{ annotline/.style={ very thick, red }, annotline start/.style={ }, annotline end/.style={ -> } }

\ExplSyntaxOn

\dim_new:N \l_annotline_breakdist_dim \dim_set:Nn \l_annotline_breakdist_dim { 1cm }

\NewDocumentCommand{\annotlinebreakdist}{ m }{ \dim_set:Nn \l_annotline_breakdist_dim { #1 } }

\clist_new:N \l_annotline_allxpos_clist \clist_new:N \l_annotline_allypos_clist \int_new:N \l_annotline_currid_int \int_new:N \l_annotline_lastid_int

\NewDocumentCommand{\annotline}{ O{0pt} O{0pt} m m }{% \clist_put_right:Nn \l_annotline_allxpos_clist { #3 } \clist_put_right:Nn \l_annotline_allypos_clist { #4 } \int_incr:N \l_annotline_currid_int \begin{tikzpicture}[remember~picture, overlay] \coordinate (annotline-\int_use:N\l_annotline_currid_int -start) at ([xshift=#1,yshift=.5ex]0,0); \coordinate (annotline-\int_use:N\l_annotline_currid_int -start-break) at ([xshift={-1\dim_use:N\l_annotline_breakdist_dim+#2}]current~page.east); \coordinate (annotline-\int_use:N\l_annotline_currid_int -start-margin) at ([shift={(0,-1#4)}]current~page.north~east); \draw[annotline, annotline~start] (annotline-\int_use:N\l_annotline_currid_int -start) -- (annotline-\int_use:N\l_annotline_currid_int -start -| annotline-\int_use:N\l_annotline_currid_int -start-break) |- (annotline-\int_use:N\l_annotline_currid_int -start-margin); \end{tikzpicture} }

\dim_new:N \l_annotline_currxpos_dim \dim_new:N \l_annotline_currypos_dim

\NewDocumentCommand{\annotlineend}{ m }{% \dim_set:Nn \l_annotline_currxpos_dim { \clist_item:Nn \l_annotline_allxpos_clist #1 cm } \dim_set:Nn \l_annotline_currypos_dim { \clist_item:Nn \l_annotline_allypos_clist #1 cm } \begin{tikzpicture}[remember~picture, overlay] \coordinate (annotline-#1-end-margin) at ([shift={(0,-1\int_use:N\l_annotline_currypos_dim)}]current~page.north~west); \coordinate (annotline-#1-end) at ([shift={(\dim_use:N\l_annotline_currxpos_dim,-1\dim_use:N\l_annotline_currypos_dim)}]current~page.north~west); \draw[annotline, annotline~end] (annotline-#1-end-margin) -- (annotline-#1-end); \end{tikzpicture} }

\NewDocumentCommand{\printannotlines}{}{% \int_incr:N \l_annotline_lastid_int \foreach \i in {\int_use:N\l_annotline_lastid_int,...,\int_use:N\l_annotline_currid_int} { \annotlineend{\i} } \int_set:Nn \l_annotline_lastid_int \l_annotline_currid_int }

\ExplSyntaxOff

\begin{document}

\annotlinebreakdist{2cm}

Some very interesting thing \annotline[0pt][10pt]{8}{5}

Some other interesting thing \annotline[0pt][-10pt]{12}{10}

\vspace{10cm}

Yet another interesting thing \annotline{16}{7.5}

\newpage

\noindent \includegraphics[width=\textwidth]{example-image-a}

\printannotlines

\newpage

Again some very interesting thing \annotline{10}{10}

\newpage

\noindent \includegraphics[width=\textwidth]{example-image-a}

\printannotlines

\end{document}

enter image description here


If you want a vertical line alongside the comment, you might want to use a node which contains the comment:

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

\tikzset{ annotline/.style={ very thick, red }, annotline start/.style={ }, annotline end/.style={ -> }, annotline box/.style={ inner sep=0pt, text width=5cm, } }

\ExplSyntaxOn

\dim_new:N \l_annotline_breakdist_dim \dim_set:Nn \l_annotline_breakdist_dim { 1cm }

\NewDocumentCommand{\annotlinebreakdist}{ m }{ \dim_set:Nn \l_annotline_breakdist_dim { #1 } }

\clist_new:N \l_annotline_allxpos_clist \clist_new:N \l_annotline_allypos_clist \int_new:N \l_annotline_currid_int \int_new:N \l_annotline_lastid_int

\NewDocumentEnvironment{annotlinebox}{ O{0pt} O{0pt} m m +b }{% \clist_gput_right:Nn \l_annotline_allxpos_clist { #3 } \clist_gput_right:Nn \l_annotline_allypos_clist { #4 } \int_gincr:N \l_annotline_currid_int \begin{tikzpicture}[remember~picture] \node[annotline~box] (annotline-\int_use:N\l_annotline_currid_int -box) at (0,0) { { #5 } }; \begin{scope}[overlay] \coordinate (annotline-\int_use:N\l_annotline_currid_int -start) at ([xshift=#1]annotline-\int_use:N\l_annotline_currid_int -box.north~east); \coordinate (annotline-\int_use:N\l_annotline_currid_int -start-break) at ([xshift={-1\dim_use:N\l_annotline_breakdist_dim+#2}]current~page.east); \coordinate (annotline-\int_use:N\l_annotline_currid_int -start-margin) at ([shift={(0,-1#4)}]current~page.north~east); \draw[annotline, annotline~start] (annotline-\int_use:N\l_annotline_currid_int -box.south~east -| annotline-\int_use:N\l_annotline_currid_int -start) -- (annotline-\int_use:N\l_annotline_currid_int -start) -- (annotline-\int_use:N\l_annotline_currid_int -start -| annotline-\int_use:N\l_annotline_currid_int -start-break) |- (annotline-\int_use:N\l_annotline_currid_int -start-margin); \end{scope} \end{tikzpicture} }{}

\dim_new:N \l_annotline_currxpos_dim \dim_new:N \l_annotline_currypos_dim

\NewDocumentCommand{\annotlineend}{ m }{% \dim_set:Nn \l_annotline_currxpos_dim { \clist_item:Nn \l_annotline_allxpos_clist #1 cm } \dim_set:Nn \l_annotline_currypos_dim { \clist_item:Nn \l_annotline_allypos_clist #1 cm } \begin{tikzpicture}[remember~picture, overlay] \coordinate (annotline-#1-end-margin) at ([shift={(0,-1\int_use:N\l_annotline_currypos_dim)}]current~page.north~west); \coordinate (annotline-#1-end) at ([shift={(\dim_use:N\l_annotline_currxpos_dim,-1\dim_use:N\l_annotline_currypos_dim)}]current~page.north~west); \draw[annotline, annotline~end] (annotline-#1-end-margin) -- (annotline-#1-end); \end{tikzpicture} }

\NewDocumentCommand{\printannotlines}{}{% \int_incr:N \l_annotline_lastid_int \foreach \i in {\int_use:N\l_annotline_lastid_int,...,\int_use:N\l_annotline_currid_int} { \annotlineend{\i} } \int_set:Nn \l_annotline_lastid_int \l_annotline_currid_int }

\ExplSyntaxOff

\begin{document}

\annotlinebreakdist{2cm}

\begin{annotlinebox}{8}{5} Some very interesting thing \end{annotlinebox}

\vspace{10cm}

\begin{annotlinebox}{12}{10} Some other interesting thing \ which is a bit longer \ than the other \end{annotlinebox}

\newpage

\noindent \includegraphics[width=\textwidth]{example-image-a}

\printannotlines

\end{document}

enter image description here

  • Wow, what a great answer! It works like charm. Thanks a lot! – mapf Aug 06 '22 at 09:09
  • 1
    @mapf I wasn't sure whether this would suit your needs. I just corrected a minor flaw in the code (It had four lines which were remains from prior testing but which are not necessary actually) so I updated the answer. – Jasper Habicht Aug 06 '22 at 09:19
  • It's exactly what I was thinking of. I'd like to use it for a cumulative thesis where I comment on the incorporated pdfs of papers (afaik you cannot include the actual tex code of the papers instead and make that work, which is a shame but understandable). It's based on the kaobook and classic thesis styles and I think your solution will fit right in. – mapf Aug 06 '22 at 15:28
  • I have a follow-up question, but I'm not sure how complicated that change is, maybe it should be its own post. I would like to change how the line connects to the comments. I would like it to end in a vertical line that is located at the right side of the comment and as long as its height. I tried changing some stuff in the definition of \annotline, but it's really poking in the dark. I'm not really sure what any of that code means. – mapf Nov 23 '22 at 09:40
  • 1
    @mapf I added a variation to my answer that uses a node to contain the comment. Using this approach, it is easy to append a vertical line to the side of the comment. – Jasper Habicht Nov 23 '22 at 10:39
  • Amazing, thanks a lot! I didn't expect such a quick reply. So in the meantime, I started to undertand parts of your code and managed to come up with my own way of doing it. My biggest problem was figuring out what the height of the text block would be. Now I'm essentially using what is shown here as a wrapper around the \annotline command. But your solution is much more elegant I think. – mapf Nov 23 '22 at 16:34
  • Sorry, maybe one more question: Why do you have to use ~ in your code for the spaces in the arguments? I was trying to add some rectangles with rounded corners, but I kept getting an error saying that the command wasn't recognized. I only just now understand thtat this was because the space got removed. – mapf Nov 24 '22 at 12:29
  • 1
    @mapf Between \ExplSyntaxOn and \ExplSyntaxOff, spaces are ignored. But some TikZ options, such as rounded corners, need a space. You can use ~ to insert a space inside the expl3 syntax block since ~ will be converted to a space. – Jasper Habicht Nov 24 '22 at 12:40
  • Ok, I know this is getting out of hand, but I have one more comment: for some reason, when I use the commands for a second set of pages, the "right-page pointing part" from the previous set gets repeated. If I understand correctly, you were trying to handly this in this line \int_set:Nn \l_annotline_lastid_int \l_annotline_currid_int, but it has no effect (in fact nothing I put there seems to). So I created a new command that resets the lists and ids. For some reason, it needs to be executed after \includepdf[pagecommand={\printannotlines}]{...}, passing it along doesn't work either. – mapf Nov 24 '22 at 15:47
  • 1
    @mapf Sorry, but I cannot reproduce this problem with my code above. It is probably a scoping issue. Try to replace \int_incr:N \l_annotline_lastid_int by \int_gincr:N \l_annotline_lastid_int and \int_set:Nn \l_annotline_lastid_int \l_annotline_currid_int by \int_gset:Nn \l_annotline_lastid_int \l_annotline_currid_int in the defintion for the \printannotlines macro to set the two counters globally. If this does not help, I suggest that you ask a new question and show your current code. – Jasper Habicht Nov 24 '22 at 16:05
  • I see, I'll give it a try! Thanks a lot for all the help. – mapf Nov 24 '22 at 16:12
  • 1
    Just to let you know: your suggestion works! Thanks! – mapf Nov 25 '22 at 09:06