javascript - 如何在 Vega JS 中实现树节点切换?
问题描述
我正在使用Vega JS构建树形图。一般来说,我的问题如下:
Vega 文档中有一个很好的树形布局示例。如何通过折叠和扩展其节点的能力来扩展它?
更具体地说,让我们考虑一个我在 Vega Editor 中构建的树形图示例。
如果您单击节点,它们将切换(展开或折叠),从而允许您查看树的特定分支。除非您尝试折叠顶级节点(区域)同时保持二级节点(区域)展开,否则此功能可以正常工作。在这种情况下,树将如下所示:
发生这种情况是因为我处理这种交互的方式:
- 当您单击一个节点时,
toggledNode
会触发信号,进而触发数据数组toggle
中的动作。expandedNodes
即通过单击一个节点,我向expandedNodes
数组添加或删除该节点(更准确地说,我们添加/删除只有name
属性的缩减对象) - 因此
expandedNodes
,数据包含有关哪些节点被显式扩展的信息。但它不知道这些展开的节点是否在折叠的父节点内。 - 然后,为了找出哪些节点实际上是可见的,我使用
visibleNodes
数据。在那里,我使用filter
以下表达式应用变换:!datum.parent || indata('expandedNodes', 'name', datum.parent)
. 即我只检查一个级别:如果节点的父节点存在于expandedNodes
数组中,我认为该节点是可见的。
问题如下:我找不到跨多个级别扩展此功能的任何方法。
可能我可以编写一些钩子来检查 2 或 3 个级别的相同条件,例如:
!datum.parent ||
indata('expandedNodes', 'name', datum.parent) &&
indata('expandedNodes', 'name', datum.myCustomFieldWithParentNode.parent) &&
indata('expandedNodes', 'name', datum.myCustomFieldWithParentNode.myCustomFieldWithParentNode.parent)
但是对于这样一个简单的问题来说,它似乎太复杂了,而且它也不是最终的解决方案。理论上,一棵树可能包含几十个嵌套级别:那该怎么办?
我在 Vega 中发现了一个有用的表达式:treeAncestors。我可以很容易地用 JavaScript 编写一个解决方案,其中我有循环和数组方法,例如.some()
和.every()
。但显然 Vega 不支持任何表达式来迭代数组。因此,即使我可以获得具有treeAncestors
函数的树节点祖先数组,我也无法用它做任何事情来验证所有祖先是否都已展开。
要么我的方法是错误的,有人可以找到更好的算法来做同样的事情,它不需要迭代数组(data
和indata
表达式除外)——或者这是 Vega 的当前限制。
解决方案
您可以使用 treeAncestors,然后使用展平变换来获取可以查询的数据集。在您的情况下,它看起来像:
{
"transform": [
{
"as": "treeAncestors",
"type": "formula",
"expr": "treeAncestors('tree', datum.id, 'root')"
}
],
"name": "tree-ancestors",
"source": "tree"
},
{
"transform": [{"fields": ["treeAncestors"], "type": "flatten"}],
"name": "tree-ancestors-flatt",
"source": "tree-ancestors"
},
{
"transform": [
{
"type": "filter",
"expr": "indata('selected', 'value', datum.treeAncestors.id)"
}
],
"name": "filtered",
"source": "tree-ancestors-flatt"
},
{
"transform": [{"type": "aggregate", "groupby": ["id"]}],
"name": "filtered-aggregate",
"source": "filtered"
},
{
"transform": [
{
"type": "filter",
"expr": "indata('filtered-aggregate', 'id', datum.id) "
}
],
"name": "filtered-tree",
"source": "tree"
}
推荐阅读
- python - 如何避免时间线图中的标签重叠
- sql - 创建增量统计
- python - 获取存储在数据框列中的键值?
- android - 网站在浏览器中打开,但在 WebView 中不起作用
- c++ - 如何在 QTextEdit 中输出文本上方的单词
- vba - Application_ItemSend() 的语法是什么?
- php - 使用 ForEach 语句将值存储在数组中
- javascript - SailsJS / Waterline ORM:仅使用一个查询更新多个条目
- django - 如何从 websocket 请求中找到用户?
- laravel - Laravel 查询构建器 - 使用行中的数据与另一个中的时间进行比较