快速响应的交互式图表/图形:SVG、Canvas 还是其他?

Posted

技术标签:

【中文标题】快速响应的交互式图表/图形:SVG、Canvas 还是其他?【英文标题】:Fast and responsive interactive charts/graphs: SVG, Canvas, other? 【发布时间】:2012-08-31 20:38:50 【问题描述】:

我正在尝试选择合适的技术来更新项目,该项目基本上在可缩放、可平移的图形中呈现数千个点。当前使用 Protovis 的实现性能不佳。在这里查看:

http://www.planethunters.org/classify

完全缩小时大约有 2000 个点。尝试使用底部的手柄放大一点,然后拖动它来平移。您会看到它非常不稳定,除非您拥有一台非常快的计算机,否则您的 CPU 使用率可能会在一个内核上达到 100%。对焦点区域的每次更改都会对 protovis 进行重绘,这非常缓慢,而且绘制的点越多越糟糕。

我想对界面进行一些更新,并更改底层的可视化技术,使其对动画和交互更加敏感。从以下文章来看,似乎是在另一个基于 SVG 的库或基于画布的库之间进行选择:

http://www.sitepoint.com/how-to-choose-between-canvas-and-svg/

d3.js,从 Protovis 发展而来,是基于 SVG 的 supposed to be better at rendering animations。但是,我怀疑它的性能提升多少以及它的性能上限是多少。出于这个原因,我也在考虑使用像KineticJS 这样的基于画布的库进行更全面的改造。但是,在我深入使用一种或另一种方法之前,我想听听有人用这么多数据完成了类似的 Web 应用程序并听取他们的意见。

最重要的是性能,其次是易于添加其他交互功能和对动画进行编程。一次可能不会超过 2000 个点,每个点上都有那些小误差线。 放大、缩小和平移需要平滑。如果最新的 SVG 库在这方面表现不错,那么使用 d3 的易用性可能会超过 KineticJS 等的增加设置。但如果使用画布有巨大的性能优势,特别是对于计算机速度较慢的人,那么我肯定更喜欢这样做。

NYTimes 制作的应用程序示例,它使用 SVG,但动画仍然可以接受地流畅: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html 。如果我能够获得这种性能并且不必编写自己的画布绘图代码,我可能会选择 SVG。

我注意到一些用户使用了d3.js manipulation combined with canvas rendering 的混合体。但是,我在网上找不到太多关于此的文档,也无法与该帖子的 OP 取得联系。如果有人对这种 DOM-to-Canvas (demo, code) 实现有任何经验,我也想听听您的意见。它似乎是能够操纵数据和对如何呈现数据(以及因此性能)进行自定义控制的一个很好的混合体,但我想知道是否必须将所有内容加载到 DOM 中仍然会减慢速度。

我知道存在一些与此类似的现有问题,但没有一个问题完全相同。感谢您的帮助。

跟进:我最终使用的实现位于https://github.com/zooniverse/LightCurves

【问题讨论】:

“最重要的是性能,其次是易于添加其他交互”+1 画布 问题是,SVG 在大多数浏览器上是否足以容纳 2k 点 + 其他图表元素?如果是这样,而且速度慢只是由于 protovis 的弱点,那么我宁愿坚持使用 SVG。 Mike Bostock 已经给出了很好的答案。有关其他信息,您可以查看以下两个资源:***.com/questions/5882716/html5-canvas-vs-svg-vs-div/…blogs.msdn.com/b/ie/archive/2011/04/22/… 跟进:我使用混合 SVG/画布方法实现了这一点,其中 SVG 负责轴和网格线,而画布可以非常快速地渲染点。速度超级快! 【参考方案1】:

我认为在你的情况中,canvas 和 svg 之间的决定不像是在 »骑马« 或驾驶 »Porsche« 之间做出决定。对我来说,这更像是关于汽车颜色的决定。

让我解释一下: 假设,基于框架的操作

画一颗星星, 添加星标并 移除星标

采用线性时间。所以,如果你对框架的决定是好的,那就快一点,否则慢一点。

如果你继续假设框架很快,那么很明显,性能不足是由大量的星星造成的,处理它们是任何框架都无法为你做的,至少我不知道这个。

我想说的是,问题的基础导致了计算几何的一个基本问题,即:range searching和另一个计算机图形学问题:level of detail。

要解决您的性能问题,您需要实现一个好的预处理器,它能够非常快速地找到要显示的星星,并且可能能够根据缩放将靠近的星星聚集在一起。使您的视图保持生动和快速的唯一方法是尽量减少要绘制的星星数量。

正如您所说,最重要的是性能,而不是我倾向于使用画布,因为它可以在没有 DOM 操作的情况下工作。它还提供了使用 webGL 的机会,从而大大提高了图形性能。

顺便说一句:你检查paper.js了吗?它使用画布,但模拟矢量图形。

PS:In this Book 你可以找到关于网络图形、技术、画布、SVG 和 DHTML 的优缺点的非常详细的讨论。

【讨论】:

【参考方案2】:

幸运的是,绘制 2000 个圆圈是一个非常容易测试的示例。所以这里有四种可能的实现方式,Canvas 和 SVG 各两种:

Canvas geometric zooming Canvas semantic zooming SVG geometric zooming SVG semantic zooming

这些示例使用 D3 的 zoom behavior 来实现缩放和平移。除了圆圈是用 Canvas 还是 SVG 呈现之外,另一个主要区别是您是使用 geometric 还是 semantic 缩放。

几何缩放意味着您将单个变换应用于整个视口:当您放大时,圆圈会变大。对比的语义缩放意味着您对每个圆圈单独应用变换:当您放大时,圆圈保持相同的大小,但它们会散开。 Planethunters.org 目前使用语义缩放,但考虑其他情况可能会有用。

几何缩放简化了实现:您应用一次平移和缩放,然后重新渲染所有圆圈。 SVG 的实现特别简单,只更新了一个“transform”属性。两个几何缩放示例的性能都感觉绰绰有余。对于语义缩放,您会注意到 D3 比 Protovis 快得多。这是因为它为每个缩放事件做的工作要少得多。 (Protovis 版本必须重新计算所有元素的所有属性。)基于 Canvas 的语义缩放比 SVG 更灵活一些,但 SVG 语义缩放仍然感觉反应灵敏。

然而,性能并没有灵丹妙药,这四种可能的方法并没有开始涵盖所有可能性。例如,您可以结合几何缩放和语义缩放,使用几何平移(更新“变换”属性)的方法,仅在缩放时重绘单个圆圈。您甚至可以将这些技术中的一种或多种与 CSS3 转换结合起来以添加一些硬件加速(如在 hierarchical edge bundling example 中),尽管这可能很难实现并且可能会引入视觉伪影。

不过,我个人的偏好是尽可能多地保留在 SVG 中,并且在渲染成为瓶颈时仅将 Canvas 用于“内循环”。 SVG 为开发提供了如此多的便利——例如 CSS、数据连接和元素检查器——因此从 Canvas 开始通常是为时过早的优化。将 Canvas 与 SVG 结合起来,就像您链接的 Facebook IPO 可视化一样,是一种灵活的方式,可以保留大多数这些便利,同时仍能获得最佳性能。我还在Cubism.js 中使用了这种技术,其中时间序列可视化的特殊情况非常适合位图缓存。

正如这些示例所示,您可以将 D3 与 Canvas 一起使用,即使 D3 的某些部分是特定于 SVG 的。另请参阅此force-directed graph 和此collision detection example。

【讨论】:

哇,这是一个很棒的答案,而且来自可视化大师本人!我想我必须坚持语义缩放,并且在我的计算机上,基于画布的渲染器在平移/缩放时比 SVG 版本快得多(可能与浏览器实现有关?)。您所说的将 SVG 与 canvas 用作内部循环正是我想要确认的内容,代码示例只是一个甜蜜的奖励。非常感谢! 只是想在不同的浏览器上尝试语义缩放示例:Chrome,都非常快,我看不出区别; IE:SVG 稍慢; Firefox(最后一条评论):SVG 比画布慢。我想这也使决定变得有点复杂,但使画布渲染成为一个安全的选择。还有一个问题:直接使用 KineticJS 代替 canvas 会显着影响性能吗? 安德鲁,有点晚了,但这是我对 FF 的体验:它正在迎头赶上。我曾经运行 FF 15 和 D3 SVG 过渡很快就开始变慢。但是每个新版本都变得更快了。现在我在 FF 18 beta 上,它比 17 快。但不确定它是否像 chrome 一样平滑。 @AndrewMao 嗨,安德鲁,我遇到了一种情况,渲染似乎是瓶颈。我需要平移和缩放一些点和大约 6000 条曲线路径。 ***.com/questions/17907769/svg-path-rendering-speed/… 但是当 Bostock 说“尽可能多地使用 SVG,并且仅将 Canvas 用于“内循环””时,我不太理解,不过我已经看过四个例子了。你能给我一些启发吗? @kakacii 在所有浏览器中的转换速度都一样慢吗?如果是这样,我会说你要么使用了错误的代码,要么你已经达到了浏览器渲染的限制。如果您可以发布一些代码,我可能会提供帮助。 mbostock 指的是使用 SVG 来简化操作,并且仅在必要时使用画布,因为它的代码更复杂。但是 KineticJS 等库在一定程度上简化了这一点。【参考方案3】:

还可以研究 Meteor Charts,它建立在 uber fast KineticJS 框架之上:http://meteorcharts.com/

【讨论】:

【参考方案4】:

我最近开发了一个近乎实时的仪表板(每 5 秒刷新一次),并选择使用通过画布呈现的图表。

我们尝试了 Highcharts(基于 SVG 的 javascript 图表库)和 CanvasJS(基于 Canvas 的 JavaScript 图表库)。尽管 Highcharts 是一个出色的图表 API,并且提供了更多功能,但我们还是决定使用 CanvasJS。

我们需要在每个图表中显示至少 15 分钟的数据(可选择选择最多两个小时的范围)。

所以 15 分钟:900 点(每​​秒数据点)x2(折线和条形组合图)x4 图表 = 总共 7200 点。

使用 chrome profiler,CanvasJS 的内存从未超过 30MB,而 Highcharts 的内存使用量超过 600MB。

此外,刷新时间为 5 秒的 CanvasJS 渲染比 Highcharts 响应更快。

我们使用一个计时器(setInterval 5 秒)进行 4 次 REST API 调用,以从连接到 Elasticsearch 的后端服务器中提取数据。 JQuery.post() 接收到作为数据更新的每个图表。

也就是说,对于离线报告,我会使用 Highcharts,因为它的 API 更灵活。

还有声称使用 SVG 或 Canvas 但尚未研究过的 Zing 图表。

当性能非常关键时,应考虑使用画布。 SVG 的灵活性。并不是画布框架不灵活,而是画布框架需要做更多的工作才能获得与 svg 框架相同的功能。

【讨论】:

【参考方案5】:

我还发现,当我们将带有 SVG 图形的页面打印到 PDF 时,生成的 PDF 仍然包含基于矢量的图像,而如果您打印带有 Canvas 图形的页面,则生成的 PDF 文件中的图像会被光栅化。

【讨论】:

以上是关于快速响应的交互式图表/图形:SVG、Canvas 还是其他?的主要内容,如果未能解决你的问题,请参考以下文章

图形基础篇03 # 声明式图形系统:如何用SVG图形元素绘制可视化图表?

坎夫 |将 SVG 转换为 Canvas 以输出为图像

使用echarts插件做图表常见的几个问题——图形的两种渲染方式

echarts研究

有哪些用 JavaScript 实现的图形库

Echarts-ZRender源码分析