在D3.js中动态减少数据

时间:2016-12-24 20:03:45

标签: javascript d3.js svg

我使用D3显示SVG,显示来自JSON数据的圆圈。我想支持缩放和拖动。 JSON结构可以变得非常大。这是我的主要问题:

  • 为所有JSON条目添加圆圈并不真正起作用。页面变得太慢,因为DOM中可能有数千个<circle>元素。

我是如何解决的:

  • 我保留了我在拖动功能中更新的数据集的简化副本。在每个拖动事件中,我声明一个空数据集:

var reducedData = [];

我查看整个数据集,只推送到reducedData具有中心坐标的圆圈,这些圆圈在给定当前轴的情况下可见。然后我擦除SVG并使用reducedData重绘它。我对每个缩放事件执行相同的处理,仅在reducedData处根据当前缩放比率附加半径大于5像素的圆圈。

尽管页面响应速度很快并且似乎运行良好,但效率非常低,我确信这不是最好的方法。我的问题有哪些替代解决方案?感谢。

3 个答案:

答案 0 :(得分:1)

当然,总有改进的余地,但我认为你的方法已经足够好了,可能没有那么好。但是,如果您愿意,可以自行考虑和/或测试一些......

首先,我建议您检查是否真的需要进行任何优化。在最新版本的Google Chrome中,在“性能”标签下的DevTools中,您可以使用CPU限制来模拟速度较慢的设备。然后使用timeline tool,您可以验证数据减少或DOM操作是否导致任何瓶颈并降低帧速率。如果没有,不要出汗,你很高兴。

如果从您的分析中发现数据减少会降低渲染速度,您可以使用时间轴工具准确找到缓慢的位置并研究更快的替代方案。

另一方面,如果您的DOM操作导致任何问题,请确保您使用general update pattern,以确保您只在真正需要时才创建或删除元素。此外,您可以通过duplicating them加速创建圈子,而不是创建新圈子。

通常当需要可视化太多数据项时,作为最后的手段,我们会从SVG切换到基于画布的可视化,但我认为这对您的上下文来说太过分了。

希望有帮助,如果您有任何问题,请告诉我们。

答案 1 :(得分:1)

我最终使用Crossfilter.js来快速过滤数据。这样我就不需要手动保留数据集的简化副本。我可以在每次拖动和缩放事件上快速过滤它。感谢所有回答的人。

答案 2 :(得分:0)

我如何解决这个问题只是在用户进行平移/缩放时更新可见的svg元素。

function pointInDomain(d, domain) {
    return d.x < domain[1] && d.x > domain[0]
}

function zoomed() {
  xz = d3.event.transform.rescaleX(x);
  xGroup.call(xAxis.scale(xz));

  var domain = xz.domain();

  clippedArea.selectAll("circle")
    .style("visibility", d => pointInDomain(d, domain) ? "visible" : "hidden")
    .filter(d => pointInDomain(d, domain))
    .attr("cx", d => xz(d.x));
}

JSFiddle