I’ve been using d3 for quite some time but just created my first couple of real Observable notebooks. In particular, this one calls mathjs and x3dom as well as d3. When I load the page, sometimes the generated image appears and sometimes it doesn’t. My guess is that this has something to do with the various libraries loading asynchronously at different rates and not necessarily returning correctly, but I’m not sure how to fix it. Any help would be much appreciated.
For the record, the page should generate and image like the one shown here. Here’s a static version:
I must admit that I probably know the least about any of this out of all the users on this forum, but since your question’s been active for a couple of hours without a reply, please allow me to point out a pattern I’ve seen several places when these sorts of issues arise… await :
To pull a pattern from another thread (recognizing the modules being required differ from yours):
My understanding is (going out on a limb here) that you can work around the asynchronous loading by specifying a particular order for modules.
Also, you might check out the section on ‘stubborn add-ons’ here:
… If I were more adept at this, I’d try to help tailor it to your purposes, but I have a feeling you’ll sort it out on your own
@aaronkyle Thanks for the reply. Unfortunately, it doesn’t quite seem to help. I can see where using await would help in the case that you reference, since you’re basically loading one module that modifies the object returned by another but that’s not the case here.
There is good news, though:
Loading x3dom via the following command seems to help: x3dom = require('x3dom').catch(() => window['x3dom'])
More importantly, a web page using the embed code works reliably.
Nice example using x3dom with d3 which is a good combo.
I also typically use x3dom.reload() to make sure all changes to the DOM are picked up. The main API for x3dom is just DOM manipulation with any tool including plain DOM API or d3. x3dom then uses observers to react to mutations in the x3d element. However, x3dom follows the x3d specification which does not allow for dynamically changing all fields/attributes of all nodes, and so not all DOM mutations lead to perhaps expected changes in the scene. Therefore it is safest to just recreate the scene from scratch after a change by using x3dom.reload().
If there is interested, it might be useful to put together more reactive x3dom examples, for example one using variable evaluation within a html tagged template.
[ For the x3d content, you could use DEF/USE for the coordinate axes as in this fork: ]
Yes, that’s exactly why I favor x3dom for 3D graphics as compared to other libraries like three.js. Working with x3d feels a lot like working with SVG so the style of programming doesn’t change too much. There are some oddities like you mention.
I’m getting a “Sorry, we couldn’t find that page” error. Perhaps you tried to share a private file?
I agree that X3Dom doesn’t react as to changes as I’m accustomed to. Nonetheless, building from scratch can be very expensive so it’s worth avoiding it, if possible. I just published a new version that allows the user to select how many threads are displayed. I did try to create that by building from scratch but that was quite slow. Thus, instead, the published code creates all threads from the beginning and then sets the transparency of some of the threads as necessary.
There are also a few other enhancements, including your suggestion to use DEF/USE for the axes - thanks for that!
x3dom reacts to most changes in the x3d sub DOM, just not to all of them. I think that is a VRML legacy where 3d performance needed to be carefully managed.
It does make sense to keep DOM changes to a minimum, let alone recreate from scratch, when possible. This includes actually first building the x3d element detached from the page dom, and only appending it to the page document when it is fully constructed. That way there are no unnecessary updates or parsing.
Sofar you do not really use d3 data binding, so selectAll would not be that useful. Here is variant which uses standard DOM querySelectorAll to update the transparencies:
I am not sure if it is a worthwhile enhancement but perhaps educational. [Actually, the thread attribute in this fork should be named data-thread].