如何在 Vega JS 中实现树节点切换? [英] How to implement tree nodes toggling in Vega JS?

查看:44
本文介绍了如何在 Vega JS 中实现树节点切换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用

这是因为我处理这种交互的方式:

  1. 当你点击一个节点时,会触发toggledNode信号,进而触发expandedNodes数据数组中的toggle动作.IE.通过单击一个节点,我可以在 expandedNodes 数组中添加或删除该节点(更准确地说,我们添加/删除了一个只有 name 属性的简化对象)
  2. 因此 expandedNodes 数据包含有关哪些节点被显式扩展的信息.但它不知道这些展开的节点是否在折叠的父节点内.
  3. 然后,为了找出哪些节点实际上是可见的,我使用了 visibleNodes 数据.在那里我使用以下表达式应用 filter 转换: !datum.parent ||indata('expandedNodes', 'name', datum.parent).IE.我只检查一个级别:如果节点的父节点存在于 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 函数获取树节点祖先数组,但我无法用它做任何事情来验证所有祖先都已展开.

要么我的方法是错误的,有人可以找到更好的算法来做同样的事情,它不需要迭代数组(dataindata 表达式除外) - 或者这是 Vega 的当前限制.

解决方案

您可以使用 treeAncestors,然后使用展平变换来获取您可以查询的数据集.在您的情况下,它看起来像:

<代码>{变换":[{作为":树祖先",类型":公式","expr": "treeAncestors('tree', datum.id, 'root')";}],名称":树祖先",来源":树"},{transform":[{fields":[treeAncestors"],type":flatten"}],名称":tree-ancestors-flatt",来源":树祖先";},{变换":[{类型":过滤器","expr": "indata('selected', 'value', datum.treeAncestors.id)";}],名称":过滤",来源":tree-ancestors-flatt"},{transform":[{type":aggregate",groupby":[id"]}],名称":过滤聚合",来源":过滤";},{变换":[{类型":过滤器","expr": "indata('filtered-aggregate', 'id', datum.id) "}],名称":过滤树",来源":树"}

I'm using Vega JS for building a tree chart. In general, my question is the following:

Vega documentation has a great example of tree layout. How can I extend it with an ability to collapse & expand its nodes?

To be more specific, let's consider an example of tree chart that I'm building here in Vega Editor.

If you click on the nodes, they will toggle (expand or collapse), allowing you to see particular branches of the tree. This feature works fine unless you try to collapse the top-level node (region) while keeping the second-level nodes (districts) expanded. In that case the tree will look like this:

It happens because of the way I handle this interaction:

  1. When you click on a node, toggledNode signal is triggered, which in turn triggers toggle action in the expandedNodes data array. I.e. by clicking on a node, I add or remove that node to the expandedNodes array (more precisely, we add/remove a reduced object with only name property)
  2. Thus expandedNodes data contains information about which nodes are explicitly expanded. But it doesn't know if those expanded nodes are inside of a collapsed parent node.
  3. Then, to find out which nodes are actually visible, I use visibleNodes data. There I apply filter transform with the following expression: !datum.parent || indata('expandedNodes', 'name', datum.parent). I.e. I check only one level up: if the node's parent is present in the expandedNodes array , I consider the node as visible.

The problem is the following: I can't find any way of extending this functionality across multiple levels.

Probably I could write some hooks to check the same condition across 2 or 3 levels, e.g:

!datum.parent ||
  indata('expandedNodes', 'name', datum.parent) && 
  indata('expandedNodes', 'name', datum.myCustomFieldWithParentNode.parent) && 
  indata('expandedNodes', 'name', datum.myCustomFieldWithParentNode.myCustomFieldWithParentNode.parent)

But it seems too complex for such a simple problem, and also it's not a final solution. In theory, a tree may contain dozens of nesting levels: what to do then?

I found one useful expression in Vega: treeAncestors. I could easily write a solution in JavaScript, where I have loops and array methods such as .some() and .every(). But apparently Vega doesn't support any expressions to iterate over an array. So even though I can get an array of tree node ancestors with treeAncestors function, I can't do anything with it to verify that all ancestors are expanded.

Either my approach is wrong, and somebody can find a better algorithm for doing the same, which doesn't require iterating over arrays (except for data and indata expressions) - or it's a current limitation of Vega.

解决方案

You can use treeAncestors and then use a flatten transform to get a dataset that you can query. In your case it would look something like:

{
  "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"
}

这篇关于如何在 Vega JS 中实现树节点切换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆