Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is my d3 data outputting after body?

This is a simple page that demonstrates some basic functionality of d3. I made a dataset var dataset = [3,1,4,1,5]; and would like to output it as well as some paragraphs. The data is appearing, but after the body! Strange ...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title> demo project</title>
    <script type="text/javascript" src="d3/d3.v2.js"></script>
</head>
<body>

    <script type="text/javascript">
        d3.select("body").append("p").text("hello!");
        d3.select("p").append("text").text(" hello!!");
        d3.select("body").append("p").text("hello2!");
        d3.select("p:nth-child(3)").append("text").text(" hello2!!");
        var dataset = [3,1,4,1,5];
        d3.select("p:nth-child(3n+1)")
            .data(dataset)
            .enter()
            .append("p")
            .text(function(d) { return d; });
        d3.select("p:nth-child(7n + 1)").append("text").text("hello againss?");
    </script>

</body>
</html>

the page looks like this:

enter image description here

and the DOM looks like this (note the data shows up after the body close tag):

enter image description here

Also note that the line d3.select("p:nth-child(7n + 1)").append("text").text("hello againss?"); was intended to be printed after all my data, but it does not show up.

like image 416
user391339 Avatar asked Dec 10 '12 04:12

user391339


1 Answers

The short answer is that in your particular case the enter() selection's parentNode is the document (and not the body).

Let's take a simple example to see what an enter() selection looks like. Assuming we have a document with a body without any p elements.

var ps = d3.select("body").selectAll("p")
    .data([0, 1, 2]);

Since no p elements existed yet, the enter() selection will have three elements. Let's inspect the enter selection:

ps.enter()

You see that the inner array has a property named parentNode. When you add new elements using selection.append() or selection.insert() the new elements will be created as children of that parentNode.

So, inspecting ps.enter()[0].parentNode will reveal the body element. It now becomes clear that, in a data join, the selection before the selectAll specifies the parentNode; in the above case that was d3.select("body").

What if we had omitted the select("body") part in the data join?

// example of bad data join
var ps2 = d3.selectAll("p")
    .data([0, 1, 2]);

It turns out that in this case ps2.enter()[0].parentNode is the #document! That means that if you add elements using this enter() selection, they will become the document's direct children. The append method will add them to the end of the document; i.e. after the body.

The last case is basically what you've encountered. Your data join and enter expression is not correct; it should follow this pattern:

d3.select(parent).selectAll(element)
    .data(data)
  .enter().append(element);

BTW, there is no HTML text element. So, append("text") doesn't seem meaningful.

like image 89
nautat Avatar answered Sep 20 '22 18:09

nautat