# media9: toggle elements of a 3D scene

I successfully created a 3D PRC file and have embedded it in a PDF using LaTeX and the media9 package. Now I need to create buttons to allow the user to toggle on/off some elements of the scene. From the media9 manual I guess I can do that using the \mediabutton and jsaction. But I am ignorant of Javascript commands and could not figure how to use the jsaction. Hope someone can give me an example of media button command to toggle one or several elements of the 3D scene?

## 1 Answer

This requires some JavaScript.

Below example uses the PRC file epix.prc from the media9 package. The initialization script init3D.js defines the method

toggleNodeByID(<id>)


that recursively toggles the visibility of all children belonging to the node identified by its <id> (an integer number).

In order to determine a node <id>, an auxiliary script getID.js is provided. Click the part in question in the "Model Tree" navigation pane of A-Reader. The ID is then printed into the console. After finalizing the document, the line

add3Djscript=getID.js,


can be removed.

\documentclass{article}

\usepackage{media9}
\usepackage{filecontents}

%%%%%%% 3D initialisation script %%%%%%%%%%%%%%%%%%%
% Defines method toggleNodeByID(<ID>) for toggling %
% node visibility.                                 %
% <ID> to be determined by using the auxiliary     %
% script getID.js' listed below.                  %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{filecontents*}{init3D.js}
toggleNodeByID = function (i) {
if(scene.nodes.getByIndex(i).firstChild)
toggleSubNode(scene.nodes.getByIndex(i).firstChild);
else
scene.nodes.getByIndex(i).visible=!scene.nodes.getByIndex(i).visible;
return;
}
toggleSubNode = function (nd) {
if(nd.nextSibling) toggleSubNode(nd.nextSibling);
if(nd.firstChild) toggleSubNode(nd.firstChild);
else nd.visible=!nd.visible;
}
\end{filecontents*}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%% 3D-JS for getting node ID %%%%%%%%%%%%%%%%%%
% Only needed during document authoring.           %
% In the Model Tree, click the part to get its ID. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{filecontents*}{getID.js}
selEventHandler=new SelectionEventHandler();
selEventHandler.onEvent=function(e){
if(e.selected){
for(var i=0; i<scene.nodes.count; i++) {
if (scene.nodes.getByIndex(i)==e.node) {
host.console.show();
host.console.println("Node ID: "+i);
}
}
}
}
runtime.addEventHandler(selEventHandler);
\end{filecontents*}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\includemedia[
label=example3D,
width=0.8\linewidth,
add3Djscript=init3D.js,
add3Djscript=getID.js, %remove this after finalizing the document
add3Djscript=asylabels.js,  %upright text labels
activate=pageopen,
3Dmenu,
3Dc2c=4 2 3,
3Dcoo=4.4 2.2 0,
3Droo=430,
width=0.6\linewidth, height=0.6\linewidth
]{}{epix.prc}

\mediabutton[
jsaction=example3D:{
annotRM['example3D'].context3D.toggleNodeByID(2);
}
]{\fbox{\strut surface}}

\mediabutton[
jsaction=example3D:{
annotRM['example3D'].context3D.toggleNodeByID(71);
annotRM['example3D'].context3D.toggleNodeByID(105);
}
]{\fbox{\strut x axis}}

\mediabutton[
jsaction=example3D:{
annotRM['example3D'].context3D.toggleNodeByID(3);
annotRM['example3D'].context3D.toggleNodeByID(37);
}
]{\fbox{\strut y axis}}

\mediabutton[
jsaction=example3D:{
annotRM['example3D'].context3D.toggleNodeByID(143);
annotRM['example3D'].context3D.toggleNodeByID(177);
}
]{\fbox{\strut z axis}}

\mediabutton[
jsaction=example3D:{
annotRM['example3D'].context3D.toggleNodeByID(215);
}
]{\fbox{\strut function label}}
\end{document}

• Terrific, this is exactly what I need! Now I have a small problem to implement this solution: the <name> from the "Model Tree" are duplicated... Could I use the UTF16NAME instead? If so, what would be the syntax? – Herve Bouy Jun 10 '15 at 15:51
• I realise my question is silly: UTF16NAME are just a translation of the <name> to hex... Is there a solution to my problem? If several elements have the same name, how can I select one of them? – Herve Bouy Jun 10 '15 at 16:00
• @Herve I rewrote the script, to toggle part visibility by Node ID. This is more robust than identifying the Node by regular expression. To determine the Node ID, use the auxiliary script getID.js`. – AlexG Jun 11 '15 at 7:29
• Fantastic! Now it works! That solves my problem, thank you so much AlexG! – Herve Bouy Jun 11 '15 at 8:12