Javascript-Anwendung in Latex

Javascript-Anwendung in Latex

Ich möchte wissen, ob es möglich ist, einem Latex-Dokument eine mit Javascript erstellte interaktive App hinzuzufügen.

Ich möchte einige der Javascripts hinzufügen, die erscheinenHier.

Wie das Eine:

Bildbeschreibung hier eingeben

BEARBEITEN

Ich kann das .js-Dokument haben, daher möchte ich wissen, wie ich eine .js-Datei an Latex anhängen kann.

Irgendeine Idee? Irgendeine Hilfe?

Antwort1

Dies portiert das Kartenmischbeispiel unter Verwendung von PDF Layers (Paket ocgx2) und JavaScript nach LaTeX und PDF. Zur Anzeige ist Acrobat Reader erforderlich.

Aktualisieren: Erweitertes Beispiel mit Diagramm, das die Königs-Karo-Position gegenüber der Gewehranzahl aufzeichnet.

Warnung:pdflatexAufgrund der großen Anzahl von OCGs (ca. 21 KB), die erstellt werden, dauert es etwa 2 Stunden, den Code zweimal zu kompilieren. Darüber hinaus muss für pdflatexeine erfolgreiche Ausführung main_memorydas Format vergrößert oder lualatexstattdessen verwendet werden. Das (ursprüngliche) Beispiel ohne das Diagramm wird viel schneller kompiliert (zweite Codebox).

Bildbeschreibung hier eingeben

\documentclass[a4paper,landscape]{article}

\usepackage{tikz,color,calc}
\usepackage{media9} %\mediabutton
\usepackage{xsavebox,ocgx2}

%suit symbols from https://tex.stackexchange.com/a/9643
\DeclareSymbolFont{extraup}{U}{zavm}{m}{n}
\DeclareMathSymbol{\varheart}{\mathalpha}{extraup}{86}
\DeclareMathSymbol{\vardiamond}{\mathalpha}{extraup}{87}

%typesets playing card; args: value, suite, colour
\makeatletter
\def\mycard#1#2#3{%
  \fbox{\rule[-4ex]{0pt}{5ex}\makebox[3.5ex][l]{#1$\color{#3}\@nameuse{#2}$}}}
\makeatother

%initialisations (JavaScript) on page-open (/O <<...>>), reset on page-close
\usepackage{ifluatex}
\ifluatex\def\pdfpageattr{\pdfvariable pageattr}\fi
\begingroup
\edef\x{\endgroup
  \pdfpageattr{
    \the\pdfpageattr
    /AA <<
      /O << /S/JavaScript /JS (%
%        console.show();
        console.clear();
        %riffle top card
        var riffle=function(){
          for(var i=0;i<52;i++) oldOrder[i]=order[i];
          if(order[0]!=51){
            %remove current card from top
            var top=order.shift();
            %insert `top' at new random position
            order.splice(1+Math.random()*order.length, 0, top);
            %new King Diamond position
            KdiamondPos=order.indexOf(51);
            ++riffleCount;
            console.println(riffleCount+' '+KdiamondPos);
          }
        };
        var update=function(){
          %update OCG visibility
          for(tablePos=0;tablePos<52;tablePos++){
            try{card[tablePos][oldOrder[tablePos]].state=false;}catch(e){}
            try{card[tablePos][order[tablePos]].state=true;}catch(e){}
          }
          try{pix[riffleCount][KdiamondPos].state=true;}catch(e){}
        };
        var reset=function(){
          console.clear();
          try{app.clearInterval(myIntA);}catch(e){}
          try{app.clearInterval(myIntB);}catch(e){}
          for(var i=0;i<52;i++) {oldOrder[i]=order[i]; order[i]=i;}
          riffleCount=0; KdiamondPos=51;
          for(var j=0;j<52;j++){
            for(var i=0;i<350;i++){
              try{pix[i][j].state=false;}catch(e){}
            }
          }
          update(); 
        };
        %card[<table position>][<stack position>]
        var card=new Array(52);
        for(var i=0;i<52;i++){card[i]=new Array(52);}
        %pix[<riffle count>][<stack position>]
        var pix=new Array(350);
        for(var i=0;i<350;i++){pix[i]=new Array(52);}
        ocg=this.getOCGs(this.pageNum);
        for(var i in ocg){
          ocgName=ocg[i].name.split('-');
          if(ocgName[2]=='card')
            card[ocgName[0]][ocgName[1]]=ocg[i];
          else % 'pix'
            pix[ocgName[0]][ocgName[1]]=ocg[i];
        }%
        %initial order
        var order=new Array(52); for(var i=0;i<52;i++) order[i]=i;
        var oldOrder=new Array(52);
        var riffleCount=0, KdiamondPos=51;
      ) >>
      /C << /S/JavaScript /JS (reset();) >>
    >>
  }
}
\x

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}\parindent=0pt%
%
% build chart
\xsavebox{Pix}[0.317mm][c]{\tikz\fill (0,0) circle [radius=0.5mm];}
\parbox{\linewidth}{\offinterlineskip%
  $\uparrow$ K$\color{red}\vardiamond$ position\\[0.5ex]
  \makebox[111mm]{\hrulefill}\\
    \foreach \j in {0,...,51}{%
      \foreach \i in {0,...,349}{%
         \expandafter\ifnum\numexpr\j+\i\relax<51
           \phantom{\thePix}%
         \else%  
           \begin{ocg}{\i-\j-pix}{\i-\j-pix}{off}%
             \thePix%
           \end{ocg}%
         \fi% 
      }\\
    }%
  \makebox[111mm]{\hrulefill}\\[0.5ex]
  \makebox[111mm][r]{riffle count $\rightarrow$}%
  \begin{ocg}{0-51-pix}{0-51-pix}{on}\end{ocg}%
}\\[1ex]

%typeset playing cards into xsaveboxes
\foreach \suit/\suitcol in {%
  spadesuit/black,clubsuit/black,varheart/red,vardiamond/red}{%
  \fboxrule=0.5pt\fboxsep=3pt%
  \foreach \val in {A,2,3,...,10,J,Q,K}{%
    \xsavebox{\val-\suit}{\mycard{\val}{\suit}{\suitcol}}%
  }%
}%
\xsavebox{K-vardiamond}{%
  \fboxsep=1.5pt\fboxrule=2pt\mycard{K}{vardiamond}{red}}%
%
%create layered array of cards: 13x4x52=2704 OCGs!
\foreach \j in {0,...,3}{%
  \foreach \i in {0,...,12}{%
    \fboxrule=0pt\fboxsep=3.5pt%
    \makebox[\widthof{\xusebox{K-vardiamond}}][l]{%
      \foreach \suit/\jj in {spadesuit/0,clubsuit/1,varheart/2,vardiamond/3}{%
        \foreach \val/\ii in {%
          A/0,2/1,3/2,4/3,5/4,6/5,7/6,8/7,9/8,10/9,J/10,Q/11,K/12}{%
          \xdef\tablePos{\the\numexpr\j*13+\i\relax}%
          \xdef\stackPos{\the\numexpr\jj*13+\ii\relax}%
          \begin{ocg}{\tablePos-\stackPos-card}{\tablePos-\stackPos-card}{%
            \expandafter\ifnum\numexpr\tablePos-\stackPos\relax=0 on%
            \else off\fi%
          }%
            \makebox[0pt][l]{\xusebox{\val-\suit}}%
          \end{ocg}%
        }%
      }%
    }~%
  }\\%
}\\[1ex]
\mediabutton[
  jsaction={riffle();update();}
]{\fbox{\strut Riffle}}
\mediabutton[
  jsaction={
    var myIntA=app.setInterval(
      'riffle();update();if(riffleCount\%10==0||order[0]==51)
        app.clearInterval(myIntA);',100);
  }
]{\fbox{\strut Riffle$\times$10}}
\mediabutton[
  jsaction={
    var myIntB=app.setInterval(
      'riffle();update();if(order[0]==51) app.clearInterval(myIntB);',100);
  }
]{\fbox{\strut Auto Riffle}}
\mediabutton[
  jsaction={reset();}
]{\fbox{\strut Reset}}

\end{document}

Originalbeispiel ohne Diagramm:

Bildbeschreibung hier eingeben

\documentclass[a4paper,landscape]{article}

\usepackage{pgffor,color,calc}
\usepackage{media9} %\mediabutton
\usepackage{xsavebox,ocgx2}

%suit symbols from https://tex.stackexchange.com/a/9643
\DeclareSymbolFont{extraup}{U}{zavm}{m}{n}
\DeclareMathSymbol{\varheart}{\mathalpha}{extraup}{86}
\DeclareMathSymbol{\vardiamond}{\mathalpha}{extraup}{87}

%typesets playing card; args: value, suite, colour
\makeatletter
\def\mycard#1#2#3{%
  \fbox{\rule[-4ex]{0pt}{5ex}\makebox[3.5ex][l]{#1$\color{#3}\@nameuse{#2}$}}}
\makeatother

%initialisations (JavaScript) on page-open (/O <<...>>)
\usepackage{ifluatex}
\ifluatex\def\pdfpageattr{\pdfvariable pageattr}\fi
\begingroup
\edef\x{\endgroup
  \pdfpageattr{
    \the\pdfpageattr
    /AA << /O << /S/JavaScript /JS (%
      console.show();
      console.clear();
      %card[<table position>][<stack position>]
      var card=new Array(52);
      for(var i=0;i<52;i++){card[i]=new Array(52);}
      ocg=this.getOCGs(this.pageNum);
      for(var i in ocg){
        ocgName=ocg[i].name.split('-');
        card[ocgName[0]][ocgName[1]]=ocg[i];
      }%
      %initial order
      var order=new Array(52);
      var oldOrder=new Array(52);
      for(i=0;i<52;i++) order[i]=i;
      var riffleCount=0;
      %riffle top card
      var riffle=function(){
        for(i=0;i<52;i++) oldOrder[i]=order[i];
        if(order[0]!=51){
          %remove current card from top
          var top=order.shift();
          %insert `top' at new random position
          order.splice(1+Math.random()*order.length, 0, top);
          console.println(++riffleCount);
        }
      };
      var update=function(){
        %update OCG visibility
        for(tablePos=0;tablePos<52;tablePos++){
          card[tablePos][oldOrder[tablePos]].state=false;
          card[tablePos][order[tablePos]].state=true;
        }
      };
      var reset=function(){
        for(i=0;i<52;i++) {oldOrder[i]=order[i]; order[i]=i;}
        update(); riffleCount=0;
        console.clear();
      };
    ) >> >>
  }
}
\x

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}\parindent=0pt%
%
%typeset playing cards into xsaveboxes
\foreach \suit/\suitcol in {%
  spadesuit/black,clubsuit/black,varheart/red,vardiamond/red}{%
  \fboxrule=0.5pt\fboxsep=3pt%
  \foreach \val in {A,2,3,...,10,J,Q,K}{%
    \xsavebox{\val-\suit}{\mycard{\val}{\suit}{\suitcol}}%
  }%
}%
\xsavebox{K-vardiamond}{%
  \fboxsep=1.5pt\fboxrule=2pt\mycard{K}{vardiamond}{red}}%
%
%create layered array of cards: 13x4x52=2704 OCGs!
\foreach \j in {0,...,3}{%
  \foreach \i in {0,...,12}{%
    \fboxrule=0pt\fboxsep=3.5pt%
    \makebox[\widthof{\xusebox{K-vardiamond}}][l]{%
      \foreach \suit/\jj in {spadesuit/0,clubsuit/1,varheart/2,vardiamond/3}{%
        \foreach \val/\ii in {%
          A/0,2/1,3/2,4/3,5/4,6/5,7/6,8/7,9/8,10/9,J/10,Q/11,K/12}{%
          \xdef\tablePos{\the\numexpr\j*13+\i\relax}%
          \xdef\stackPos{\the\numexpr\jj*13+\ii\relax}%
          \begin{ocg}{\tablePos-\stackPos}{\tablePos-\stackPos}{%
            \expandafter\ifnum\numexpr\tablePos-\stackPos\relax=0 on%
            \else off\fi%
          }%
            \makebox[0pt][l]{\xusebox{\val-\suit}}%
          \end{ocg}%
        }%
      }%
    }~%
  }\\%
}\\[1ex]
\mediabutton[
  jsaction={riffle();update();}
]{\fbox{\strut Riffle}}
\mediabutton[
  jsaction={
    var myIntA=app.setInterval(
      'riffle();update();if(riffleCount\%10==0||order[0]==51)
        app.clearInterval(myIntA);',100);
  }
]{\fbox{\strut Riffle$\times$10}}
\mediabutton[
  jsaction={
    var myIntA=app.setInterval(
      'riffle();update();if(order[0]==51) app.clearInterval(myIntA);',100);
  }
]{\fbox{\strut Auto Riffle}}
\mediabutton[
  jsaction={reset();}
]{\fbox{\strut Reset}}

\end{document}

verwandte Informationen