AJAX3D Tutorial 2:
Listening for SAI Events.

This tutorial illustrates connecting the HTML DOM to listen for node events coming from an X3D SAI, a capability that is fundamental for building dynamic applications which respond to user input.

Launch Listening for SAI Events

The 3D Text elements Ajax (X3D sensor 1) and X3D (X3D sensor 2) appear.
Clicking either geometry causes the scene to change and the click to be reported by the HTML text.

Setup: Embed X3D content in the page.
The X3D content is embedded in the html document using the technique shown in Tutorial 1.. In this case the X3D browser is starting with no scene loaded because we will load the replacement scene dynamically using DOM and SAI.

Step 1: Create a browser listener object.
In the file AJAX3D2b.js, we have defined a function initAjax3d() which is called by the DOM body onLoad event when the page is loaded. This function sets up a DOM listener as follows:

dom.js
  web3Dbrowser = document.objx3d.getBrowser();
  listener = new Object();
  listener.browserChanged = web3DbrowserChanged;
  web3Dbrowser.addBrowserListener(listener);

The X3D browser listener is an object with a specially named callback function browserChanged() that is called by the DOM when interesting SAI events happen, such as when a new X3D file is loaded.

We want to know when the X3D file is completely loaded because only then can we be sure that we can get handles to nodes using the getNode() method of the SAI ExecutionContext object. If, for example, we tried to call context.getNode() in response to the DOM body onLoad event, the call might fail. Why? Because web browsers may operate asynchronously, i.e. they do not guarantee the order in which the X3D viewer component is loaded and the onLoad handler for the page is called. We get around this by loading an empty scene, setting up the browser listener, and then asking the browser to load the named file and produce a callback when the scene is loaded and running.

Note that with this code we are now introducing the beginnings of a general-purpose framework for building AjaX3D applications. At the moment this file is quite simple; it has just 3 functions defined to help the application connect to the X3D world. We will be building on this framework in following tutorials.

Step 2: Dynamically load a world file.
Now that we have set up a browser listener, we can ask the browser to load a specific file, and the application will be notified when the X3D scene is fully loaded:

dom.js
  web3Dbrowser.loadUrlS("AJAX3Dlogo.x3d");

This loads the file AJAX3Dlogo.x3d, which has a nicely modeled AjaX3D logo using real 3D extruded text geometry. The function browserChanged() will be called when the new scene is fully loaded:

dom.js
  function web3DbrowserChanged(evt)
  {
    if (evt == 0) // BROWSER_INITIALIZED
    {
    web3Dbrowsercontext = web3Dbrowser.getExecutionContext();
    setupListeners();
    }
  }

Which obtains the current SAI execution context object then calls code to set up the listeners for X3D SAI node events.

Step 3: Create field listener objects.
Our browserChanged() calls out to a helper function, setupListeners(), which is defined specifically for this application. The file AJAX3D2c.js contains the application-specific code to create the SAI node and field listeners which will alert the DOM when the user interacts with objects in the scene.

In this example, the fields being listened to are from X3D TouchSensor nodes: objects that respond when a piece of geometry is clicked.

.x3d
  <TouchSensor DEF='TouchSensor1' />
  <TouchSensor DEF='TouchSensor2' />

The code first tucks away a handle to each node this application is interested in: a TimeSensor node for starting/stopping time-based animations, and two Material nodes for controlling the color of the two groups of geometry that comprise the AjaX3D logo.

.x3d
  <TimeSensor DEF='Timer' ... />
  <Material DEF='AjaxTextMaterial'... diffuseColor='1 0 0'/>
  <Material DEF='X3DTextMaterial' ... diffuseColor='0 0 1'/>

dom.js
  // Get a handle to the nodes
  timeSensor = web3Dbrowsercontext.getNode("Timer");
  AjaxTextMaterial = web3Dbrowsercontext.getNode("AjaxTextMaterial");
  X3DTextMaterial = web3Dbrowsercontext.getNode("X3DTextMaterial");

dom.js
  // Set up the observers that detect clicks
  touchObserver1 = setListenerObserver
("TouchSensor1", "touchTime", sensor1Touched);
  touchObserver1 = setListenerObserver
("TouchSensor2", "touchTime", sensor2Touched);
  }

setupListeners() calls a helper function in our new framework, setListenerObserver() that creates a field listener object with a callback function.

dom.js
  function setListenerObserver(nodeName,fieldName,callback)
  {
    // obtain node and field
    node = web3Dbrowsercontext.getNode(nodeName);
    field = node.getField(fieldName);

    // Set up observer and specify callback funtion
    var observer = new Object;
    observer.readableFieldChanged = callback;
    observer.field = field;
    field.addFieldEventListener(observer);
    return observer;
  }

The DOM is notified and the callback function executes when the value of the specified X3D node’s field changes.

Step 4: Respond to the events.
Once the field listeners are set up, we can now respond to clicks on the geometry.

dom.js
  function sensor1Touched(f, t)
  {
    AjaxTextMaterial.diffuseColor.g = .5;
    X3DTextMaterial.diffuseColor.r = .5;
    X3DTextMaterial.diffuseColor.g = .5;
    document.getElementById('statusArea').innerHTML =
"Sensor 1 clicked.";
  }

Click on the “Ajax” geometry and you will see two actions: i) the color of both the "Ajax" and the "X3D" geometries will change, and ii) the contents of the containing web page will be updated with a text message "Ajax Sensor clicked". The X3D behavior happens using internal SAI to sense the pointer action, send the event to the DOM which sends new colors to the SAI and then presents the new message in the status area.

The HTML behavior actually illustrates a typical DOM programming trick employed in AJAX: changing the innerHTML property of a DOM element of the web page to provide additional user feedback without reloading the document.

dom.js
  function sensor2Touched(f, t)
  {
    timeSensor.startTime = t;
    document.getElementById('statusArea').innerHTML =
"Sensor 2 clicked.";
  }

Click on the “X3D” geometry and three things happen: i) the color of the geometry changes; ii) the logo starts spinning by setting the start time of the animation, and iii) once again, the html message is updated.

Actions i) and ii) result from animation coding in the X3D scene. From the X3D scene point of view, the DOM does "External" scripting of the scene while the SAI does "Internal" scripting of the scene. We have the host "live" DOM document object connected to the embedded "live" web3D X3D browser SAI execution context object and can easily pass events to produce a highly interactive result.

Next we add the XMLHttpRequest object to the DOM using Ajax and Ajax3D tech to achieve SAI<=>DOM<=>XMLHttpRequest happiness.

Refresh/Reload Example page to restart.

Next step Tut3 - Connect SAI events to DOM and XMLHttpRequest

This AjaX3D tutorial start

AJAX3D.org Tutorials

Original Author: Tony Parisi  tparisi@mediamachines.com
last updated: October 12, 2006
This version by: Joe D Williams  joedw@hypermultimedia.com
last updated: April 42, 2007