admin管理员组

文章数量:1287858

I am populating a div with child divs containing the values from an array. On first pass, the array looks like this:

arr_subpop_unique = ["CPL", "NAP", "NPL", "SAP", "SPL", "TPL", "UMW", "WMT", "XER"]

My selection enter/update/exit looks like this:

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
        .data(arr_subpop_unique)

    sizemapHeader.enter().append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
        .html(function(d,i){ return d; });

    sizemapHeader.exit().remove();

This works fine, giving me a div for each element containing a string.

When I run the function again, my data array updates to this:

    arr_subpop_unique = ["MAN_MADE", "NATURAL"]

The update returns two divs, however, they contain "CPL" and "NAP" (index values 0 and 1). Can someone explain why this would not replace the first two indicies with "MAN_MADE" and "NATURAL"?

Thanks for the help...trying to get the hang of enter/update/exit data joins in D3!

I am populating a div with child divs containing the values from an array. On first pass, the array looks like this:

arr_subpop_unique = ["CPL", "NAP", "NPL", "SAP", "SPL", "TPL", "UMW", "WMT", "XER"]

My selection enter/update/exit looks like this:

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
        .data(arr_subpop_unique)

    sizemapHeader.enter().append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
        .html(function(d,i){ return d; });

    sizemapHeader.exit().remove();

This works fine, giving me a div for each element containing a string.

When I run the function again, my data array updates to this:

    arr_subpop_unique = ["MAN_MADE", "NATURAL"]

The update returns two divs, however, they contain "CPL" and "NAP" (index values 0 and 1). Can someone explain why this would not replace the first two indicies with "MAN_MADE" and "NATURAL"?

Thanks for the help...trying to get the hang of enter/update/exit data joins in D3!

Share Improve this question asked Mar 31, 2015 at 2:01 thefreelinethefreeline 6311 gold badge12 silver badges26 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

It's worth noting that the chaining is a little bit asymmetrical because enter() has the side-effect of merging into the update selection. This means, if you add features on to the update selection after the append(), they will also be added on the enter nodes. On the other hand, the update selection is not merged into the enter selection. So any features chained after enter() will only be on the enter selection.

In the case of the OP question, there are two update nodes and zero enter nodes. So the HTML is added on the non-existent enter nodes and the HTML of the two update nodes is not updated.

So, yes, this works...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//ENTER
sizemapHeader
.enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
//UPDATE
sizemapHeader
    .html(function (d, i) { return d; })

//EXIT
sizemapHeader
.exit()
    .remove();

But this doesn't...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//ENTER
//sizemapHeader
    .enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

//UPDATE
sizemapHeader
        .html(function (d, i) { return d; })

//EXIT
sizemapHeader
.exit()
    .remove();

And this breaks in the initial update (when the update selection is empty)...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//UPDATE
sizemapHeader
    .html(function (d, i) { return d; })

//ENTER
sizemapHeader
.enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

//EXIT
sizemapHeader
.exit()
    .remove();

When you trace your code, you will see that the value of sizemapHeader changes after .enter() is called on it.

The reason is buried in the wiki...

The enter selection merges into the update selection when you append or insert. Rather than applying the same operators to the enter and update selections separately, you can now apply them only once to the update selection after entering the nodes. If you find yourself removing an entire selection's elements only to reinsert most of them, do this instead. For example:

var update_sel = svg.selectAll("circle").data(data)
update_sel.attr(/* operate on old elements only */)
update_sel.enter().append("circle").attr(/* operate on new elements only */)
update_sel.attr(/* operate on old and new elements */)
update_sel.exit().remove() /* plete the enter-update-exit pattern */

Just providing a different take on the answer @Plato provided...

In certain situations you may want the changed data to be recognised as "new", ie. be part of the enter selection, rather than just part of the update. In your example, it is considered part of the update selection because your data is being bound to DOM elements based on index (this is the default). You can change this behaviour by passing a second argument to the data call.

See https://github./mbostock/d3/wiki/Selections#data for more information. It's referred to as the key argument.

Here is an example:

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
    .data(arr_subpop_unique, function(d, i) { return d; });

sizemapHeader.enter().append("div")
    .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
    .html(function(d,i){ return d; });

sizemapHeader.exit().remove();

The second argument to the data function call will now ensure that the data is bound to the DOM elements by value, rather than by their index in the array.

The next time you call your function with new data, any value that is not currently bound to a DOM element, will be considered new and part of the enter selection.

Both cases are useful, depending on what you're trying to achieve.

take a look at "General update pattern"
i think you aren't triggering d3's update selection

var sizemapHeader =
d3.select("#d3-sizemap-hr").selectAll("div")
  .data(arr_subpop_unique)

sizemapHeader
.enter()
  .append("div")
    .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

sizemapHeader
    .html(function(d,i){ return d; });

sizemapHeader
.exit()
  .remove();

本文标签: javascriptD3Correct number of elements on updatebut wrong valuesStack Overflow