【问题标题】:D3 force directed graph node - text is being duplicated when expadingD3 强制有向图节点 - 展开时文本被复制
【发布时间】:2013-11-15 16:32:18
【问题描述】:

我正在尝试实现我在 D3 网站上看到的展开/折叠功能,但我得到的是,当我运行此功能时,某些节点会具有多个标签。

   var width = 960,
            height = 500;

        var node,
            path,
            root, nodes, links, link;

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

        var force = d3.layout.force();

        var resource = $.getJSON('js/nodes.json', function(data)
        {
            root = restructure(data);
            render();
        })

        function restructure(data)
        {
            var root = data[0];
            data.splice(0,1);
            root.children = data;
            _.each(root.children, function(child)
            {
                child._children = child.links;
            })

            return root;
        }


        function flatten(root) {

            // return root;
            var nodes = [];
            var links = [];

            function rec(node) {
                var sourceNode = addNode(nodes, node);

                if (node.children)
                {
                    //sourceNode.children = [];
                    node.children.forEach(function(child)
                    {
                        var targetNode = rec(child);
                        links.push({source:sourceNode, target:targetNode});
                        //sourceNode.children.push(targetNode);
                    })

                }

                return sourceNode;
            }


            rec(root);
            return {nodes:d3.values(nodes), links:links};
        }

        function addNode(collection, node) {
            if(collection[node.name] != null)
                return collection[node.name];

            collection[node.name] = node;
            return node;
        }

        function render()
        {
            var flat = flatten(root);
            var nodes = flat.nodes;
            var links = flat.links;

             nodes = tree.nodes(elements.nodes).reverse();
             links = tree.links(nodes);*/

            force.nodes(nodes)
                .links(links)
                .size([width, height])
                .linkDistance(160)
                .charge(-1500)
                .on("tick", tick)
                .start();

            var drag = force.drag()
                .on("dragstart", dragstart);

            function dragstart(d) {
                d.fixed = true;
                d3.select(this).classed("fixed", true);
            }

            function isRoot(node)
            {
                return node.id == root.id
            }

            /*  link = svg.selectAll(".link")
             .data(force.links())
             .enter().append("line")
             .attr("class", "link");*/


            // Update the links…
            link = svg.selectAll("line.link")
                .data(force.links(), function(d) { return d.target.id; });

            // Enter any new links.
            link.enter().insert("line", ".node")
                .attr("class","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; })
                .style("stroke-width",function(l)
                {
                    console.log(l.source.rank + ':' + l.target.rank);
                    var val = Math.min(10,Math.max(1,Math.log(Math.max(Math.abs(l.source.rank),Math.abs(l.target.rank)))));
                    console.log('width: ' + val);
                    return val;
                });

            // Exit any old links.
            link.exit().remove();


            node = svg.selectAll(".node")
                .data(force.nodes());

            node.exit().remove();

            node.enter().append("g")
                .attr("class", "node")
                .attr("id", function(d) { return d.id; })
                .on("click", click)
                .on("dblclick", doubleclick)
                .on("mouseover", mouseover)
                .on("mouseout", mouseout)
                .call(force.drag);

            node.append("image")
                .attr("xlink:href", function (d)
                {
                    return "../img/icon-location.png";
                })
                .attr("x", -8)
                .attr("y", -8)
                .attr("width", 16)
                .attr("height", 16);

            /*  node.append("circle")
             .attr("r", function(d)
             {
             return isRoot(d)? 14:8;
             })
             .style("fill",function(d)
             {
             return isRoot(d)? "steelblue":"";
             });*/

            var center = svg.select('#node_' + nodes[0].id)
            center.append("circle")
                .attr("r", "14")
                .style("fill","steelblue");

            node.append("text")
                .attr("x", 12)
                .attr("dy", ".35em")
                .text(function(d) { return  d.name; });



            node.transition()
                .attr("r", function(d) { return d.children ? 4.5 : Math.sqrt(d.size) / 10; });

            // Exit any old nodes.
            node.exit().remove();
        }

        function tick() {
            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) { return "translate(" + d.x + "," + d.y + ")"; });
        }

        // Toggle children on click.
        function doubleclick(d) {
            alert(d);
        }
        // Toggle children on click.
        function click(d) {
            if (d.children) {
                d._children = d.children;
                d.children = null;
            } else {
                d.children = d._children;
                d._children = null;
            }
            render();
        }

        function mouseover() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 16);
        }

        function mouseout() {
            d3.select(this).select("circle").transition()
                .duration(750)
                .attr("r", 8);
        }

但是,我得到的(扩展后)是这样的:

<g class="node fixed" id="1063" transform="translate(329.44373878271944,118.27604414379978)" r="NaN"><image xlink:href="../img/icon-location.png" x="-8" y="-8" width="16" height="16"></image><text x="12" dy=".35em">PRO</text><image xlink:href="../img/icon-location.png" x="-8" y="-8" width="16" height="16"></image><text x="12" dy=".35em">Dropbox</text></g>

有什么帮助吗?

【问题讨论】:

  • 另外,每次您点击“simon simon”时,它都会在我上面发布的同一个 html 中不断添加更多的文本项。
  • 您似乎主要将元素附加到更新选择node。您可能想改用node.enter()
  • 但我愿意....见下文。你可以说得更详细点吗? node.enter().append("g") .attr("class", "node") .attr("id", function(d) { return d.id; }) .on("click", click ) .on("dblclick", 双击) .on("mouseover", mouseover) .on("mouseout", mouseout) .call(force.drag);
  • 在上面的代码中,你做例如node.append("text")render()
  • 我是 D3 的新手,我还在学习进入/退出的概念。你能发布一些你建议如何解决这个问题的衬里吗?谢谢!'

标签: javascript svg d3.js force-layout


【解决方案1】:

您希望确保更新的节点与现有的 DOM 元素正确匹配,您已经在为边缘做这件事。您将身份函数作为第二个参数传递给节点data() 调用。也许:

        node = svg.selectAll(".node")
            .data(force.nodes(), function(d) { return d.id; });

您需要注意的一件事是,该函数既可以在新数据元素上调用,也可以在正在更新的节点上存储的数据上调用。

欲了解更多信息,请参阅http://bost.ocks.org/mike/selection/

【讨论】:

    猜你喜欢
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 2015-01-06
    • 2018-02-18
    • 2016-02-21
    • 1970-01-01
    相关资源
    最近更新 更多