javascript - D3js 在 Enter() 上强制重复节点

标签 javascript d3.js

我在 d3js 方面遇到了一些问题,我不知道发生了什么。这个想法是从一些端点数据(第一个图像)绘制初始图,这很好用。每个节点都是可点击的,点击时对该节点进行ajax调用并返回数据,基于此时的一些标准nodes.push(xx),links.push(xx)碰巧添加新节点并调用restart()绘制新的节点和链接。问题是主图正在做正确的事情(屏幕截图中没有显示,因为我必须在第一个图上放置虚假数据,即调用端点/record/id/first 不会返回数据),但有一堆随机节点出现在右下角。

您还可以在下面的示例中看到,即使单击第一个/第二个/第三个后数据没有更改,在 restart() 后传入相同数据的情况下,node.enter() 也会出现问题...

JS fiddle :http://jsfiddle.net/5754j86e/

initial graph

after click

var   w = 1200,
      h = 1200;

var nodes = [];
var links = [];
var node;
var link;
var texts;

var ids = [];

var circleWidth = 10;

var initialIdentifier = "marcin";

nodes = initialBuildNodes(initialIdentifier, sparql);

links = initialBuildLinks(sparql);

//Add SVG

var svg = d3.select('#chart').append('svg')
  .attr('width', w)
  .attr('height', h);

var linkGroup = svg.append("svg:g").attr("id", "link-group");
var nodeGroup = svg.append("svg:g").attr("id", "node-group");
var textGroup = svg.append("svg:g").attr("id", "text-group");

//Add Force Layout

var force = d3.layout.force()
  .size([w, h])
  .gravity(.05)
  .charge(-1040);

force.linkDistance(120);

restart();


function restart() {

    force.links(links)

    console.log("LINKS ARE: ", links)

    link = linkGroup.selectAll(".link").data (links);

    link.enter().append('line')
        .attr("class", "link");

    link.exit().remove();

    force.nodes(nodes)

    console.log("NODES ARE: ", nodes)

    node = nodeGroup.selectAll(".node").data (nodes);

    node.enter().append("svg:g")
            .attr("class", "node")
            .call(force.drag);

    node.append('circle')
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .attr('r', circleWidth )
        .attr('fill', function(d, i) {
            if (i>0) { return palette.pink }
            else { return palette.blue }
        })

        .on("click", function(d) {
            nodeClicked (d);
        })

        .on('mouseenter', function(d){
            nodeMouseEnter(d)
            })
        .on('mouseout', function(d){
            nodeMouseOut(d)
        });


    node.exit().remove();

    var annotation = textGroup.selectAll(".annotation").data (nodes);

    annotation.enter().append("svg:g")
            .attr("class", "annotation")
            .append("text")
            .attr("x", function(d) { return d.radius + 4 })
            .attr("y", ".31em")
            .attr("class", "label")
            .text(function(d) { return d.name; });
    annotation.exit().remove();


    force.start();
}


function nodeClicked (d) {

    // AJAX CALL happens here and bunch of nodes.push({name: "new name"}) happen

}


force.on('tick', function(e) {
        link
            .attr('x1', function(d) { return d.source.x })
            .attr('y1', function(d) { return d.source.y })
            .attr('x2', function(d) { return d.target.x })
            .attr('y2', function(d) { return d.target.y })

        node.attr('transform', function(d, i) {
            return 'translate('+ d.x +', '+ d.y +')';
        })

        svg.selectAll(".annotation").attr("transform", function(d) {
            var labelx = d.x + 13;
            return "translate(" + labelx + "," + d.y + ")";
        })



    });

最佳答案

好的,我明白了,根据文档 ( https://github.com/mbostock/d3/wiki/Selections#enter ):

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() /* complete the enter-update-exit pattern */

从我的代码中,您可以看到我执行了 Enter(),然后再次在单独的语句中在节点上添加了圆圈。

node = nodeGroup.selectAll(".node").data (nodes);

    node.enter().append("svg:g")
            .attr("class", "node")
            .call(force.drag);

    node.append('circle')
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .attr('r', circleWidth )
        .attr('fill', function(d, i) {
            if (i>0) { return palette.pink }
            else { return palette.blue }
        });

添加圆圈应该在 Enter() 的范围内,否则它会发生在所有节点上,而不仅仅是节点,因此它应该是:

    node.enter().append("svg:g")
      .attr("class", "node")
      .call(force.drag)

      .append('circle')
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .attr('r', circleWidth )
        .attr('fill', function(d, i) {
            if (i>0) { return palette.pink }
            else { return palette.blue }
        });

关于javascript - D3js 在 Enter() 上强制重复节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27984603/

相关文章:

d3.js - nvd3 : remove y-axis tick labels from discrete bar chart

javascript - 如何在有界区域中正确模拟重力?

javascript - 事件处理程序关闭中 d3.js 键控连接的内存泄漏

javascript - 如何计算javascript中字符串中的空行

javascript - 在 ReactJS 中渲染数组的内容

javascript - 如何创建一个包含 3 个学生的数组并让他们按名字和 nid 排序

php - 不使用 <form> 传递变量

javascript - FullCalendar 4 - 向事件对象添加/显示附加值

javascript - d3 - 笔刷/平移缩放 - 禁用上部 x 轴上的平移

javascript - 点沿路径插值平移函数