score:47

Accepted answer

You'll notice in their examples that their javascript is below any of the html elements that is utilized so that part of the dom is loaded before it starts executing the javascript.

Simply putting your javascript at the bottom of the body is usually good enough.

score:2

You can put an onload event at body and put all d3js code in a function. For example:

<body onload="yourFunctionName()">

And in your javascript, insert this:

function yourFunctionName() {
    //Your d3js code goes here
}

Just paste the full d3 example code inside this function. The onload event will happen after the DOM is ready.

score:4

The answer marked as correct didn't work for me, and is actually wrong. It's some kind of a hack and should not be considered as a correct answer. Same way you could just execute your code inside setTimeout(function() { .. }, 1000). It is even more reliable as you can set the delay :-/

In my case I needed to wait for all elements to be processed in order to know their actual dimensions. When they are not built, processed and done, the numbers were not correct.

UPDATED. Here is the correct answer:

Most probably you get your data for building DOM using some async call like d3.json() and that's why it takes some time. As async call is non-blocking, then your subsequent code gets invoked even before the async call finishes, causing problems, and this is the reason why you posted this question.

So you are trying to solve this by looking for something in D3 or anywhere else, that would tell you that D3 async call is finished and now you can do your next thing. Some people suggest making sync ajax call. This is awfully WRONG. Async calls are created to be async.

What you actually need to do is to change your paradigm. Just pass a callback to that async call and that's it! Something like that:

function thingsToDoWhenDOMisBuilt() {
    ...
}

function buildDOM(rootNode, error, thingsToDoWhenDOMisBuilt) {
    ...
    // everything is built, so we can do our post-build thing against DOM
    if (thingsToDoWhenDOMisBuilt)
        thingsToDoWhenDOMisBuilt()
}

d3.json(urlToData, buildDOM) {
    if (error)
        console.log("oops")
    buildDOM(rootNode, thingsToDoWhenDOMisBuilt)
}

Also, take a look at async.js

Binding events as suggested above is also a horrible idea. You should use .enter() .exit() instead. D3 is Data driven, if you need event-driven flow, then just use jQuery or vanilla JS!

score:5

Sometimes you can't rely on the DIV / HTML element placing, for instance when you need to insert the element manipulated with D3 dynamically into the document. In such situations one solution is to monitor the document for DOMNodeInserted events and insert the D3 code in a callback (I believe this rules out IE versions prior to 9 though). Here's an example with jQuery:

$(document).bind('DOMNodeInserted', function(event)
{
    if (event.target.id == "viz")
    {
        var sampleSVG = d3.select("#viz")
                 .append("svg:svg")
                 .attr("width", 100)
                 .attr("height", 100);    

        sampleSVG.append("svg:circle")
                 .style("stroke", "gray")
                 .style("fill", "white")
                 .attr("r", 40)
                 .attr("cx", 50)
                 .attr("cy", 50)
                 .on("mouseover", function() {
                      d3.select(this).style("fill", "aliceblue");
                 })
                 .on("mouseout", function() {
                      d3.select(this).style("fill", "white");}
                 );
    }
});

Related Query