D3.js:实时森伯斯特分区数据:重新创建层次结构?

问题描述

首先:我喜欢 D3。太奇妙了。让我希望我能更好地了解 JS。希望有人能帮助我!

我一直在研究多变量、可缩放的旭日+冰柱图。作为参考,我受到以下启发:

我最近一直在考虑添加一个实时组件:我已经将一个实时数据馈送(通过 MQTT)集成到我的 JS 代码中,它从源接收/读取数据并将其添加到分层数据。从本质上讲,我不断地添加构建我的旭日图的数据,每 2 秒重新绘制一次旭日图,我想知道最好的方法

实时前,我开始读取静态 JSON 文件,使用 d3.json 加载 JSON 文件,然后调用 d3.hierarchy,最终我传递给 {{1} }.注意:因为我有多个值/变量,所以我需要多次运行 d3.partition 以获得不同大小的弧,然后在它们之间进行补间。 This seemed to work fine. Example here.

但是现在我每 2 秒一遍又一遍地构建层次结构 + 分区,因为数据是从后面加载的,我想知道:创建一个新的层次结构会更好吗? (d3 节点树) 每次都从我的数据中获取,还是自己构建层次结构?

我特别关心 partition 是如何工作的(用于在前一个值和新值的弧之间进行补间),以及 d3 如何知道哪些节点是新的,哪些不是?如果我每次都运行 select.join(),那么每个节点都是新的(对吧?),那么 enter-vs-update 是如何工作的?即使源数据相同(尽管由于实时更新而具有不同的值)。我认为没有公开记录的创建“new Node()”的方法,或者如何维护/添加到节点树,但似乎这比每隔几秒运行一次 d3.hierarchy() 更有效.

我希望我已经解释清楚了吗?只是在寻找一些专家的指导。谢谢!

解决方法

当您调用 .data() 时,您可以提供第二个参数来告诉 D3 如何识别每个项目。例如,.data(mydata,d => d.data.id) 表示使用 id 字段来标识每个节点。

然后,当 .join() 起作用时,它会查看此值并将其与附加到每个节点的内容进行比较。在任何节点上看不到的任何新值都将转到 enter,而在现有节点上找到的那些值将转到 update

唯一的技巧是确保您指定的值绝对是唯一的,并且不会在调用之间改变。例如,如果您执行诸如 .data(mydata,d => d.data.surname) 之类的操作并且您得到两个具有相同姓氏的项目,则输入/更新将产生不可预测的结果。同样,如果您执行 .data(mydata,d => d.data.randomValue),则项目将永远不会更新,因为每次调用之间的值始终不同 - 节点将通过 exit 删除,然后通过 enter 重新创建,而不是留在放置但由 update 修改,因为不同的值使 D3 将它们视为新节点,而不是将它们识别为现有节点。