【问题标题】:D3 v4 drag/drop tree node into new parents childrenD3 v4 将树节点拖放到新的父子节点中
【发布时间】:2017-03-04 23:06:10
【问题描述】:

在使用 4 个 D3 时,我在调整下面的 sn-p 以完全更新节点及其所有子节点时遇到了一些麻烦。

当一个节点被拖放到另一个父节点(在“dragend”事件中)时,此代码会触发。其目的是将拖动的节点从其当前父节点中移除,并将其插入到新的父子节点中。

当前的代码在使用 v4 时实际上仍然按照它的意图执行,但是现在有了新版本,似乎还有一些需要更新到“draggingNode”的东西,这样它才能正确过渡到新的位置.至少,需要将“draggingNode”应用到它的新“父级”,并将其“深度”更新到它在树中的新位置。 “draggingNode”的每个子节点也需要将其“深度”更新到它在树中的新位置。

  • selectedNode:将“draggingNode”拖放到的节点(新父节点)
  • draggingNode:当前被拖动的节点

目标片段 (full source code):

var index = draggingNode.parent.children.indexOf(draggingNode);
if (index > -1) {
    draggingNode.parent.children.splice(index, 1);
    // had to update the "draggingNode" parent "children" array if it's 
    // empty otherwise the "firstWalk()" core function throws an error when
    // trying to call "children[0]".
    if (draggingNode.parent.children.length == 0) {
        draggingNode.parent.children = null;
    }
}
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);
}

我相信上面的代码可以保持不变,但我需要做的是为“draggingNode”添加一些更新,以便它可以正确更新。

我最初的想法是在上面的 sn-p 中添加以下内容,然后将其添加到“selectedNode”数组中:

draggingNode.parent = selectedNode;
draggingNode.depth = selectedNode.depth + 1;

这很好用!问题是它只适用于没有子节点的节点。需要更新子节点属性。

问题是

如何更新“draggingNode”及其所有子节点,以便将它们的属性正确调整到新的父节点和深度?

我可以使用hierarchystratify 之类的函数来正确更新它们吗?如果是这样,我不太确定如何使这些工作。或者也许 API 中没有可用的函数,我只需要遍历所有子节点并更新它们的深度?

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    事实证明,我想出了一个似乎对我很有效的解决方案。我最终创建了一个函数来遍历拖动节点的所有后代并更新它们的节点深度。

    function setNodeDepth(d) {
        d.depth = d == root ? 0 : d.parent.depth + 1;
        if (d.children) {
            d.children.forEach(setNodeDepth);
        } else if (d._children) {
            d._children.forEach(setNodeDepth);
        }
    }
    

    这就是我最终的结果..

    var index = draggingNode.parent.children.indexOf(draggingNode);
    if (index > -1) {
        draggingNode.parent.children.splice(index, 1);
        // had to update the "draggingNode" parent "children" array if it's 
        // empty otherwise the "firstWalk()" core function throws an error when
        // trying to call "children[0]".
        if (draggingNode.parent.children.length == 0) {
            draggingNode.parent.children = null;
        }
    }
    
    // update the "draggingNode" parent as well as update all its children 
    // so that their properties are properly adjusted to their new depths.
    draggingNode.parent = selectedNode;
    draggingNode.descendants().forEach(setNodeDepth);
    
    // check for visible children.
    if (selectedNode.children) {
        selectedNode.children.push(draggingNode);
    // check for hidden children.
    } else if (selectedNode._children) {
        selectedNode._children.push(draggingNode);
    // no children exist, create new children array and add "draggingNode".
    } else {
        selectedNode.children = [];
        selectedNode.children.push(draggingNode);
    }
    

    【讨论】:

      【解决方案2】:

      我刚刚将我的 D3 树升级到 V4 并且遇到了同样的问题。看起来 D3 V4 比以前做更多的内部簿记,并且搞乱节点属性不是一个好主意。 使用分型时,某些属性实际上被标记为只读(如深度),这确实告诉您一些事情......

      相反,通过更新您自己的数据结构并使用 d3.hierarchy() 刷新根节点来反映新布局。然后用新的根调用你的更新方法。 这对我来说非常有效,不需要黑客攻击!

      【讨论】:

      • 谢谢,我采纳了您的建议,到目前为止,这适用于各种树模型。
      猜你喜欢
      • 2011-06-25
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多