我已将d3树从v3.5迁移到v5。现在,我发现使用Patrick Brockmann’s search and highlight functionality在树上执行搜索时,v5版本存在相当大的滞后。

使用下拉Select2进行搜索时,将显示延迟。在v5版本中,所有叶节点的扩展速度都不够快,导致几秒钟的大量黑色文本。在v3.5版本中不会发生这种情况。

javascript - d3-v5文字渲染比v3.5慢?-LMLPHP

有什么想法可以优化它以获得与树的v3.5版本相同的性能吗?两个版本中的JSON数据相同。

d3 v3.5 fiddle

d3 v5 fiddle

搜索功能中的代码(v3.5和v5版本均相同):

            function select2DataCollectName( d ) {
                if ( d.children )
                    d.children.forEach( select2DataCollectName );
                else if ( d._children )
                    d._children.forEach( select2DataCollectName );
                if ( !d.children && d.data.type == 'learning_event' ) select2Data.push( d.data.name );
            }

            //===============================================
            function searchTree( d ) {
                if ( d.children )
                    d.children.forEach( searchTree );
                else if ( d._children )
                    d._children.forEach( searchTree );
                var searchFieldValue = eval( searchField );
                if ( searchFieldValue && searchFieldValue.toLowerCase().match( searchText.toLowerCase() ) ) {
                    // Walk parent chain
                    var ancestors = [];
                    var parent = d;
                    while ( parent !== null && typeof ( parent ) !== "undefined" ) {
                        ancestors.push( parent );
                        //console.log(parent);
                        parent.class = "found";
                        parent = parent.parent;
                    }
                }
            }

            //===============================================
            function clearAll( d ) {
                d.class = "";
                if ( d.children )
                    d.children.forEach( clearAll );
                else if ( d._children )
                    d._children.forEach( clearAll );
            }
            //===============================================
            function collapse( d ) {

                if ( d.children ) {
                    d._children = d.children;
                    //set the parent object in all the children
                    d._children.forEach( function ( d1 ) {
                        d1.parent = d;
                        collapse( d1 );
                    } );
                    d.children = null;
                }
            }
            //===============================================
            function collapseAllNotFound( d ) {
                if ( d.children ) {
                    if ( d.class !== "found" ) {
                        d._children = d.children;
                        d._children.forEach( collapseAllNotFound );
                        d.children = null;
                    } else
                        d.children.forEach( collapseAllNotFound );
                }
            }
            //===============================================
            function expandAll( d ) {
                if ( d._children ) {
                    d.children = d._children;
                    d.children.forEach( expandAll );
                    d._children = null;
                } else if ( d.children )
                    d.children.forEach( expandAll );
            }

            //===============================================
            // Toggle children on click.
            function toggle( d ) {
                if ( d.children ) {
                    d._children = d.children;
                    d.children = null;
                } else {
                    d.children = d._children;
                    d._children = null;
                }
                clearAll( root );
                update( d );
                $( "#search" ).select2( "val", "" );
            }

            //===============================================
            $( "#search" ).on( "select2-selecting", function ( e ) {
                clearAll( root );
                expandAll( root );
                update( root );
                searchField = "d.data.name";
                searchText = e.object.text;
                searchTree( root );
                root.children.forEach( collapseAllNotFound );
                update( root );
            } )


    var colourScale = d3.scaleOrdinal()
        .domain(["MD", "Year 1", "Year 2", "Year 3", "Year 4"])
        .range(["#abacab", "#53e28c", "#4b80fa", "#eab014", "#bd57fe"]);

    // Set the dimensions and margins of the diagram
var margin = {top: 20, right: 90, bottom: 30, left: 0},
    width = 2000 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

    // append the svg object to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("body").append("svg")
        .attr("width", width + margin.right + margin.left)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" +
            margin.left + "," + margin.top + ")");



    var i = 0,
        duration = 750,
        root;

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

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

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

    update(root);


    select2Data = [];
                select2DataCollectName( root );
                select2DataObject = [];
                select2Data.sort( function ( a, b ) {
                        if ( a > b ) return 1; // sort
                        if ( a < b ) return -1;
                        return 0;
                    } )
                    .filter( function ( item, i, ar ) {
                        return ar.indexOf( item ) === i;
                    } ) // remove duplicate items
                    .filter( function ( item, i, ar ) {
                        select2DataObject.push( {
                            "id": i,
                            "text": item
                        } );
                    } );
                $( "#search" ).select2( {
                    placeholder: "Select a Learning Event...",
                    data: select2DataObject,
                    containerCssClass: "search"
                } );

最佳答案

您的标题是clickbait,因为两个版本之间的性能没有任何区别。听起来好像您正在报告回归。 :)

正如@RobertHarvey指出的,不同之处在于文本在输入时不会从透明淡入。从D3v3到D3v5移植代码时,您似乎错过了fill-opacity

    nodeEnter.append('text')
      // ...
      .style( "fill-opacity", 1e-6 )




    var nut = nodeUpdate.transition()
    // ...
    nut.select( "text" )
      .style( "fill-opacity", 1 );


Fork of your d3v5 fiddle

10-05 20:29