D3js在enter()上强制重复节点 [英] D3js force duplicate nodes on enter()

查看:101
本文介绍了D3js在enter()上强制重复节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在d3js上遇到了一些问题,无法弄清楚是怎么回事.这个想法是从一些端点数据(初始img)绘制初始图形,这很好用.每个节点都是可单击的,在该节点上单击ajax时会调用该节点,然后根据该节点处的某些条件返回数据.push(xx),links.push(xx)会添加新节点并调用restart()绘制新的节点和链接.问题在于主图在做正确的事情(未在屏幕快照上显示,因为我必须在第一个图上放置伪数据,即调用端点/record/id/first不会返回数据),但是有很多随机节点显示在右下角.

I am having some issues with d3js and I can't figure out what is going on. The idea is to draw initial graph from some endpoint data (first img), that's fine works well. Each node is clickable, on click ajax call is made for that node and data is returned, based on some criteria at that point nodes.push(xx), links.push(xx) happens to add new nodes and restart() is called to draw new nodes and links. The issue is that the main graph is doing the correct thing (Not showed on screenshots as I had to put fake data on the first graph i.e. calling an endpoint /record/id/first doesn't return a data) but there are bunch of random nodes showing up in the right bottom corner.

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

You can also see on the example below, even if the data doesn't change after clicking on first/second/third something wrong goes with node.enter() after restart() with the same data passed in...

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

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

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(),然后再次在单独的语句中的节点上添加了圆圈.

From my code you can see I do enter() and then once again I add circle on node in a separate statement.

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()范围内,否则它会发生在所有节点上,而不仅仅是 new 节点,因此它应该是:

Adding circle should be within the scope of enter() otherwise it happens to all nodes not only the new nodes therefore it should be :

    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 }
        });

这篇关于D3js在enter()上强制重复节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆