简体   繁体   中英

D3 V3 to D3 V4 Tree Array Reordered Wrong Using Hierarchy

This may sound more complex than I intend it to, however, I am switching from D3 V3 to D3 V4. ALL of my other graphs and charts have transferred over really easily, but this specific one (a tree) is causing all sorts of grief from changing from d3.layout.tree and simply using the .children() function then setting nodes/links the old way to the new way using d3.hierarchy(). I set it the way that I've seen in countless tutorials.

I have 2 different Plunkers set up. This one is in D3 V3 and is working/displaying properly with the correct array order: https://plnkr.co/edit/qXDWDGzhNIM2tTOoAXRa?p=preview

树应该如何看待

正确的数据顺序

var tree = d3.layout.tree()
                .nodeSize([0, 75])
                .children(function(d) {
                    return d.subsidiaries;
                });

            var line = d3.svg.line().interpolate('step')
                .x(function(d) {
                    return d.x;
                })
                .y(function(d) {
                    return d.y - 12;
                });

            // Define 'div' for tooltips
            var div = d3.select('#tree')
                // Declare the tooltip div
                .append('div')
                // Apply the 'tooltip' class
                .attr('class', 'tooltip')
                .style('opacity', 0);

            var svg = d3.select('#tree').append('svg')
                .attr('width', width + margin.left + margin.right)
                .append('g')
                .attr('transform', `translate(${ margin.left },${ margin.top })`);

            function lineData(d) {
                var points = [{
                    x: d.source.y,
                    y: d.source.x
                }, {
                    x: d.target.y,
                    y: d.target.x
                }];

                return line(points);
            }

            root = treeData;
            root.x0 = 0;
            root.y0 = 0;

            update(root);

            function update(source) {
                // Compute the flattened node list.
                var nodes = tree.nodes(root);
                console.log(nodes);

                var height = Math.max(500, nodes.length * barHeight + margin.top + margin.bottom);

                d3.select('svg').transition()
                    .duration(duration)
                    .attr('height', height);

                d3.select(window.frameElement).transition()
                    .duration(duration)
                    .style('height', `${ height }px`);

                // Compute the layout.
                nodes.forEach(function(n, i) {
                    n.x = i * barHeight;
                });

                // Update the nodes.
                var node = svg.selectAll('g.node')
                    .data(nodes, function(d) {
                        return d.id || (d.id = ++i);
                    });

This second one is in D3 V4, and it's clear to tell that the array order is extremely incorrect. Many of the objects are moved up the list from where they are supposed to be, so it's causing a weird collided effect as seen here: https://plnkr.co/edit/PGPw92URj24yDMrPenwE?p=preview

树看起来如何

不同的数据结构和对象顺序

function _drawTree(treeData) {
            // This solves the maximum call stack issue with d3 layout function
            const margin = {
                    top: 55,
                    right: 20,
                    bottom: 30,
                    left: 30
                },
                width = 960 - margin.left - margin.right,
                barHeight = 65,
                barWidth = width * 0.35,
                duration = 400,
                treeMap = d3.tree()
                    .nodeSize([0, 75]);

            let i = 0,
                root;

            var line = d3.line()
                .x(d => d.x)
                .y(d => d.y - 12)
                .curve(d3.curveStep);

            // Define 'div' for tooltips
            var div = d3.select('#tree')
                // Declare the tooltip div
                .append('div')
                // Apply the 'tooltip' class
                .attr('class', 'tooltip')
                .style('opacity', 0);

            var svg = d3.select('#tree').append('svg')
                .attr('width', width + margin.left + margin.right)
                .append('g')
                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

             function lineData(d) {
                var points = [{
                    x: d.source.y,
                    y: d.source.x
                }, {
                    x: d.target.y,
                    y: d.target.x
                }];

                return line(points);
            }

            root = d3.hierarchy(treeData, d => {
                return d.subsidiaries;
                });
            root.x0 = 0;
            root.y0 = 0;

            update(root);

            function update(source) {
                var tree = treeMap(root);

                var nodes = tree.descendants(root);

                console.log(nodes);

                // Compute the flattened node list.
                var height = Math.max(500, nodes.length * barHeight + margin.top + margin.bottom);

                d3.select('svg').transition()
                    .duration(duration)
                    .attr('height', height);

                d3.select(window.frameElement).transition()
                    .duration(duration)
                    .style('height', height + 'px');

                // Compute the layout.
                nodes.forEach((n, i) => {
                    n.x = i * barHeight;
                });

I've logged the necessary variables, and you can view them by popping open your dev console.

I'm not sure if this is enough information or not, please let me know if you need more! Thanks for the help!!!

It turns out that the answer was actually relatively simple. I was using forEach instead of eachBefore when laying out the nodes. The solution on this GitHub Issue .

They link to this example , and the correct fix is this:

// Compute the "layout". TODO https://github.com/d3/d3-hierarchy/issues/67
var index = -1;
root.eachBefore(function(n) {
    n.x = ++index * barHeight;
    n.y = n.depth * 20;
});

I have also updated my Plunker with the correct code in action...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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