Post

Accessing the External Browser

Overview

X_ITE is designed to provide access to the internal X3D browser and its contained scene graph via JavaScript, either within an internal X3D Script node or an external HTML script.

If you want combine DOM access with X3D access in your JavaScript functions then you probably want to access the external browser object if you want include an external JavaScript file in your HTML page and you don’t want to do it directly in a Script node.

Usage

This script initializes an X3D canvas within an HTML page, configuring it to contain a scene, a camera and a geometric cube with default material properties. It then animates the rotation of the cube within the scene, ensuring that the camera captures the dynamic action.

Declarative Syntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script defer src="https://cdn.jsdelivr.net/npm/x_ite@10.5.12/dist/x_ite.min.js"></script>
<x3d-canvas>
  <X3D profile='Interchange' version='4.0'>
    <head>
      <unit category='angle' name='degree' conversionFactor='0.017453292519943295'></unit>
    </head>
    <Scene>
      <Viewpoint
          description='Initial View'
          position='2.869677 3.854335 8.769781'
          orientation='-0.7765887 0.6177187 0.1238285 28.9476440862198'></Viewpoint>
      <Transform DEF='Box'
          rotation='0 1 0 0'>
        <Shape>
          <Appearance>
            <Material></Material>
          </Appearance>
          <Box></Box>
        </Shape>
      </Transform>
      <TimeSensor DEF='Timer'
          cycleInterval='10'
          loop='true'></TimeSensor>
      <OrientationInterpolator DEF='Rotor'
          key='0, 0.25, 0.5, 0.75, 1'
          keyValue='0 1 0 0, 0 1 0 90, 0 1 0 180, 0 1 0 270, 0 1 0 0'></OrientationInterpolator>
      <ROUTE fromNode='Timer' fromField='fraction_changed' toNode='Rotor' toField='set_fraction'></ROUTE>
      <ROUTE fromNode='Rotor' fromField='value_changed' toNode='Box' toField='set_rotation'></ROUTE>
    </Scene>
  </X3D>
</x3d-canvas>

Pure JavaScript

The same scene can also be created using pure JavaScript.

Outside of a Script node context, you can access all objects through the X3D object, which can then be used as a namespace, eg. new X3D .MFString ("foo").

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<script type="module">
import X3D from "https://cdn.jsdelivr.net/npm/x_ite@10.5.12/dist/x_ite.min.mjs";

const
   browser = X3D .getBrowser (),
   scene   = browser .currentScene;

scene .setProfile (browser .getProfile ("Interchange"));
scene .addComponent (browser .getComponent ("Interpolation", 1));

await browser .loadComponents (scene);

// Viewpoint

const viewpointNode = scene .createNode ("Viewpoint");

viewpointNode .set_bind    = true;
viewpointNode .description = "Initial View";
viewpointNode .position    = new X3D .SFVec3f (2.869677, 3.854335, 8.769781);
viewpointNode .orientation = new X3D .SFRotation (-0.7765887, 0.6177187, 0.1238285, 0.5052317);

scene .rootNodes .push (viewpointNode);

// Box

const
   transformNode  = scene .createNode ("Transform"),
   shapeNode      = scene .createNode ("Shape"),
   appearanceNode = scene .createNode ("Appearance"),
   materialNode   = scene .createNode ("Material"),
   boxNode        = scene .createNode ("Box");

appearanceNode .material = materialNode;

shapeNode .appearance = appearanceNode;
shapeNode .geometry   = boxNode;

transformNode .children .push (shapeNode);

scene .rootNodes .push (transformNode);

// Give the node a name if you like.
scene .addNamedNode ("Box", transformNode);

// Animation

const
   timeSensorNode   = scene .createNode ("TimeSensor"),
   interpolatorNode = scene .createNode ("OrientationInterpolator");

timeSensorNode .cycleInterval = 10;
timeSensorNode .loop          = true;

for (let i = 0; i < 5; ++ i)
{
  interpolatorNode .key [i]      = i / 4;
  interpolatorNode .keyValue [i] = new X3D .SFRotation (0, 1, 0, Math .PI * i / 2);
}

scene .rootNodes .push (timeSensorNode, interpolatorNode);

// Routes

scene .addRoute (timeSensorNode,   "fraction_changed", interpolatorNode, "set_fraction");
scene .addRoute (interpolatorNode, "value_changed",    transformNode,    "set_rotation");
</script>
<!-- x3d-canvas element comes here: -->
<x3d-canvas></x3d-canvas>

Example

And here you can see the result:

X3D Object

Functions

X3D noConflict ()

In X_ITE’s case, the X3D function object is the main entry function. If you need to use another JavaScript library alongside X_ITE, return control of the X3D function object back to the other library with a call to X3D .noConflict (). Old references of X3D function object are saved during X_ITE initialization; X3D .noConflict () simply restores them. The return value is the X3D function object itself.

If for some reason two versions of X_ITE are loaded (which is not recommended), calling X3D .noConflict () from the second version will return the globally scoped X3D object to those of the first version.

1
2
3
4
5
6
<script src="other_lib.js"></script>
<script src="x_ite.js"></script>
<script>
const X_ITE_X3D = X3D .noConflict ();
// Code that uses other library's X3D can follow here.
</script>

The following services can be used to establish a session and obtain the X3DBrowser object.

X3DBrowser getBrowser ([selector : String])

The selector argument must be a string containing a valid CSS selector expression to match elements against. If no selector was given, »x3d-canvas« is used as selector string. The return value is the appropriate X3DBrowser object.

1
2
// Obtain X3DBrowser object of first x3d-canvas element.
const Browser = X3D .getBrowser ();

X3DBrowser getBrowser (element : Object)

Given a DOM element that represents a x3d-canvas element, the getBrowser function returns the appropriate X3DBrowser object.

1
2
3
4
5
6
7
8
9
// Query all x3d-canvas elements within the HTML page.
const canvases = document .querySelectorAll ("x3d-canvas");

for (const canvas of canvases)
{
  // Obtain X3DBrowser object of element i.
  const Browser = X3D .getBrowser (canvas);
  ...
}

Object createBrowser ()

Creates a new x3d-canvas DOM element, initializes it and returns it. Throws an exception if the browser object cannot be created.

1
2
3
4
5
6
7
8
9
function addBrowser (parent)
{
   // Create a new x3d-canvas element.
   const canvas = X3D .createBrowser ();

   canvas .setAttribute ("src", "/my/world.x3d");

   parent .appendChild (canvas);
}

Objects

The X3D object has several properties, you can use any of the properties below.

X3DConstants

The X3DConstants object defines values that can be useful for scripting. See also Constants Services.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function foo (node)
{
  // Get node type array.

  const types = node .getNodeType () .reverse ();

  // Iterate over node type array in reverse order with
  // concrete node types as first and abstract node
  // types as last index.

  for (const type of types)
  {
    switch (type)
    {
      case X3D .X3DConstants .Transform:
        // node is of type Transform.
        ...
        break;
      case X3D .X3DConstants .X3DLightNode:
        //  node is at least of type X3DLightNode.
        ...
        break;
    }
  }
}

X3DFields

All X3DFields (SFColor, …, MFBool, MFColor, and so on). The fields can be created using the object as constructor. See also Field Services and Objects.

Note: Scalar objects like SFBool, SFDouble, SFFloat, SFInt32, SFString, and SFTime have no constructor, just use the built-in JavaScript types Boolean, Number, and String.

1
2
3
4
5
6
// Create a new translation vector and
// determine the length of this vector.

const
  translation = new X3D .SFVec3f (4, 2, 0),
  length      = translation .length ();

Function Reference

A complete function reference for the X3DBrowser object and all other X3D JavaScript objects can be found in ECMAScript Object and Function Definitions.

Example

Adding HTML controls to your scene is no rocket science. We have added some HTML buttons below the x3d-canvas, which on click call a callback function.

The JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<script defer src="https://code.jquery.com/jquery-latest.js"></script>
<script type="module">
import X3D from "https://cdn.jsdelivr.net/npm/x_ite@10.5.12/dist/x_ite.min.mjs";

const Browser = X3D .getBrowser (".browser");

Browser .addBrowserCallback ("init", X3D .X3DConstants .INITIALIZED_EVENT, init);

function init ()
{
  const
    scene = Browser .currentScene,                      // Get the scene.
    timer = scene .getNamedNode ("SpinAnimationTimer"); // Get box TouchSensor node.

  $("#center")            .on ("click",  center);
  $("#change-style")      .on ("change", changeStyle);
  $("#change-background") .on ("change", changeBackground);
  $("#spin")              .on ("click",  spin);

  // Add a field callback to be notified when cycleTime is fired. "time" is an arbitrary
  // string to identify the callback, for example if you want to remove the callback later.
  timer .getField ("cycleTime") .addFieldCallback ("time", value =>
  {
    console .log ("cycleTime: " + value);
  });

  changeStyle ();
  changeBackground ();
};

function center ()
{
  Browser .changeViewpoint ("Viewpoint");
}

function changeStyle ()
{
  const
    scene      = Browser .currentScene,                   // Get the scene.
    switchNode = scene .getNamedNode ("Adrenaline");      // Get Switch node.

  // Change styles.

  switchNode .whichChoice = parseInt ($("#change-style") .val ());
}

function changeBackground ()
{
  const
    scene          = Browser .currentScene,              // Get the scene.
    backgroundNode = scene .getNamedNode ("Background"); // Get Background node.

  switch (parseInt ($("#change-background") .val ()))
  {
    case 0:
      backgroundNode .skyColor [0] = new X3D .SFColor (1, 1, 1);
      break;
    case 1:
      backgroundNode .skyColor [0] = new X3D .SFColor (0, 0, 0);
      break;
  }
}

function spin ()
{
  const
    scene = Browser .currentScene,                      // Get the scene.
    timer = scene .getNamedNode ("SpinAnimationTimer"); // Get TimeSensor node.

  if (timer .isPaused)
    timer .resumeTime = Date .now () / 1000;
  else
    timer .pauseTime = Date .now () / 1000;
}
</script>

The HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<x3d-canvas src="external-browser.x3d"></x3d-canvas>

<div class="buttons">
  <button id="center" class="button">Center</button>
  <select id="change-style" class="button">
    <option value="0">Balls</option>
    <option value="1">Sticks And Balls</option>
    <option value="2">Sticks</option>
    <option value="3">Line</option>
  </select>
  <select id="change-background" class="button">
    <option value="0">White Background</option>
    <option value="1">Black Background</option>
  </select>
  <button id="spin" class="button">Spin</button>
</div>

The init function is called when the scene is loaded and installs a field callback that is called when the models are clicked. The various callback functions first obtains the different nodes and then alter a field of the nodes.

The HTML and X3D

The scene defines different named nodes with the »DEF« attribute, which can be accessed later. Download adrenaline.html and adrenaline.x3d.

This post is licensed under CC BY 4.0 by the author.