42

Is it possible to get tooltips into a LaTeX pdf?

I am working on my CV. I would like to show some more information on my electronic version once you swipe over that field with the mouse. i.e. when swiping with the mouse over education I want to show my subjects taken in undergrad through a tooltip.

Is this possible and if yes would if work for all kind of pdf readers?

40

Finally I came up with a \tooltip command that works across a small number of PDF viewers, among which is an Open-Source one. The tooltip command allows for TeX-formatted tip texts.

\tooltip[*[*[*[*]]]]
           [<link colour>]{<link text>}
           [<tip box colour>]{<tip text>}
           [<x-offset>,<y-offset>]

It comes in five variants:

%draggable tip box (e. g. https://tex.stackexchange.com/a/108998),
%visible on mouse-over, hidden on mouse-out
\tooltip{<link text>}{<tip text>}

%draggable tip box, toggle visibility on mouse-over (a second wipe hides the tip)
\tooltip*{<link text>}{<tip text>}  

%NON-draggable tip, visible on mouse-over, hidden on mouse-out
\tooltip**{<link text>}{<tip text>}  

%NON-draggable tip, toggle visiblity on mouse-over
\tooltip***{<link text>}{<tip text>}

%NON-draggable tip, toggle visiblity on mouse-click
\tooltip****{<link text>}{<tip text>}

For Evince (open-source), only the command with 4 stars \tooltip**** is usable, because mouse-click is the only event Evince listens for. In Acrobat Reader, all variants are functional.

The non-draggable variants (two and more stars) do not use any JavaScript.

If hyperref is loaded, the colour of internal links (hyperref option linkcolor) is used as <link colour>.


Evince:

enter image description here

\documentclass[a6paper,12pt]{scrbook}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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
  Einstein's \tooltip****{formula}{$E=m c^2$} is well known.
  Another famous formula is due to \tooltip****{Pythagoras}{$a^2+b^2=c^2$}.

  This \tooltip{tip}{is visible only in AR} is draggable and shown on mouse-over.
\end{document}
  • What package/class provides \ocgbase@new@ocg? – 1010011010 Nov 23 '15 at 12:11
  • @1010011010 ocgbase.sty (part of package ocgx2) loaded by media9.sty. – AlexG Nov 23 '15 at 12:46
  • 1
    I copy/pasted the code above but the compilation failed. Does someone has an idea why? The complete log file is there. The first error message is: ! Undefined control sequence. \tpPdfXform ->\pbs_pdfxform:nnn {1}{1} l.133 Einstein's \tooltip**{formula}{$E=m c^2$} is well known. The control sequence at the end of the top line of your error message was never \def'ed. [...] – Gilles Bonnet Sep 8 '16 at 16:45
  • 1
    The problem seems to be that my system is too old. see: chat.stackexchange.com/transcript/message/32189614#32189614 – Gilles Bonnet Sep 8 '16 at 17:45
  • 1
    I found why it did not work. I received no complaint from a spelling error in the name of the file containing your macro. Now it is fixed. Thanks ! – Mikaël Mayer Jul 10 '17 at 8:54
6

Tooltips in PDF documents are generally possible. I do know two packages; one of them you tagged yourself for your question, the other one I added, click on these tags to see, which questions were already asked in TeX.SX: & . But as Joseph Wright in a comment wrote:

How PDF viewers show 'hover text' is down the them, not the source (LaTeX or otherwise). Thus the best you can hope is to check with a set of viewers.

I can tell you, that SumatraPDF, a popular viewer for Windows, does not show any tooltip at all with “tooltip” in a strict meaning, but does show comments, when you hover with the mouse over one of them. What is supported, what not, can be seen when reading the documentation of package pdfcomment. There is a type \pdfmarkupcomment that actually almost acts like a tooltip.

See also this fixed bug in SumatraPDF Bug tracker: PDF Comments Don't Work.

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.