d3v4更新创建重复元素

时间:2018-01-18 19:10:28

标签: d3.js

我已将大部分d3代码重写为v4,但新的更新模式让我失望。以下示例用于力图。每次更新时,在第一个容器中创建一个重复的圆圈。我的示例中的数据实际上并没有改变,但它无关紧要。如果我使用新数据,则会出现相同的问题(重复的圆圈)。

var w = 800,
    h = 500;

var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h);

var dataset = {};

function setData() {
    dataset.nodes = [{
        value: 200
    }, {
        value: 100
    }, {
        value: 50
    }];
}
setData();

var rScale = d3.scaleSqrt()
    .range([0, 100])
    .domain([0, d3.max(dataset.nodes.map(function(d) {
        return d.value;
    }))]);

var node = svg.append("g")
    .attr("class", "nodes")
    .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")")
    .selectAll(".node");

var simulation = d3.forceSimulation(dataset.nodes)
    .force("charge", d3.forceManyBody().strength(-1600))
    .force("x", d3.forceX())
    .force("y", d3.forceY())
    .alphaDecay(.05)
    .on("tick", ticked);

function ticked() {
    node.selectAll("circle")
        .attr("cx", function(d) {
            return d.x;
        })
        .attr("cy", function(d) {
            return d.y;
        });
}

function restart() {
    // Apply the general update pattern to the nodes.
    node = node.data(dataset.nodes, function(d) {
        return d.id;
    });
    node.exit().remove();
    node = node.enter().append("g")
        .attr("class", "node")
        .merge(node);
    node.append("circle")
        .attr("r", function(d) {
            return rScale(d.value);
        });

    // Update and restart the simulation.
    simulation.nodes(dataset.nodes);
    simulation.alpha(1).restart();
}
restart();

function update() {
    setData();
    restart();
}

d3.select("#update").on("click", update);

如果单击此编码板中的“更新”按钮(https://codepen.io/cplindem/pen/wpQbQe),则会在模拟重新开始时看到所有三个圆圈都有效,但在最大的圆圈后面,还有另一个相同的圆圈,它没有动画效果。如果您检查它,您还可以看到新的圆圈出现在html中。 我做错了什么?

1 个答案:

答案 0 :(得分:1)

您的第一个问题似乎是您在'id'字段上输入数据,但您的数据没有任何ID,因此需要更改或者您只是不断添加新组:

function setData() {
    dataset.nodes = [{
        value: 200,
      id: "A"
    }, {
        value: 100,
      id: "B"
    }, {
        value: 50,
      id: "C"
    }];
    console.log("dataset", dataset);
}

第二个问题是你合并新的和更新的选择,然后将新的圈子添加到所有选择,甚至是现有的圈子(因此在按下更新时每组有多个圈子)。我通过这样做得到了它:创建新节点,与现有选择合并,只为新节点添加圆圈,更新所有节点中的圆圈:

   node.exit().remove();
   var newNodes = node.enter().append("g");
   node = newNodes
        .attr("class", "node")
        .merge(node);

   newNodes.append("circle");

   node.select("circle")
        .attr("r", function(d) {
            return rScale(d.value);
        });

第二位是否是最优的我不知道,我自己仍然更加坚持v3 ...

https://codepen.io/anon/pen/WdLexR