2

When viewing PDFs from ACS publications with links, you can click on a reference to follow a link to it somewhere on the internet. Most of the times, when doing so you get some kind of a menu with a selection of where you want to find this reference (see image below). This works in Foxit Reader as well as Acrobat Reader DC.

Can this be done in LaTeX? And if so, how?

You can find an example document here, albeit behind a paywall.

enter image description here

1
  • 1
    I happen to have access to this file. I had a look at its PDF code. It makes use of JavaScript to go to the URL selected from the list. So the range of PDF-viewers is limited. But with OCGs (PDF Layers) we are able to implement something that doesn' use JS, but works in Acrobat-Reader as well as in Evince.
    – AlexG
    Apr 23 '18 at 13:25
1

Something similar may be implemented using PDF Layers (OCGs) which does not rely on JavaScript. Besides Acrobat Reader, it also works in Evince. The only problem with Evince is that the link areas are sensitive even if the pop-up box is hidden.

Click on the link in the page to show the pop-up with 3 URLs, click again to hide it. The code makes use of the \tooltip****{...}{...} command defined ↗elsewhere.

\documentclass{article}
\usepackage[a5paper]{geometry}

\usepackage{hyperref}
%patch hyperref to make PDF Annotations PDF-Layer-(OCG)-aware
\makeatletter
  \let\Hy@setpdfborderOrig\Hy@setpdfborder
  \def\Hy@setpdfborder{\ocgbase@insert@oc\Hy@setpdfborderOrig}%
\makeatother

%\usepackage[ocgcolorlinks]{ocgx2}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% tooltips with LaTeX v. 2018/01/15
%
% \tooltip[*[*[*[*]]]]
%            [<link colour>]{<link text>}
%            [<tip box colour>]{<tip text>}
%            [<x-offset>,<y-offset>]
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   \tooltip     --> draggable tip, visible on mouse-over, hidden on mouse-out
%
%   \tooltip*    --> draggable tip, toggle visiblity on mouse-over
%
%   \tooltip**   --> NON-draggable tip, visible on mouse-over, hidden on mouse-out
%
%   \tooltip***  --> NON-draggable tip, toggle visiblity on mouse-over
%
%   \tooltip**** --> NON-draggable tip, toggle visiblity on mouse-click (Evince!)
%
% Default link colour can be set with
%
%   \usepackage[linkcolor=<colour>]{hyperref}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usepackage{pdfbase}[2017/03/16]
\usepackage{xparse,ocgbase}
\usepackage{xcolor,calc}
\usepackage{tikzpagenodes,linegoal}
\usetikzlibrary{calc}

\ExplSyntaxOn
\let\tpPdfLink\pbs_pdflink:nn
\let\tpPdfAnnot\pbs_pdfannot:nnnn\let\tpPdfLastAnn\pbs_pdflastann:
\let\tpAppendToFields\pbs_appendtofields:n
\def\tpPdfXform{\pbs_pdfxform:nnnnn{1}{1}{}{}}
\let\tpPdfLastXform\pbs_pdflastxform:
\let\cListSet\clist_set:Nn\let\cListItem\clist_item:Nn
\ExplSyntaxOff

\makeatletter
\NewDocumentCommand{\tooltip}{%
  ssssO{\ifdefined\@linkcolor\@linkcolor\else blue\fi}mO{yellow!20}mO{0pt,0pt}%
}{{%
  \leavevmode%
  \IfBooleanT{#2}{%
    %for variants with two and more stars, put tip box on a PDF Layer (OCG)
    \ocgbase@new@ocg{tipOCG.\thetcnt}{%
      /Print<</PrintState/OFF>>/Export<</ExportState/OFF>>%
    }{false}%
    \xdef\tpTipOcg{\ocgbase@last@ocg}%
    %prevent simultaneous visibility of multiple non-draggable tooltips
    \ocgbase@add@ocg@to@radiobtn@grp{tool@tips}{\ocgbase@last@ocg}%
  }%
  \tpPdfLink{%
    \IfBooleanTF{#4}{%
      /Subtype/Link/Border[0 0 0]/A <</S/SetOCGState/State [/Toggle \tpTipOcg]>>
    }{%
      /Subtype/Screen%
      /AA<<%
        \IfBooleanTF{#3}{%
          /E<</S/SetOCGState/State [/Toggle \tpTipOcg]>>%
        }{%
          \IfBooleanTF{#2}{%
            /E<</S/SetOCGState/State [/ON \tpTipOcg]>>%
            /X<</S/SetOCGState/State [/OFF \tpTipOcg]>>%
          }{
            \IfBooleanTF{#1}{%
              /E<</S/JavaScript/JS(%
                var fd=this.getField('tip.\thetcnt');%
                if(typeof(click\thetcnt)=='undefined'){%
                  var click\thetcnt=false;%
                  var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
                }%
                if(fd.display==display.hidden){%
                  fd.delay=true;fd.display=display.visible;fd.delay=false;%
                }else{%
                  if(!click\thetcnt&&!dragging\thetcnt){fd.display=display.hidden;}%
                  if(!dragging\thetcnt){click\thetcnt=false;}%
                }%
                this.dirty=false;%
              )>>%
            }{%
              /E<</S/JavaScript/JS(%
                var fd=this.getField('tip.\thetcnt');%
                if(typeof(click\thetcnt)=='undefined'){%
                  var click\thetcnt=false;%
                  var fdor\thetcnt=fd.rect;var dragging\thetcnt=false;%
                }%
                if(fd.display==display.hidden){%
                  fd.delay=true;fd.display=display.visible;fd.delay=false;%
                }%
               this.dirty=false;%
              )>>%
              /X<</S/JavaScript/JS(%
                if(!click\thetcnt&&!dragging\thetcnt){fd.display=display.hidden;}%
                if(!dragging\thetcnt){click\thetcnt=false;}%
                this.dirty=false;%
              )>>%
            }%
            /U<</S/JavaScript/JS(click\thetcnt=true;this.dirty=false;)>>%
            /PC<</S/JavaScript/JS (%
              var fd=this.getField('tip.\thetcnt');%
              try{fd.rect=fdor\thetcnt;}catch(e){}%
              fd.display=display.hidden;this.dirty=false;%
            )>>%
            /PO<</S/JavaScript/JS(this.dirty=false;)>>%
          }%
        }%
      >>%
    }%
  }{{\color{#5}#6}}%
  \sbox\tiptext{%
    \IfBooleanT{#2}{%
      \ocgbase@oc@bdc{\tpTipOcg}\ocgbase@open@stack@push{\tpTipOcg}}%
    \fcolorbox{black}{#7}{#8}%
    \IfBooleanT{#2}{\ocgbase@oc@emc\ocgbase@open@stack@pop\tpNull}%
  }%
  \cListSet\tpOffsets{#9}%
  \edef\twd{\the\wd\tiptext}%
  \edef\tht{\the\ht\tiptext}%
  \edef\tdp{\the\dp\tiptext}%
  \tipshift=0pt%
  \IfBooleanTF{#2}{%
    %OCG-based (that is, all non-draggable) boxes should not extend beyond the
    %current column as they may get overlaid by text in the neighbouring column
    \setlength\whatsleft{\linegoal}%
  }{%
    \measureremainder{\whatsleft}%
  }%
  \ifdim\whatsleft<\dimexpr\twd+\cListItem\tpOffsets{1}\relax%
    \setlength\tipshift{\whatsleft-\twd-\cListItem\tpOffsets{1}}\fi%
  \IfBooleanF{#2}{\tpPdfXform{\tiptext}}%
  \raisebox{\heightof{#6}+\tdp+\cListItem\tpOffsets{2}}[0pt][0pt]{%
    \makebox[0pt][l]{\hspace{\dimexpr\tipshift+\cListItem\tpOffsets{1}\relax}%
    \IfBooleanTF{#2}{\usebox{\tiptext}}{%
      \tpPdfAnnot{\twd}{\tht}{\tdp}{%
        /Subtype/Widget/FT/Btn/T (tip.\thetcnt)%
        /AP<</N \tpPdfLastXform>>%
        /MK<</TP 1/I \tpPdfLastXform/IF<</S/A/FB true/A [0.0 0.0]>>>>%
        /Ff 65536/F 3%
        /AA <<%
          /U <<%
            /S/JavaScript/JS(%
              var fd=event.target;%
              var mX=this.mouseX;var mY=this.mouseY;%
              var drag=function(){%
                var nX=this.mouseX;var nY=this.mouseY;%
                var dX=nX-mX;var dY=nY-mY;%
                var fdr=fd.rect;%
                fdr[0]+=dX;fdr[1]+=dY;fdr[2]+=dX;fdr[3]+=dY;%
                fd.rect=fdr;mX=nX;mY=nY;%
              };%
              if(!dragging\thetcnt){%
                dragging\thetcnt=true;Int=app.setInterval("drag()",1);%
              }%
              else{app.clearInterval(Int);dragging\thetcnt=false;}%
              this.dirty=false;%
            )%
          >>%
        >>%
      }%
      \tpAppendToFields{\tpPdfLastAnn}%
    }%
  }}%
  \stepcounter{tcnt}%
}}
\makeatother
\newsavebox\tiptext\newcounter{tcnt}
\newlength{\whatsleft}\newlength{\tipshift}
\newcommand{\measureremainder}[1]{%
  \begin{tikzpicture}[overlay,remember picture]
    \path let \p0 = (0,0), \p1 = (current page.east) in
      [/utils/exec={\pgfmathsetlength#1{\x1-\x0}\global#1=#1}];
  \end{tikzpicture}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}\huge
  Some useful \tooltip****{web sites}{\parbox{3cm}{\href{https://tex.stackexchange.com}{TeX.SX}\\\href{https://www.tug.org}{TUG}\\\href{https://www.ctan.org}{CTAN}}}.
\end{document}
7
  • "%patch hyperref to make PDF Annotations PDF-Layer-(OCG)-aware" should that be a hyperref option (or always on or ....) Apr 23 '18 at 13:48
  • Don't know. It inserts an /OC entry into a PDF Annotation dictionary if it is placed in an ocg environment defined by the ocgx2 pkg. If the OCG is made invisible by the user, the link and its sensitive area is also hidden.
    – AlexG
    Apr 23 '18 at 14:05
  • @David I just had a look into ocgbase.sty where \ocgbase_insert_oc:n is defined. It would produce a compilation error if ocgbase.sty is not loaded. So maybe this should not be added to hyperref by default.
    – AlexG
    Apr 23 '18 at 14:12
  • yes would need some coordination, or I suppose hyperref could define it to be empty if not defined, maybe I'll add a gh issue on hyperref but not change any code for now:-) Apr 23 '18 at 14:17
  • 1
    Several versions of the \tooltip macro are provided, but only \tooltip****{...}{...} is used in the document. The variant with four stars doesn't insert JS.
    – AlexG
    Apr 23 '18 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.