115

我正在尝试选择正确的技术来更新一个项目,该项目基本上在可缩放、可平移的图形中呈现数千个点。当前使用 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 的,应该更擅长渲染动画。但是,我怀疑它的性能提升多少以及它的性能上限是多少。出于这个原因,我还在考虑使用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 操作与画布渲染相结合的混合体。但是,我在网上找不到太多关于此的文档,也无法与该帖子的 OP 取得联系。如果有人对这种 DOM-to-Canvas(演示代码)实现有任何经验,我也希望收到您的来信。它似乎是能够操纵数据和对如何呈现数据(以及因此性能)进行自定义控制的一个很好的混合体,但我想知道是否必须将所有内容加载到 DOM 中仍然会减慢速度。

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

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

4

5 回答 5

186

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

这些示例使用 D3 的缩放行为来实现缩放和平移。除了圆圈是用 Canvas 还是 SVG 渲染之外,另一个主要区别是您是使用几何缩放还是语义缩放。

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

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

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

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

正如这些示例所示,您可以将 D3 与 Canvas 一起使用,即使 D3 的某些部分是特定于 SVG 的。另请参阅此力导向图和此碰撞检测示例

于 2012-09-08T23:59:17.440 回答
9

我认为在你的情况下,画布和 svg 之间的决定不像是在“骑马”或驾驶“保时捷”之间做出决定。对我来说,这更像是关于汽车颜色的决定。

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

  • 画一颗星星,
  • 添加一颗星和
  • 去掉一颗星

采取线性时间。因此,如果您对框架的决定是好的,它会更快一点,否则会慢一点。

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

我想说的是,问题的根源导致了计算几何的一个基本问题,即:范围搜索和计算机图形学的另一个问题:细节层次

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

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

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

PS:在本书中,您可以找到关于网络图形、画布、SVG 和 DHTML 的技术、优缺点的非常详细的讨论。

于 2012-09-08T11:45:37.930 回答
7

我最近在一个近乎实时的仪表板(每 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 框架相同的功能。

于 2014-08-07T15:47:19.507 回答
3

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

于 2013-05-31T05:22:45.423 回答
0

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

于 2020-07-25T16:31:44.377 回答