javascriptx3dx3dom

Adding an IndexedLineSet in X3Dom


When working with X3D via X3Dom, sometimes I'd like to add objects dynamically. As an example, I might have a function like the following to add a line:

function add_line(lineString) {
    var lineString = lineString || random_line();
    var orbit = $("<shape></shape>");
    scene.append(orbit);
    var indexedLineSet = $("<IndexedLineSet></IndexedLineSet>");
    orbit.append(indexedLineSet).attr('coordIndex', '0 1');
    var coordinate = $("<coordinate></coordinate>");
    coordinate.attr('point', lineString);   
    indexedLineSet.append(coordinate)
}

In this code, scene is an existing X3D scene, random_line is a function that generates a string defining a random line, and I'm manipulating the scene with JQuery. When calling the function as the page loads, it works just fine. When calling the function in response to a button push, however, the line doesn't appear, though it is added to the scene.

Notes:


Solution

  • If you open up your developer console you can find:

    x3dom.js:3014 Uncaught TypeError: Cannot read property 'getPoints' of null_
    buildGeometry @ x3dom.js:3014
    nodeChanged @ x3dom.js:3046
    x3dom.NodeNameSpace.setupTree @ x3dom.js:2744
    onNodeInserted @ x3dom.js:1100
    (anonymous function) @ jquery-1.12.4.min.js:3
    Ha @ jquery-1.12.4.min.js:3
    append @ jquery-1.12.4.min.js:3
    add_line @ IndexedLineSet-Test.html:76
    (anonymous function) @ IndexedLineSet-Test.html:90
    dispatch @ jquery-1.12.4.min.js:3
    r.handle @ jquery-1.12.4.min.js:3
    

    After investigation line 76 of your original code, you will find that you have to change the order of adding the points and adding the indices:

    var indexedLineSet = $("<IndexedLineSet></IndexedLineSet>");
    var coordinate = $("<coordinate></coordinate>");
    coordinate.attr('point', lineString);   
    indexedLineSet.append(coordinate);
    orbit.append(indexedLineSet).attr('coordIndex', '0 1');
    

    It works well for you on the initial load, because you construct the x3d before X3DOM is ready, check when this call appears (after your calls to add_line have been finished):

    x3dom.runtime.ready = function() {
        console.log('ready');
    };
    

    This means that all the events and listeners are not setup yet. But later when you click that button X3DOM has been initialized completely. Thus it can listen to all events and fires the onNodeInserted event right after you append orbit to scene. Another solution would be to have this call right at the end of your function:

    1. Construct the 3D object completely
    2. Add the object (orbit) to the scene.