Javascript 在 Latex 的應用

Javascript 在 Latex 的應用

我想知道是否可以將使用 Javascript 建立的互動式應用程式新增至 Latex 文件中。

我想加入一些出現的Javascript這裡

就像那個:

在此輸入影像描述

編輯

我可以擁有 .js 文檔,所以我想知道如何將 .js 附加到 Latex。

任何想法?有什麼幫助嗎?

答案1

ocgx2這使用 PDF Layers(套件)和 JavaScript將洗牌範例移植到 LaTeX 和 PDF 。需要 Acrobat Reader 才能顯示。

更新:帶有圖表的擴展範例,繪製了王鑽位置與淺槽數量的關係。

警告:pdflatex由於創建的 OCG 數量較多(約 21k),兩次編譯程式碼大約需要 2h 。而且,為了pdflatex成功運行,main_memory必須增加格式,或lualatex使用它來代替。沒有圖表的(原始)範例編譯速度要快得多(第二個程式碼框)。

在此輸入影像描述

\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}

沒有圖表的原始範例:

在此輸入影像描述

\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}

相關內容