<html>
<head>
<title>X3DOM Rotations and Translations</title>
<script type=’text/javascript’ src=’https://www.x3dom.org/download/x3dom.js’> </script>
<link rel=’stylesheet’ type=’text/css’ href=’https://www.x3dom.org/download/x3dom.css’/>
<style>x3d{border:2px solid blue;}
</style>
The above section of code is typical html. Note that it references x3dom.js and x3dom.css. These files are essential and what link the DOM of html to x3d and its screen output. Below within script tags javascript functions are what bring animation to the x3d scene.
<script>
function startTimer(){
var nowTime = Date.now()/1000;
document.getElementById(“explodeTimer”).setAttribute(‘startTime’,nowTime);
document.getElementById(“contractTimer”).setAttribute(‘startTime’,nowTime + 45);
}
Function startTimer sets one timer in motion and delays the start of another. Function explode takes a changing input value from a timer controlled scalar interpolator and uses that changing value to repetitively call function moves which performs the translations of the cubelets. It also repetitively establishes a required rotation position and calls and gets form function getUQ the unit quaternion of that rotation position. It uses the changing unit quaternion to set the rotational position of the repetitively built scene.
function explode(event){
if(event.type != ‘outputchange’ || event.fieldName != ‘value_changed’)
return;
var v = event.value;
moves(v);
var rotnVal = ((v-1) * 1.25664)- 0.78539;
var reqdQ = getUQ(rotnVal);
document.getElementById(“Build”).setFieldValue(‘rotation’, reqdQ);
}
function getUQ(angleinrads){
ang = angleinrads;
yUq = Math.sin(ang/2);
angUq = Math.cos(ang/2);
q = new x3dom.fields.Quaternion(0.0, yUq, 0.0, angUq);
return q;
}
Function contract, like explode, takes a changing input value from another timer controlled scalar interpolator, using the changing value to repetitively call function moves and thereby contracting the cubelets but not rotating them.
function contract(event){
if(event.type != ‘outputchange’ || event.fieldName != ‘value_changed’)
return;
var v = event.value;
moves(v);
}
Function moves repetitively establishes as SFVec3f’s the required and changing translation positions of the cubelets . Those positions are then assigned to the cubelets by setting their translation attribute via their Dom id’s
function moves(trans){
var val = trans;
var newR = new x3dom.fields.SFVec3f(val, 0, 0);
var newU = new x3dom.fields.SFVec3f(0, val, 0);
var newF = new x3dom.fields.SFVec3f(0, 0, val);
var newL = new x3dom.fields.SFVec3f(-val, 0, 0);
var newD = new x3dom.fields.SFVec3f(0, -val, 0);
var newB = new x3dom.fields.SFVec3f(0, 0, -val);
var newFU = new x3dom.fields.SFVec3f(0, val, val);
var newFR = new x3dom.fields.SFVec3f(val, 0, val);
var newFL = new x3dom.fields.SFVec3f(-val, 0, val);
var newFD = new x3dom.fields.SFVec3f(0, -val, val);
var newBU = new x3dom.fields.SFVec3f(0, val, -val);
var newBR = new x3dom.fields.SFVec3f(val, 0, -val);
var newBL = new x3dom.fields.SFVec3f(-val, 0, -val);
var newBD = new x3dom.fields.SFVec3f(0, -val, -val);
var newLU = new x3dom.fields.SFVec3f(-val, val, 0);
var newLD = new x3dom.fields.SFVec3f(-val, -val, 0);
var newRU = new x3dom.fields.SFVec3f(val, val, 0);
var newRD = new x3dom.fields.SFVec3f(val, -val, 0);
var newFLU = new x3dom.fields.SFVec3f(-val, val, val);
var newFUR = new x3dom.fields.SFVec3f(val, val, val);
var newFDL = new x3dom.fields.SFVec3f(-val, -val, val);
var newFRD = new x3dom.fields.SFVec3f(val, -val, val);
var newBRU = new x3dom.fields.SFVec3f(val, val, -val);
var newBUL = new x3dom.fields.SFVec3f(-val, val, -val);
var newBDR = new x3dom.fields.SFVec3f(val, -val, -val);
var newBLD = new x3dom.fields.SFVec3f(-val, -val, -val);
document.getElementById(“BlockR”).setAttribute(‘translation’,newR.toString());
document.getElementById(“BlockU”).setAttribute(‘translation’,newU.toString());
document.getElementById(“BlockF”).setAttribute(‘translation’,newF.toString());
document.getElementById(“BlockL”).setAttribute(‘translation’,newL.toString());
document.getElementById(“BlockD”).setAttribute(‘translation’,newD.toString());
document.getElementById(“BlockB”).setAttribute(‘translation’,newB.toString());
document.getElementById(“BlockFU”).setAttribute(‘translation’,newFU.toString());
document.getElementById(“BlockFR”).setAttribute(‘translation’,newFR.toString());
document.getElementById(“BlockFL”).setAttribute(‘translation’,newFL.toString());
document.getElementById(“BlockFD”).setAttribute(‘translation’,newFD.toString());
document.getElementById(“BlockBU”).setAttribute(‘translation’,newBU.toString());
document.getElementById(“BlockBR”).setAttribute(‘translation’,newBR.toString());
document.getElementById(“BlockBL”).setAttribute(‘translation’,newBL.toString());
document.getElementById(“BlockBD”).setAttribute(‘translation’,newBD.toString());
document.getElementById(“BlockLU”).setAttribute(‘translation’,newLU.toString());
document.getElementById(“BlockLD”).setAttribute(‘translation’,newLD.toString());
document.getElementById(“BlockRU”).setAttribute(‘translation’,newRU.toString());
document.getElementById(“BlockRD”).setAttribute(‘translation’,newRD.toString());
document.getElementById(“BlockFLU”).setAttribute(‘translation’,newFLU.toString());
document.getElementById(“BlockFUR”).setAttribute(‘translation’,newFUR.toString());
document.getElementById(“BlockFDL”).setAttribute(‘translation’,newFDL.toString());
document.getElementById(“BlockFRD”).setAttribute(‘translation’,newFRD.toString());
document.getElementById(“BlockBRU”).setAttribute(‘translation’,newBRU.toString());
document.getElementById(“BlockBUL”).setAttribute(‘translation’,newBUL.toString());
document.getElementById(“BlockBDR”).setAttribute(‘translation’,newBDR.toString());
document.getElementById(“BlockBLD”).setAttribute(‘translation’,newBLD.toString());
}
</script>
</head>
The body of the html document has in addition to normal html tags, the x3d tags and the x3d content starting with a view point and angle followed by the cube build. Note that we have included an onclick = “startTimer” in the enclosing build transform that initiates the animation
<body>
<h3>Using X3DOM to Explode and Contract a Cube</h3>
<p>
Mouse click on the cube to start explosion
</p>
<x3d showLog=’false’ showStat=’false’ width=’650px’ height=’650px’>
<scene>
<Viewpoint DEF=”View1″ description=”Top View”
orientation=”1.0 0.0 0.0 -0.6107″ position=”0.0 7.28 10.4″></Viewpoint>
<Transform ID=”Build” DEF=”Build” onclick = “startTimer()” rotation=”0.0 1.0 0.0 -0.78539″ scale=”0.5 0.5 0.5″>
<Shape DEF=”BlackBox”>
<appearance>
<material DEF=”BoxColour” diffuseColor=”0.0 0.0 0.0″> </material>
</appearance>
<Box size=”0.99 0.99 0.99″></Box>
</Shape>
<Shape DEF=”RShape”>
<IndexedFaceSet coordIndex=” 0 1 2 3″>
<Coordinate point=” 0.499 -0.43 0.43 0.499 -0.43 -0.43 0.499 0.43 -0.43 0.499 0.43 0.43″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”1.0 0.0 0.0″> </material>
</Appearance>
</Shape>
<Shape DEF=”UShape”>
<IndexedFaceSet DEF=”FaceU” coordIndex=” 0 1 2 3″>
<Coordinate point=” 0.43 0.499 0.43 0.43 0.499 -0.43 -0.43 0.499 -0.43 -0.43 0.499 0.43″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”1.0 1.0 0.0″> </material>
</Appearance>
</Shape>
<Shape DEF=”DShape”>
<IndexedFaceSet DEF=”FaceD” coordIndex=” 0 1 2 3″>
<Coordinate point=” 0.43 -0.499 -0.43 0.43 -0.499 0.43 -0.43 -0.499 0.43 -0.43 -0.499 -0.43″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”0.8 0.9 1.0″> </material>
</Appearance>
</Shape>
<Shape DEF=”LShape”>
<IndexedFaceSet DEF=”FaceL” coordIndex=” 0 1 2 3″>
<Coordinate point=” -0.499 -0.43 0.43 -0.499 0.43 0.43 -0.499 0.43 -0.43 -0.499 -0.43 -0.43″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”0.5 0.16 0.16″> </material>
</Appearance>
</Shape>
<Shape DEF=”FShape”>
<IndexedFaceSet DEF=”FaceF” coordIndex=” 0 1 2 3″>
<Coordinate point=” -0.43 -0.43 0.499 0.43 -0.43 0.499 0.43 0.43 0.499 -0.43 0.43 0.499″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”0.1 0.0 1.0″> </material>
</Appearance>
</Shape>
<Shape DEF=”BShape”>
<IndexedFaceSet DEF=”FaceB” coordIndex=” 0 1 2 3″>
<Coordinate point=” 0.43 -0.43 -0.499 -0.43 -0.43 -0.499 -0.43 0.43 -0.499 0.43 0.43 -0.499″> </Coordinate>
</IndexedFaceSet>
<Appearance>
<material diffuseColor=”0.0 1.0 0.0″> </material>
</Appearance>
</Shape>
<Transform ID=”BlockR” DEF=”BlockR” translation=”1.0 0.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”RShape”></Shape>
</Transform>
<Transform ID=”BlockU” DEF=”BlockU” translation=”0.0 1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockF” DEF=”BlockF” translation=”0.0 0.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
</Transform>
<Transform ID=”BlockL” DEF=”BlockL” translation=”-1.0 0.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”LShape”></Shape>
</Transform>
<Transform ID=”BlockD” DEF=”BlockD” translation=”0.0 -1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockB” DEF=”BlockB” translation=”0.0 0.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
</Transform>
<Transform ID=”BlockFU” DEF=”BlockFU” translation=”0.0 1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockFR” DEF=”BlockFR” translation=”1.0 0.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”RShape”></Shape>
</Transform>
<Transform ID=”BlockFL” DEF=”BlockFL” translation=”-1.0 0.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”LShape”></Shape>
</Transform>
<Transform ID=”BlockFD” DEF=”BlockFD” translation=”0.0 -1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockBU” DEF=”BlockBU” translation=”0.0 1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockBR” DEF=”BlockBR” translation=”1.0 0.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”RShape”></Shape>
</Transform>
<Transform ID=”BlockBL” DEF=”BlockBL” translation=”-1.0 0.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”LShape”></Shape>
</Transform>
<Transform ID=”BlockBD” DEF=”BlockBD” translation=”0.0 -1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockLU” DEF=”BlockLU” translation=”-1.0 1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”LShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockLD” DEF=”BlockLD” translation=”-1.0 -1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”LShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockRU” DEF=”BlockRU” translation=”1.0 1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”RShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockRD” DEF=”BlockRD” translation=”1.0 -1.0 0.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”RShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockFLU” DEF=”BlockFLU” translation=”-1.0 1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”LShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockFUR” DEF=”BlockFUR” translation=”1.0 1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”UShape”></Shape>
<Shape USE=”RShape”></Shape>
</Transform>
<Transform ID=”BlockFDL” DEF=”BlockFDL” translation=”-1.0 -1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”DShape”></Shape>
<Shape USE=”LShape”></Shape>
</Transform>
<Transform ID=”BlockFRD” DEF=”BlockFRD” translation=”1.0 -1.0 1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”FShape”></Shape>
<Shape USE=”RShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
<Transform ID=”BlockBRU” DEF=”BlockBRU” translation=”1.0 1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”RShape”></Shape>
<Shape USE=”UShape”></Shape>
</Transform>
<Transform ID=”BlockBUL” DEF=”BlockBUL” translation=”-1.0 1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”UShape”></Shape>
<Shape USE=”LShape”></Shape>
</Transform>
<Transform ID=”BlockBDR” DEF=”BlockBDR” translation=”1.0 -1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”DShape”></Shape>
<Shape USE=”RShape”></Shape>
</Transform>
<Transform ID=”BlockBLD” DEF=”BlockBLD” translation=”-1.0 -1.0 -1.0″>
<Shape USE=”BlackBox”></Shape>
<Shape USE=”BShape”></Shape>
<Shape USE=”LShape”></Shape>
<Shape USE=”DShape”></Shape>
</Transform>
</Transform>
The x3d content continues with two TimeSensor nodes each linked via Route statements to scalar interpolators that output the changing explode and contract values previously referred to. Specifically note the onoutputchange entries that link the interpolator keyValue field to the javascript explode and contract functions.
<TimeSensor id=”explodeTimer” DEF=”explodeTimer” cycleInterval=”40.0″ loop=”false” enabled=”true” ></TimeSensor>
<ScalarInterpolator DEF=”moveCubelets” onoutputchange=’explode(event)’ key=”0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1″ keyValue=”1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0″></ScalarInterpolator>
<ROUTE fromNode=”explodeTimer” fromField=”fraction_changed” toNode=”moveCubelets” toField=”set_fraction”></ROUTE>
<TimeSensor id=”contractTimer” DEF=”contractTimer” cycleInterval=”20.0″ loop=”false” enabled=”true” ></TimeSensor>
<ScalarInterpolator DEF=”contractCubelets” onoutputchange=’contract(event)’ key=”0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1″ keyValue=”6.0 5.5 5.0 4.5 4.0 3.5 3.0 2.5 2.0 1.5 1.0″></ScalarInterpolator>
<ROUTE fromNode=”contractTimer” fromField=”fraction_changed” toNode=”contractCubelets” toField=”set_fraction”></ROUTE></scene>
</x3d>
</body>
</html>