我想知道是否可以将用 Javascript 创建的交互式应用程序添加到 Latex 文档中。
我想添加一些出现的 Javascript这里。
就像这个:
编辑
我可以拥有 .js 文档,所以我想知道如何将 .js 附加到 Latex。
有什么想法吗?有什么帮助吗?
答案1
这将卡片洗牌示例移植到 LaTeX 和 PDF,使用 PDF 图层(包ocgx2
)和 JavaScript。显示需要 Acrobat Reader。
更新:扩展示例,使用图表绘制国王钻石位置与浅滩数量的关系。
警告:pdflatex
由于创建的 OCG 数量很大(约 21k),因此使用编译代码两次大约需要 2 小时。此外,为了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}