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:
IndexedLineScene
appears to be added to the scene correctly; it just doesn't appear in the image.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: