如何使用D3 v4的更新模式更新嵌套的子节点

时间:2017-04-13 00:25:14

标签: d3.js

使用D3 v4更新模式时,我无法让某些后代更新其数据。

将数据连接中的更改传播给子级的正确方法是什么?

这是一个例子 https://bl.ocks.org/yanofsky/5b30b12582b6b66bc262b165806a6dc5

单击按钮时,只会更改文本,而不会更改文本和颜色。

1 个答案:

答案 0 :(得分:2)

您应该遵循为添加的每个元素添加数据的模式。通过这种方式,您始终可以选择updateenterexit。删除exit并为enter添加新元素后,您可以合并updateenter并更新属性:

Here is the updated block

  //define some data
var data = [
        {"location": 1, "month": "Jan", "year": 2017, "value": "#ccc"},
        {"location": 2, "month": "Jan", "year": 2017, "value": "#999"},
        {"location": 3, "month": "Jan", "year": 2017, "value": "#666"},
        {"location": 4, "month": "Jan", "year": 2017, "value": "#333"},
        {"location": 1, "month": "Jan", "year": 2018, "value": "#fcc"},
        {"location": 2, "month": "Jan", "year": 2018, "value": "#f99"},
        {"location": 3, "month": "Jan", "year": 2018, "value": "#f66"},
    {"location": 4, "month": "Jan", "year": 2018, "value": "#f33"},
        {"location": 1, "month": "Feb", "year": 2017, "value": "#cfc"},
        {"location": 2, "month": "Feb", "year": 2017, "value": "#9f9"},
        {"location": 3, "month": "Feb", "year": 2017, "value": "#6f6"},
        {"location": 4, "month": "Feb", "year": 2017, "value": "#3f3"},
        {"location": 1, "month": "Feb", "year": 2018, "value": "#ccf"},
        {"location": 2, "month": "Feb", "year": 2018, "value": "#99f"},
        {"location": 3, "month": "Feb", "year": 2018, "value": "#66f"},
        {"location": 4, "month": "Feb", "year": 2018, "value": "#33f"},
    {"location": 5, "month": "Feb", "year": 2018, "value": "#0505ff"},
    ]

 // nest the data by month then year
 var by_month = d3.nest()
        .key(function(d){return d.month})
        .key(function(d){return d.year})
        .entries(data)


function render(ident, key_month) {

    var w = 500
    var h = 100

    var container = d3.select(ident)

  // select and add a container div for each year in the data
  // using only the data for the target month
    var year = container
        .selectAll("div.year")

  var data = by_month.filter(function(d){return d.key == key_month})[0].values;
    var yearAll= year.data(data);


  yearAll.exit().remove();


  var yearEnter= yearAll
        .enter()
    .append("div")
    .classed("year",true);

  //Add h2 and svg
  yearEnter.append("h2");
  yearEnter.append("svg")
                    .append("g")
                    .classed("gwrapper",true);

  yearEnter = yearEnter.merge(yearAll);

  yearEnter.select("h2")
    .text(function(d) {return  d.values[0].month + " " + d.values[0].year ;});

  // update the svg dimensions
  yearEnter.select("svg")
    .attr("width", w)
        .attr("height", h);


  // select and add element g location
    var gloc = yearEnter.select(".gwrapper").selectAll("g")
                                             .data(function(d){return d.values;});

  gloc.exit().remove();


  var glocEnter = gloc.enter()
                                        .append("g")
                       .classed("loc",true);

  glocEnter.append("rect");
           ;

  glocEnter = glocEnter.merge(gloc);


  // merge and position element wrappers
  glocEnter
        .attr("transform", function(d,i){return "translate("+[w/5*i]+")"});

  var t = d3.transition().duration(1000);

  glocEnter.select("rect")
            .attr("x", (w/5 - 5)/2)
                                .attr("y", (w/5 - 5)/2)
                                .attr("width", 0)
                                    .attr("height", 0)
                                .attr("fill", "black")
                                .transition(t)
                                .attr("x", 5)
                                .attr("y", 0)
                                    .attr("width", w/5 - 5)
                                    .attr("height", w/5 - 5)
                                .attr("fill", function(d){return d.value});

}

// on button click change the subset of data being used
d3.selectAll(".month").on("click", function(){
    render("#toggle",this.getAttribute("data-month"))
}) 


d3.selectAll("#clearb").on("click", function(){
   d3.selectAll("g.loc").remove();
}) 

render("#toggle","Jan")