61

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?

AlexG
  • 54,894
soosap
  • 805

2 Answers2

57

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>.


In order to break longer <tip text> into multiple lines, wrap it in a \parbox of given width:

\tootltip{link text}{\parbox{0.5\linewidth}{... long tip text ...}}

Evince:

enter image description here

A-Reader:

enter image description here

\documentclass[a6paper,12pt]{scrbook}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% tooltips with LaTeX v. 2019/09/26
%
% \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}
\usepackage{tcolorbox}

\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}%
    \tcbox[colframe=black,colback=#7,size=fbox,arc=1ex,sharp corners=southwest]{#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}
  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}
AlexG
  • 54,894
  • 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 08 '16 at 16:45
  • 1
    The problem seems to be that my system is too old. see: http://chat.stackexchange.com/transcript/message/32189614#32189614 – Gilles Bonnet Sep 08 '16 at 17:45
  • I could not make this solution to work. It complained that tooltip was not recognized. Anyway, I swiched to pdfcomment – Mikaël Mayer Jul 07 '17 at 14:51
  • @MikaëlMayer : What did complain? pdflatex? Your PDF viewer? Maybe your TeX installation needs an upgrade (I recommend TeXLive-2017). I compiled the code with pdflatex (TL 2017) and opened the PDF in Evince. The links "formula" and "Pythagoras" work as advertised. – AlexG Jul 07 '17 at 16:59
  • 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 08:54
  • It will not work if I put two or more asterisks. It says \tpPdfLink has an extra }, paragraph ended before \tpPdfLink was complete and a bunch of undefined control sequences for \ocgbase. =( (I'm using texlive-full package on Debian 9 'Stretch') – João Victor Bateli Romão Mar 23 '18 at 02:07
  • "TeXLive" means nothing. Which version do you use? Look at the top of the *.log file. – AlexG Mar 23 '18 at 05:54
  • "This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) (preloaded format=pdflatex 2018.3.3)". Is this too old? =/ – João Victor Bateli Romão Mar 28 '18 at 00:40
  • TL-16 is definitely too old. TL-17 is final now and TL-18 to be released end of april. – AlexG Mar 28 '18 at 04:56
  • Very good! But I get: "Package typearea Warning: Maybe no optimal type area setting" – exchange Jun 24 '18 at 08:58
  • The example makes use of A6 papersize (post card) and a \Huge font just for the sake of producing the nice screen recording shown above, but which is not optimal in terms of typography (as juged by the scrbook documentclass used here). For real-world applications, other papersize/font combinations would be used and the warning would disappear. Since It is unrelated to the \tooltip macro you can safely ignore the warning. – AlexG Jun 24 '18 at 10:15
  • I copy pasted this into an overleaf document but the it doesn't compile properly. The editor doesn't seem to know \tpTipOcg}\ocgbase@open@stack@push{\tpTipOcg} and \tpTipOcg}\ocgbase@open@stack@pop\tpNull – ViktorStein Jul 10 '19 at 15:13
  • 1
    Overleaf's package status is ancient. You would be better off having TeXLive or MiKTeX installed on your computer. – AlexG Jul 10 '19 at 15:20
  • Small issue with \tooltip****: Firefox's built-in PDF viewer (pdfjs) shows the tooltip boxes unconditionally (even if you don't click anything). – copy Apr 11 '20 at 16:17
  • 2
    @copy It's Firefox's fault. – AlexG Jun 26 '20 at 12:29
  • Would I be correct to think that it won't work on a cellphone (since ocg is use and ocg are not working on cellphone, to my knowledge)? I obviously don't own a cellphone or tablet to try it. – sipaq11 Dec 04 '20 at 18:28
  • 1
    This is most likely correct. On portable devices it wouldn't work. – AlexG Dec 04 '20 at 19:50
  • These don't work in preview on mac or in Google Chrome. – Caleb Stanford Jun 01 '22 at 13:38
  • They don't, indeed. Send a feature request to Google, asking for OCG, Forms and JavaScript support in their PDF viewer. – AlexG Jun 01 '22 at 13: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.

Speravir
  • 19,491
  • correction: Tooltips in PDF documents are generally impossible :) – Caleb Stanford Jun 01 '22 at 13:42
  • The rest of the answer explains why. – Caleb Stanford Jun 01 '22 at 13:43
  • 1
    That's also my conclusion from the last 15 minutes of research and trying to get one of the solutions to work. I think they're all pdf-viewer-specific. Preview on Mac and Google Chrome won't display things correctly. It's not really satisfactory to have a solution that only works on a few PDF viewers. – Caleb Stanford Jun 01 '22 at 13:43