繁体   English   中英

将d3.js树从版本3迁移到版本6-我缺少什么?

Migrating d3.js tree from version 3 to 6 - what am I missing?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

因此,我一直在尝试将这种出色的d3.js树( http://bl.ocks.org/robschmuecker/7880033 )从d3.js版本3迁移到版本6。目前,我正在尝试进行拖放操作(请参见下面的代码)。 但这并不能像预期的那样起作用。 通过拖放重新排列节点后,树无法正确绘制。 此外,拖放操作似乎不适用于所有节点(根节点除外)。 到目前为止,我仍无法找到原因。 我怀疑问题可能是在更新子级之后树数据没有正确更新。 不幸的是,关于d3.js的教程并不多基于版本6(至少据我所知),因此我真的找不到很多有用的信息。

任何提示将不胜感激。 谢谢!

<!DOCTYPE html>
<html lang="en">
<head>
    <title>d3.js tree V6</title>
    <meta charset="utf-8"/>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style>
        body {
            font-family: Arial;
        }
        #title {
            font-size: 30px;
            margin-top: 20px;
        }
        .container {
            margin: 0 auto;
        }
        .text-center {
            text-align: center;
        }

        .link {
            fill: none;
            stroke: #ccc;
            stroke-width: 1.5px;
        }

        svg {
            display: block;
            margin: auto;
        }

        .node {
            cursor: pointer;
        }

        .ghostCircle.show{
            display:block;
        }

        .ghostCircle, .activeDrag .ghostCircle{
            display: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- title -->
        <h1 class="text-center" id="title">d3.js tree V6</h1>
        <div id="concept-tree">
        </div>
    </div>


    <script>
        var treeData = {
                "name": "Top Level",
                "parent": "null",
                "children": [
                    {
                        "name": "Level 2: A",
                        "parent": "Top Level",
                        "children": [
                            {
                                "name": "Son of A",
                                "parent": "Level 2: A"
                            },
                            {
                                "name": "Daughter of A",
                                "parent": "Level 2: A"
                            }
                        ]
                    },
                    {
                        "name": "Level 2: B",
                        "parent": "Top Level"
                    }
                ]
            };

        // +++ INITIALIZATIONS +++ //
        var margin = {top: 20, right: 90, bottom: 30, left: 90},
            width = 1500 - margin.left - margin.right,
            height = 750 - margin.top - margin.bottom;

        var duration = 750;

        const svg = d3.select("#concept-tree").append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom),
            g = svg.append("g")
                .attr("transform",
                    "translate(" + margin.left + "," + margin.top + ")");

        root = d3.hierarchy(treeData, function(d) { return d.children; });
        root.x0 = height / 2;
        root.y0 = 0;

        // declares a tree layout and assigns the size
        var treemap = d3.tree().size([height, width]);

        var i = 0;

        var selectedNode = null;
        var draggingNode = null;


        // +++ FUNCTIONS +++ //
        function diagonal(s, d) {

            path = `M ${s.y} ${s.x}
            C ${(s.y + d.y) / 2} ${s.x},
              ${(s.y + d.y) / 2} ${d.x},
              ${d.y} ${d.x}`

            return path
        }

        svg.call(d3.zoom()
            .extent([[0, 0], [width, height]])
            .scaleExtent([1, 8])
            .on("zoom", zoomed));

        function zoomed({transform}) {
            g.attr("transform", transform);
        }

        // collapse the node and all it's children
        function collapse(d) {
            if(d.children) {
                d._children = d.children
                d._children.forEach(collapse)
                d.children = null
            }
        }

        function expand(d) {
            if (d._children) {
                d.children = d._children;
                d.children.forEach(expand);
                d._children = null;
            }
        }

        var overCircle = function(d) {
            selectedNode = d;
            //updateTempConnector();
        };
        var outCircle = function(d) {
            selectedNode = null;
            //updateTempConnector();
        };

        function centerNode(source) {
            /*scale = zoomEvent.scale();
            x = -source.y0;
            y = -source.x0;
            x = x * scale + viewerWidth / 2;
            y = y * scale + viewerHeight / 2;
            d3.select('g').transition()
                .duration(duration)
                .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
            zoomListener.scale(scale);
            zoomListener.translate([x, y]);*/
        }

        // toggle children on click
        function click(event, d) {
            if (event.defaultPrevented) return;

            if (d.children) {
                d._children = d.children;
                d.children = null;
            } else {
                d.children = d._children;
                d._children = null;
            }
            update(d);
            centerNode(d);
        }

        // for dragging nodes
        function dragEvent() {
            function dragstarted(event, d) {
                if (d == root) {
                    return
                }
                event.sourceEvent.stopPropagation();
            }
            function dragged(event, d) {
                var nodes = root.descendants();
                if (d == root) {
                    return
                }
                var domNode = this;
                initiateDrag(d, domNode);

                // move node
                d.x0 += event.dy;
                d.y0 += event.dx;
                var node = d3.select(this);
                node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
            }

            function dragended(event, d) {
                if (d == root) {
                    return
                }

                var domNode = this;

                function endDrag() {
                    selectedNode = null;
                    d3.selectAll('.ghostCircle').attr('class', 'ghostCircle');
                    d3.select(domNode).attr('class', 'node');
                    // now restore the mouseover event or we won't be able to drag a 2nd time
                    d3.select(domNode).select('.ghostCircle').attr('pointer-events', '');
                    //updateTempConnector();
                    if (draggingNode !== null) {
                        update(draggingNode);
                        centerNode(draggingNode);
                        draggingNode = null;
                    }
                }
                if (selectedNode) {
                    console.log(selectedNode);
                    // now remove the element from the parent, and insert it into the new elements children
                    var index = draggingNode.parent.children.indexOf(draggingNode);
                    if (index > -1) {
                        draggingNode.parent.children.splice(index, 1);
                    }
                    if (typeof selectedNode.children !== 'undefined' || typeof selectedNode._children !== 'undefined') {
                        if (typeof selectedNode.children !== 'undefined') {
                            selectedNode.children.push(draggingNode);
                        } else {
                            selectedNode._children.push(draggingNode);
                        }
                    } else {
                        selectedNode.children = [];
                        selectedNode.children.push(draggingNode);
                    }
                    // make sure that the node being added to is expanded so user can see added node is correctly moved
                    expand(selectedNode);
                    //sortTree();
                    endDrag();
                } else {
                    endDrag();
                }
            }

            return d3.drag()
                .on("start", dragstarted)
                .on("drag", dragged)
                .on("end", dragended);
        }


        function initiateDrag(d, domNode) {
            var nodes = d.descendants().slice(1),
                links = d.descendants();

            draggingNode = d;

            d3.select(domNode).select('.ghostCircle').attr('pointer-events', 'none');
            d3.selectAll('.ghostCircle').attr('class', 'ghostCircle show');
            d3.select(domNode).attr('class', 'node activeDrag');

            // remove link paths
            g.selectAll("path.link")
                .data(links, function(d) {
                    return d.id;
                }).remove();
            // remove child nodes
            g.selectAll("g.node")
                .data(nodes, function(d) {
                    return d.id;
                }).remove();
        }

        // main function
        function update(source) {

            // Assigns the x and y position for the nodes
            var treeData = treemap(root);

            // Compute the new tree layout.
            var nodes = treeData.descendants(),
                links = treeData.descendants().slice(1);

            // +++ NODES +++ //
            // update nodes
            var node = g.selectAll("g.node")
                .data(nodes, function(d) {
                    return d.id || (d.id = ++i);
                });

            // enter nodes
            var nodeEnter = node.enter().append("g")
                .attr("class", "node")
                .call(dragEvent())
                .attr("transform", function(d) {
                    return "translate(" + source.y0 + "," + source.x0 + ")";
                })
                .on("click", click);

            nodeEnter.append("circle")
                .attr('class', 'nodeCircle')
                .attr("r", 5)
                .style("fill", function(d) {
                    return d._children ? "blue" : "lightsteelblue";
                });

            nodeEnter.append("text")
                .attr("x", function(d) {
                    return d.children || d._children ? -10 : 10;
                })
                .attr("dy", ".35em")
                .attr('class', 'nodeText')
                .attr("text-anchor", function(d) {
                    return d.children || d._children ? "end" : "start";
                })
                .text(function(d) {
                    return d.data.name;
                })
                .style("fill-opacity", 1);

            // phantom node to give us mouseover in a radius around it
            nodeEnter.append("circle")
                .attr('class', 'ghostCircle')
                .attr("r", 30)
                .attr("opacity", 0.2) // change this to zero to hide the target area
                .style("fill", "red")
                .attr('pointer-events', 'mouseover')
                .on("mouseover", function(event, node) {
                    overCircle(node);
                })
                .on("mouseout", function(event, node) {
                    outCircle(node);
                });



            // update
            var nodeUpdate = nodeEnter.merge(node);

            // transition to the proper position for the node
            nodeUpdate.transition()
                .duration(duration)
                .attr("transform", function(d) {
                    return "translate(" + d.y + "," + d.x + ")";
                });


            // exit nodes
            var nodeExit = node.exit().transition()
                .duration(duration)
                .attr("transform", function(d) {
                    return "translate(" + source.y + "," + source.x + ")";
                })
                .remove();

            nodeExit.select('circle')
                .attr('r', 1e-6);

            nodeExit.select('text')
                .style('fill-opacity', 1e-6);


            // +++ LINKS +++ //
            // update links
            var link = g.selectAll("path.link")
                .data(links, function(d) {
                    return d.id;
                });

            // enter any new links at the parent's previous position
            var linkEnter = link.enter().insert("path", "g")
                .attr("class", "link")
                .attr("d", function(d) {
                    var o = {x: source.x0, y: source.y0}
                    return diagonal(o, o)
                });

            // update
            var linkUpdate = linkEnter.merge(link);

            // transition back to the parent element position
            linkUpdate.transition()
                .duration(duration)
                .attr('d', function(d){ return diagonal(d, d.parent) });

            // remove any exiting links
            var linkExit = link.exit().transition()
                .duration(duration)
                .attr('d', function(d) {
                    var o = {x: source.x, y: source.y}
                    return diagonal(o, o)
                })
                .remove();

            // store old positions
            nodes.forEach(function(d){
                d.x0 = d.x;
                d.y0 = d.y;
            });
        }

        // collapse after the second level
        //root.children.forEach(collapse);

        update(root);
    </script>
</body>
</html>

编辑

因此,在尝试了一些东西并进一步研究之后,我在GitHub上偶然发现了这个问题: https : //github.com/d3/d3-hierarchy/issues/139 因此,基本上d3.hierarchy()对于更新其结构似乎并不灵活。 如果要更改树结构,则有两种可能性:

a)通过d3.hierarchy(...)重新计算整个层次结构(这将导致重绘整个树)

b)或“手动”更改数据属性,即,在更改节点的子级时,还需要更改相关节点的深度高度(我不确定100%是否需要更改两个属性)。

我选择了b),它似乎工作得很好! 希望这对将来的人有所帮助。

唯一似乎无法完全正常工作的是将一个节点拖到另一个节点时的mouseover / mouseout事件。 对于某些节点,事件似乎根本不会触发,也不会立即触发。 我不明白

问题暂未有回复.您可以查看右边的相关问题.
1 从d3.js版本3更新到版本4

我最近将d3.js代码从v3切换到了v4,但在较新的版本中,轴已显示,但图形未显示。 我的旧代码是 但是在v4中,当我进行更改时,没有错误发生,但是图形也没有显示。 我正在使用的新代码是 问题的数据是 ...

2 将代码从版本 3 中的树布局图迁移到版本 5

我设法让这段代码处理我需要的一些事情。 它适用于d3.js第 3 版。 我想将其迁移到版本 5。 我可以分部分做,比如 但我不知道如何解决其余的问题,我查看了文档,但不明白如何进行更改。 这是我的实时代码: https://jsfiddle.net/z4fah7gm/ 这是我的代码: ...

2020-09-17 03:49:18 1 95   d3.js
3 D3.js版本4。圆的基本呈现

我刚刚开始学习D3。 现在它的版本为4,不幸的是,大多数在线教程和示例都是版本3。 我正在尝试创建圈子。 但是似乎无法使attr方法起作用。 我创建了小提琴,简化为仅绘制一个圆圈。 D3 v3: https : //jsfiddle.net/pratheepraj/595rrq ...

2016-09-24 05:49:02 1 348   d3.js
4 与选择d3.js版本3混淆

我正在使用d3.js版本3(对不起,它不是4),并且对其嵌套选择感到困惑。 在下面的代码中,我打算对包含当前时间的3深度二元树进行动画处理: 在第一次调用时,它精确地绘制了我想要的:2个红色,4个绿色和8个蓝色单元。 但是从第二个调用开始,它仅绘制前半部分,而后者被删除。 ...

5 如何将D3.js集成到Jasper Soft Community版本

我们已经使用D3.js创建了仪表板。 但是我们无法使用jrxml文件从jasperreport服务器(社区版本)调用D3.js脚本。 请建议是否可以从jasreport(社区版本)调用D3 js脚本。 ...

2015-01-15 11:41:13 1 632   d3.js
6 D3.js版本4使节点粘滞

我是D3版本4的新用户,我在向强制定向布局中添加固定节点功能时遇到了问题。 我相信这是通过将d.fixed设置为true在v3中实现的,但是我将此问题转换为与v4兼容的问题。 我已经尝试添加simulation.fix,但是如果不从模拟开始修复节点,就无法将其集成到我现有的代码中。 理 ...

7 D3.js 版本 5 图表转 PDF

我目前使用的是 d3.js 版本 5,想知道是否有实际的方法可以将我的图表导出为 PDF? 例如,在下面提供的屏幕截图中,有一个供我使用的按钮或一个可供我将该特定图表导出为 PDF 的选项 ...

8 d3.js将sankey拖放功能迁移到v4

任何人都可以做出榜样 具有水平和垂直节点移动的Sankey图 在v4中工作 因为sankey.relayout()不再可用,所以d3.drag不再具有.origin。 我的尝试在尝试拖动节点时做了最疯狂的事情,并且由于sankey和drag规范中的某些行为已更改,因此我无 ...

2018-01-24 19:47:45 0 471   d3.js
9 d3.js 3.5 版与 5.16 版梯度问题

我在网上找到了关于我需要的图表(径向条形图)的非常好的代码。 但是,它适用于 d3.js 的 3.5.3 版,但不适用于 5.16.0 版。 当我在研究它时,我似乎无法确切地找到为什么某些代码不起作用。这是代码: 问题是渐变的代码:在 5.16 版中,从 ** var gradients = d ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM