防止D3在更新时添加重复 [英] Prevent D3 adding duplicates on update

查看:149
本文介绍了防止D3在更新时添加重复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一个工作的D3动画。



鼠标点击时子节点成功消失...然而,添加了重复的节点。如果你在运行下面的代码,然后折叠和打开节点,你会看到节点出现在其他的顶部!



可以看到重复的圆圈元素



只需简单的折叠和打开就是我们在这里。您的帮助非常感谢!




$ b

div class =snippetdata-lang =jsdata-hide =falsedata-console =truedata-babel =false>

 < html>< head>< style> .node {cursor:pointer; font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif; font-weight:300; } .node .text {fill:white; } .ORG .circle {fill:#1d3649; } .EMR .circle {fill:#B2D0F5;中风:#5596e6; stroke-dasharray:3px,3px;不透明度:.5; } .EMR .circle:hover {fill:#5596e6; } .link {fill:none; stroke:#eee; stroke-width:1.5px; font:10px sans-serif; } .link.active {stroke:#ddd; stroke-width:2; } .arrow {fill:#666; } .arrow.active {stroke-width:0!important; }< / style>< / head>< body>< script src =https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js>< ; / script>< script src =// d3js.org/d3.v3.min.js\"> ;&script> ;<script> var dataset = {nodes:[{id:223,type:Parent,properties:{}},{id:136525,type:Child :{patient:6090,batch:70}},{id:146525,type:Child,properties:{patient:6090 :70}},{id:156525,type:Child,properties:{patient:6090 :166525,type:Child,properties:{patient:6090,batch:70}},{id:176525,type属性:{patient:6094,property:{patient:6090,batch:70}},{id:136448,type batch:70}},{id:136328,type:Child,properties:{patient:6082 id:136305,type:Child,properties:{patient:6096,batch:70}} ,properties:{patient:6093,batch:70}},{id:136299,type: ;batch:70}},{id:136261,type:Child,properties:{patient:6089 {id:136212,type:Child,properties:{patient:6087,batch:70}},{id:136115,type:儿童,属性:{patient:6078,batch:70}},{id:136113,type: 6088,batch:70}},{id:135843,type:Child,properties:{patient:6072,batch:70} }:{id:0,from:136113,to:555,;{id:555,type:Grandchild,properties:{}} properties:{}},{id:0,from:136525,至:555,properties:{}},{id:0,from:146525, :555,properties:{}},{id:0,from:156525,到:555,properties:{}},{id:0,from: 166525to:136448,properties:{}},{id:0,from:176525,到:223, from:223,to:136525,properties:{}},{id:0,from:223到:136448,properties:{}},{id :0从:223到:136328,属性:{}},{id:0,从:223到:136305, ,:,from:136525,到:136303,properties:{}},{id:0,from:223 :{}},{id:0,from:223至:136261,properties:{}},{id:0,from:223,to:136212 ,属性:{}},{id:0,from:223,到:136115,properties到:136113,properties:{}},{id:0,from:223,到:135843,properties:{}}]} var width = .width(),height = 0.95 * $(window).height(); var svg = d3.select(body)。append(svg).attr(width,width).attr(height,height); var force = d3.layout.force().size([width,height])//gravity(0.2).linkDistance(height / 6).charge(function(node){if(node.type!=='ORG ')return -2000; return -30;}); //构建箭头。 svg.append(svg:defs)。selectAll(marker).data([end])//不同的链接/路径类型可以在这里定义。 //这部分添加箭头.attr(id,function(d){return d;}).attr(viewBox,0 -5 10 10).attr(refX,12)。 attr(refY,0).attr(markerWidth,9).attr(markerHeight,5).attr(orient,auto).attr(class,arrow).append (svg:path).attr(d,M0,-5L10,0L0,5); var json = dataset; var edges = []; json.edges.forEach(function(e){var sourceNode = json.nodes.filter(function(n){return n.id === e.from;})[0],targetNode = json.nodes.filter [0]; edges.push({source:sourceNode,target:targetNode,value:e.id});}); var colors = {}; colors [23] =lightblue; colors [25] =lightgreen; colors [48] =lightyellow; colors [28] =lightblue; colors [5] =lightgreen; colors [3] =lightyellow; colors [99] =lightblue; colors [61] =lightgreen; colors [12] =lightyellow; for(var i = 0; i  



[基于此的代码: http://jsfiddle.net/sheilak/9wvmL8q8/

解决方案

问题在这里:

  node.enter()。append(g)... 

node.append(circle)...

node.append text)...

虽然您要将组添加到输入选择,将圆形和文本添加到节点选择,即转换元素



try:

  var nodeEnter = node.enter()append(g)... 

nodeEnter.append(circle)...

nodeEnter.append(text)...
pre>

在这种情况下, nodeEnter 将等于链中最后创建的元素,是 g 元素。


The below is a "working" D3 animation.

Child nodes successfully disappear on mouse-click... HOWEVER, duplicates nodes ("circles") are added. If you play around with running the following code, then collapsing and opening nodes you will see nodes appearing on top of other ones!

The duplication of circle-elements can be seen in chrome-inspection too.

Just simple collapse and open is what we're after here. Your help is much appreciated ! Thank you.

(ignore the node labels - they're not important)

<html>
<head>
<style>
    .node {
        cursor: pointer;
        font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
        font-weight: 300;
    }

    .node .text {
        fill: white;
    }

    .ORG .circle {
        fill: #1d3649;
    }

    .EMR .circle {
        fill: #B2D0F5;
        stroke: #5596e6;
        stroke-dasharray: 3px, 3px;
        opacity: .5;
    }

    .EMR .circle:hover {
        fill: #5596e6;
    }

    .link {
        fill: none;
        stroke: #eee;
        stroke-width: 1.5px;
        font: 10px sans-serif;
    }

    .link.active {
        stroke: #ddd;
        stroke-width: 2;
    }

    .arrow {
        fill: #666;
    }

    .arrow.active {
        stroke-width: 0 !important;
    }

</style>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
    var dataset = {
        "nodes": [{
            "id": 223,
            "type": "Parent",
            "properties": {

            }
        }, {
            "id": 136525,
            "type": "Child",
            "properties": {
                "patient": "6090",
                "batch": "70"
            }
        }, {
            "id": 146525,
            "type": "Child",
            "properties": {
                "patient": "6090",
                "batch": "70"
            }
        }, {
            "id": 156525,
            "type": "Child",
            "properties": {
                "patient": "6090",
                "batch": "70"
            }
        }, {
            "id": 166525,
            "type": "Child",
            "properties": {
                "patient": "6090",
                "batch": "70"
            }
        }, {
            "id": 176525,
            "type": "Child",
            "properties": {
                "patient": "6090",
                "batch": "70"
            }
        }, {
            "id": 136448,
            "type": "Child",
            "properties": {
                "patient": "6094",
                "batch": "70"
            }
        }, {
            "id": 136328,
            "type": "Child",
            "properties": {
                "patient": "6082",
                "batch": "70"
            }
        }, {
            "id": 136305,
            "type": "Child",
            "properties": {
                "patient": "6096",
                "batch": "70"
            }
        }, {
            "id": 136303,
            "type": "Child",
            "properties": {
                "patient": "6093",
                "batch": "70"
            }
        }, {
            "id": 136299,
            "type": "Child",
            "properties": {
                "patient": "6091",
                "batch": "70"
            }
        }, {
            "id": 136261,
            "type": "Child",
            "properties": {
                "patient": "6089",
                "batch": "70"
            }
        }, {
            "id": 136212,
            "type": "Child",
            "properties": {
                "patient": "6087",
                "batch": "70"
            }
        }, {
            "id": 136115,
            "type": "Child",
            "properties": {
                "patient": "6078",
                "batch": "70"
            }
        }, {
            "id": 136113,
            "type": "Child",
            "properties": {
                "patient": "6088",
                "batch": "70"
            }
        }, {
            "id": 135843,
            "type": "Child",
            "properties": {
                "patient": "6072",
                "batch": "70"
            }
        }, {
            "id": 555,
            "type": "Grandchild",
            "properties": {

            }
        }],
        "edges": [{
            "id": 0,
            "from": 136113,
            "to": 555,
            "properties": {

            }

        },{
            "id": 0,
            "from": 136525,
            "to": 555,
            "properties": {

            }
        },{
            "id": 0,
            "from": 146525,
            "to": 555,
            "properties": {

            }
        },{
            "id": 0,
            "from": 156525,
            "to": 555,
            "properties": {

            }
        },{
            "id": 0,
            "from": 166525,
            "to": 136448,
            "properties": {

            }
        },{
            "id": 0,
            "from": 176525,
            "to": 223,
            "properties": {

            }
        },{
            "id": 0,
            "from": 223,
            "to": 136525,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136448,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136328,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136305,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 136525,
            "to": 136303,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136299,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136261,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136212,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136115,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 136113,
            "properties": {

            }
        }, {
            "id": 0,
            "from": 223,
            "to": 135843,
            "properties": {

            }
        }]
    }

    var width = 0.975 * $(window).width(),
        height = 0.95 * $(window).height();

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

    var force = d3.layout.force()
        .size([width, height])
        //gravity(0.2)
        .linkDistance(height / 6)
        .charge(function(node) {
            if (node.type !== 'ORG') return -2000;
            return -30;
        });

    // build the arrow.
    svg.append("svg:defs").selectAll("marker")
        .data(["end"]) // Different link/path types can be defined here
        .enter().append("svg:marker") // This section adds in the arrows
        .attr("id", function(d) {
            return d;
        })
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 12)
        .attr("refY", 0)
        .attr("markerWidth", 9)
        .attr("markerHeight", 5)
        .attr("orient", "auto")
        .attr("class", "arrow")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5");

    var json = dataset;

    var edges = [];
    json.edges.forEach(function(e) {
        var sourceNode = json.nodes.filter(function(n) {
                return n.id === e.from;
            })[0],
            targetNode = json.nodes.filter(function(n) {
                return n.id === e.to;
            })[0];

        edges.push({
            source: sourceNode,
            target: targetNode,
            value: e.id
        });
    });

    var colors = {};
    colors[23] = "lightblue";
    colors[25] = "lightgreen";
    colors[48] = "lightyellow";
    colors[28] = "lightblue";
    colors[5] = "lightgreen";
    colors[3] = "lightyellow";
    colors[99] = "lightblue";
    colors[61] = "lightgreen";
    colors[12] = "lightyellow";

    for(var i=0; i<json.nodes.length; i++) {
        json.nodes[i].collapsing = 0;
        json.nodes[i].collapsed = false;
        json.nodes[i].radius = json.nodes[i].id % 100;
        if(colors[json.nodes[i].radius] != undefined)
            json.nodes[i].color = colors[json.nodes[i].radius];
        else
            json.nodes[i].color = "lightbrown";
    }

    var link = svg.selectAll(".link");
    var node = svg.selectAll(".node");

    force.on("tick", function() {
        // make sure the nodes do not overlap the arrows
        link.attr("d", function(d) {
            // Total difference in x and y from source to target
            diffX = d.target.x - d.source.x;
            diffY = d.target.y - d.source.y;

            // Length of path from center of source node to center of target node
            pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));

            // x and y distances from center to outside edge of target node
            offsetX = (diffX * d.target.radius) / pathLength;
            offsetY = (diffY * d.target.radius) / pathLength;

            return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
        });

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

    update();

    function update(){
        var nodes = json.nodes.filter(function(d) {
            return d.collapsing == 0;
        });

        var links = edges.filter(function(d) {
            return d.source.collapsing == 0 && d.target.collapsing == 0;
        });

        link = svg.selectAll(".link").data(links);
        link.exit().remove();

        link.enter().append("path")
            .attr("class", "link")
            .attr("marker-end", "url(#end)");

        node = svg.selectAll(".node").data(nodes);
        node.exit().remove();

        node.enter().append("g")
            .attr("class", function(d) {
                return "node " + d.type
            });

        node.append("circle")
            .attr("class", "circle")
            .attr("r", function(d) {
                //d.radius = 30;
                return d.radius
            })
            .attr("fill", function(d) {
                //d.radius = 30;
                return d.color;
            })
            .attr("stroke", function(d) {
                //d.radius = 30;
                return "darkgray";
            });
         // return a radius for path to use



        node.append("text")
            .attr("x", 0)
            .attr("dy", ".35em")
            .attr("text-anchor", "middle")
            .attr("class", "text")
            .text(function(d) {
                return d.type
            });

        // On node hover, examine the links to see if their
        // source or target properties match the hovered node.
        node.on('mouseover', function(d) {
            link.attr('class', function(l) {
                if (d === l.source || d === l.target)
                    return "link active";
                else
                    return "link inactive";
            });
        });

        // Set the stroke width back to normal when mouse leaves the node.
        node.on('mouseout', function() {
            link.attr('class', "link");
        })
            .on('click', click);

        /** this is NOT the problem **/
        function click(d) {
            if (!d3.event.defaultPrevented) {
                var inc = d.collapsed ? -1 : 1;
                recurse(d);

                function recurse(sourceNode){
                    //check if link is from this node, and if so, collapse
                    edges.forEach(function(l) {
                        if (l.source.id === sourceNode.id){

                            l.target.collapsing += inc;
                            recurse(l.target);


                        }
                    });
                }
                d.collapsed = !d.collapsed;
            }
            update();
        }
        force
            .nodes(nodes)
            .links(links)
            .start();
    }

</script>

</body>
</html>

[code based on this: http://jsfiddle.net/sheilak/9wvmL8q8/

解决方案

The problem is here:

node.enter().append("g")...

node.append("circle")...

node.append("text")...

Although you are adding the group to the enter selection, you're adding the circle and text to the node selection which is the transitioning elements

try:

var nodeEnter = node.enter().append("g")...

nodeEnter.append("circle")...

nodeEnter.append("text")...

In this case, nodeEnter will be equal to the last created element in the chain, which in this case is the g element.

这篇关于防止D3在更新时添加重复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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