Javascript で作成されたインタラクティブ アプリを Latex ドキュメントに追加できるかどうかを知りたいです。
表示されるJavascriptをいくつか追加したいと思いますここ。
例えばこんなの:
編集
.js ドキュメントは入手できるので、.js を Latex に添付する方法を知りたいです。
何かアイデアはありますか?何か助けていただけますか?
答え1
これは、PDF レイヤー (パッケージ ) と JavaScript を使用して、カード シャッフルの例を LaTeX と PDF に移植したものですocgx2
。表示するには Acrobat Reader が必要です。
アップデート: キング・ダイヤモンドの位置とリフル数をプロットしたチャートを含む拡張例。
警告:pdflatex
作成される OCG の数が多い (約 21k) ため、を 2 回使用してコードをコンパイルすると、約 2 時間かかります。さらに、pdflatex
を正常に実行するには、main_memory
の形式で を増やすか、 のlualatex
代わりに を使用する必要があります。チャートのない (元の) 例では、コンパイルがはるかに高速になります (2 番目のコード ボックス)。
\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}