搜索d3树-搜索后重置

searching a d3 tree - reset after search

本文关键字:搜索 d3      更新时间:2023-09-26

我已经编写了一个搜索函数来运行一个可能相当大的d3树,并只过滤出与搜索模式匹配的节点。

搜索功能运行良好,速度相当快。

但是,由于服务器上计算数据的数量和时间,如果用户清除搜索或输入另一个搜索,而不进行另一个查询,我希望能够将树重置为其初始内容。这是行不通的。

这是我尝试过的:

1-克隆d3节点

首先,我研究了[克隆对象的最有效方法是什么][1],他们提出了几个建议。从Jasmine跑过来,我的克隆似乎奏效了(不知道为什么)。

在我的应用程序中运行代码时,我立即出现错误。确切的错误取决于我使用的代码-jquery.extend或JSON.stringify.的JSON.parse

我怀疑这是因为每个节点d都有一个d.parent属性和d.children,所以只要你想递归地克隆它的子节点,它就会进入一个循环。

2-设置d3.layout.tree.children以过滤数据

然后我注意到有一个d3.layout.tree.children函数,我可以用它来操作树。因此,我这样做而不是复制json数据,并且只返回d.visible为true的节点。这个想法是,当我想重置时,我不必做任何事情,我只需要回到基础,不过滤,孩子们。

这也不起作用——与搜索不匹配的子节点现在已经从数据中消失,而不仅仅是图形。

更新:我已经删除了最初不起作用的示例代码,并自己给出了一个适用于我的初步第一个答案。

不确定这是否是最优雅的方法,但它对我有效。

基本上,我只是在进行搜索之前复制对现有_node的引用。搜索在树中重复进行,并克隆与搜索模式匹配的节点。以及具有与搜索模式匹配的子节点的任何节点。因此,克隆卷受到匹配卷的限制。克隆代码本身非常幼稚——它只处理原始值,但这就是我现在所需要的。

注意:nodes基本上是您在任何在线d3示例中看到的传入json数据。

//support an array of possible attributes for string matches...
var li_tosearch = ["label"];
//a "set" of node attributes that should not be copied    
s_skip = Object.create(null);
s_skip.parent = 1;
s_skip.children = 1;
s_skip._children = 1;
s_skip._unfiltered_children = 1;

function clone_n_filter(pattern, d) {
    /* recursive search by node 
       - a node is visible if one of its searchable attributes
       matches the pattern or if one of its children/_children is
       visible.
       - only visible nodes get cloned 
    */
    if (!d  || !pattern){
        return;
    }
    var visible_child, clone, v, s;
    var visible = false;

    //support an array of possible attributes for string matches...
    for (var i = 0; i < li_tosearch.length; ++i){
        s = d[li_tosearch[i]];
        if (s){
            if (s.match(pattern)){
                visible = true;
                break;
            }
        }
    }

    var children = [], _children = [];
    //if any of the children are visible then the current is visible too
    if (d.children) {
        for (var index = 0; index < d.children.length; ++index) {
            visible_child = clone_n_filter(pattern, d.children[index]);
            if (visible_child) {
                children.push(visible_child);
                visible = true;
            }
        }
    }

    if (d._children) {
        for (var index2 = 0; index2 < d._children.length; ++index2) {
            visible_child = clone_n_filter(pattern, d._children[index2]);
            if (visible_child) {
                _children.push(visible_child);
                visible = true;
            }
        }
    }
    //not being used, but keeps track of all original children
    //this is just a reference, so memory cost is low
    //possible use case:  expand a non-leaf node that has
    //no visible children
    d._unfiltered_children = d.children || d._children;
    if (visible){
        clone = d.constructor(); // changed
        for(var key in d) {
            if (key in s_skip){
                continue;
            }
            if(d.hasOwnProperty(key)) {
                v = d[key];
                //given the domain, only expecting primitives...
                //will address when that breaks
                if (typeof(v) === 'object'){
                    throw("unexpected complex object:[" + typeof(v) + " " + key + "]");
                }
                clone[key] = v;
            }
            else{
                //keeping track of attributes we won't be copying
                s_skip[key] = 1;
            }
        }
        clone.children = children;
        clone._children = _children;
    }
    return clone;
}

整件事的切入点。重置非常快——它只将_node设置为原始保存的引用。

_chart.search = function(pattern){
  /* external entry point for calling the search*/
    if (!_nodes){
        return;
    }
    if (!pattern){
        //no search pattern
        if  (_o_nodes){
            //restore unfiltered
            _nodes = _o_nodes;            
        }
        chart.render();
        return;
    }
    if (!_o_nodes){
        //no need to clone the _nodes, just copy reference
        _o_nodes = _nodes;        
    }
    var patre = new RegExp(pattern,"gi");
    _nodes = clone_n_filter(patre, _o_nodes);
    chart.render();
};