【问题标题】:HTML5 Canvas vs. SVG vs. divHTML5 Canvas vs. SVG vs. div
【发布时间】:2011-08-18 11:17:39
【问题描述】:

动态创建元素并能够移动它们的最佳方法是什么?例如,假设我想创建一个矩形、圆形和多边形,然后选择这些对象并移动它们。

我了解 HTML5 提供了三个元素来实现这一点:svgcanvasdiv。对于我想做的事情,其中​​哪一个元素将提供最佳性能?

为了比较这些方法,我正在考虑创建三个外观相同的网页,每个网页都有页眉、页脚、小部件和文本内容。第一个页面中的小部件将完全使用canvas 元素创建,第二个完全使用svg 元素创建,第三个使用纯div 元素、HTML 和CSS。

【问题讨论】:

  • 你可能会觉得这很有趣:Thoughts on when to use Canvas and SVG.
  • 对于那些刚接触此技术的人,video 涵盖了 SVG 和 Canvas 以及有关如何与 html5 集成的其他详细信息。
  • 简答:Canvas 之于 MS Paint 就像 SVG 之于 MS Powerpoint。画布是光栅,SVG 是矢量。
  • 亲爱的读者:对这里的所有比较和陈述持保留态度,并查看帖子和 cmets 的日期。时代变了,也会变。相对性能甚至您拥有的选项都会改变。例如。大多数答案都是在没有 WebGL 时编写的,这绝对是一种替代方案 - 它也会在几年内过时,但截至今天它可能非常相关。
  • @Sebastian 今天你会推荐哪个?如果给定一个基本尺寸(例如 1280x800),并且如果您愿意在代码中手动缩放元素或一直使用百分比,那么使用 DIV 是否有 SVG 的优势?

标签: javascript html svg html5-canvas


【解决方案1】:

简短的回答:

SVG 对您来说更容易,因为已经内置了选择和移动它。SVG 对象是 DOM 对象,因此它们具有“点击”处理程序等。

DIV 还可以,但很笨重,并且在大量加载时性能糟糕

Canvas 具有最好的性能,但您必须自己实现托管状态(对象选择等)的所有概念,或者使用库。


长答案:

HTML5 Canvas 只是位图的绘图表面。您设置要绘制(例如用颜色和线条粗细),绘制那个东西,然后 Canvas 不知道那个东西:它不知道它在哪里,也不知道您刚刚绘制的是什么,它是只是像素。如果您想绘制矩形并让它们四处移动或可选择,那么您必须从头开始编写所有这些代码,包括代码以记住您绘制了它们。

另一方面,SVG 必须维护对其呈现的每个对象的引用。您创建的每个 SVG/VML 元素都是 DOM 中的真实元素。默认情况下,这使您可以更好地跟踪您创建的元素,并使默认情况下处理鼠标事件等事情变得更容易,但是当有大量对象时它会显着减慢

那些 SVG DOM 引用意味着处理您绘制的东西的一些步骤是为您完成的。并且 SVG 在渲染 非常大 对象时速度更快,但在渲染 许多 对象时速度较慢。

在 Canvas 中游戏可能会更快。一个巨大的地图程序在 SVG 中可能会更快。如果您确实想使用 Canvas,我有一些关于启动和运行可移动对象的教程here

Canvas 更适合更快的事情和繁重的位图操作(如动画),但如果您想要大量的交互性,则需要更多的代码。

我在 HTML DIV 制作的绘图与 Canvas 制作的绘图上运行了一堆数字。我可以发表一篇关于每种方法的好处的大文章,但我会给出一些相关的测试结果,以供您针对您的特定应用考虑:

我制作了 Canvas 和 HTML DIV 测试页面,它们都有可移动的“节点”。画布节点是我在 Javascript 中创建并跟踪的对象。 HTML 节点是可移动的 Div。

我为我的两个测试中的每一个添加了 100,000 个节点。他们的表现截然不同:

HTML 测试选项卡需要很长时间才能加载(时间略低于 5 分钟,chrome 首次要求终止该页面)。 Chrome 的任务管理器说该选项卡占用了 168MB。看的时候占 CPU 时间的 12-13%,不看的时候占 0%。

Canvas 选项卡在一秒钟内加载完毕,占用 30MB。它也一直占用 13% 的 CPU 时间,无论是否有人在看它。 (2013 年编辑:他们大多已修复)

在 HTML 页面上拖动更流畅,这是设计所期望的,因为当前设置是在 Canvas 测试中每 30 毫秒重绘所有内容。为此,Canvas 有很多优化。 (画布失效是最简单的,还有剪裁区域、选择性重绘等。只是取决于你想要实现的程度)

毫无疑问,您可以让 Canvas 在对象操作方面像该简单测试中的 div 一样更快,当然在加载时间上也快得多。 Canvas 中的绘图/加载速度更快,并且还有更大的优化空间(即,排除屏幕外的内容非常容易)。

结论:

  • SVG 可能更适合具有少量项目(少于 1000 个?真的取决于)的应用程序和应用程序
  • Canvas 更适合数千个对象和仔细的操作,但需要更多代码(或库)才能让它落地。
  • HTML div 很笨重且无法缩放,只能用圆角制作圆形,可以制作复杂的形状,但需要数百个微小的像素宽度的 div。疯狂随之而来。

【讨论】:

  • Cake 库是另一个使用画布上的对象制作可移动对象和动画的示例
  • 错误 :P div 可以缩放,如果浏览器使用硬件加速 CSS 引擎,css 艺术是不同的,除了 Canvas 和 SVG 是正确的选择,CSS 艺术 / div 艺术只是当你不需要过度杀伤只是一个小的覆盖:P
  • 关于DIV,如果你想制作圆形/特殊形状并且不打算改变它的图像/精灵,你可以创建一个PNG并将其用作background-image...虽然你可以在 SVG/Canvas 中做类似的事情
  • 如果您正在创建交互式地图游戏怎么办? :p
  • 这是使用(非嵌套)DIV 和 CSS 3D 转换创建的,所以我想说 DIV 一点也不慢:youtube.com/watch?v=fzBC20B5dsk
【解决方案2】:

此外,我一直在做一个图表应用程序,最初是从画布开始的。该图由许多节点组成,它们可以变得很大。用户可以拖动图表中的元素。

我发现在我的 Mac 上,对于非常大的图像,SVG 更胜一筹。我有一台 MacBook Pro 2013 13" Retina,它在下面的小提琴运行得很好。图像是 6000x6000 像素,有 1000 个对象。当用户在图。

在现代显示器上,您还必须考虑不同的分辨率,而 SVG 在这里免费为您提供所有这些。

小提琴:http://jsfiddle.net/knutsi/PUcr8/16/

全屏:http://jsfiddle.net/knutsi/PUcr8/16/embedded/result/

var wiggle_factor = 0.0;
nodes = [];

// create svg:
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('style', 'border: 1px solid black');
svg.setAttribute('width', '6000');
svg.setAttribute('height', '6000');

svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink",
    "http://www.w3.org/1999/xlink");

document.body.appendChild(svg);


function makeNode(wiggle) {
    var node = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var node_x = (Math.random() * 6000);
    var node_y = (Math.random() * 6000);
    node.setAttribute("transform", "translate(" + node_x + ", " + node_y +")");

    // circle:
    var circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    circ.setAttribute( "id","cir")
    circ.setAttribute( "cx", 0 + "px")
    circ.setAttribute( "cy", 0 + "px")
    circ.setAttribute( "r","100px");
    circ.setAttribute('fill', 'red');
    circ.setAttribute('pointer-events', 'inherit')

    // text:
    var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.textContent = "This is a test! ÅÆØ";

    node.appendChild(circ);
    node.appendChild(text);

    node.x = node_x;
    node.y = node_y;

    if(wiggle)
        nodes.push(node)
    return node;
}

// populate with 1000 nodes:
for(var i = 0; i < 1000; i++) {
    var node = makeNode(true);
    svg.appendChild(node);
}

// make one mapped to mouse:
var bnode = makeNode(false);
svg.appendChild(bnode);

document.body.onmousemove=function(event){
    bnode.setAttribute("transform","translate(" +
        (event.clientX + window.pageXOffset) + ", " +
        (event.clientY + window.pageYOffset) +")");
};

setInterval(function() {
    wiggle_factor += 1/60;
    nodes.forEach(function(node) {

        node.setAttribute("transform", "translate(" 
                          + (Math.sin(wiggle_factor) * 200 + node.x) 
                          + ", " 
                          + (Math.sin(wiggle_factor) * 200 + node.y) 
                          + ")");        
    })
},1000/60);

【讨论】:

  • 在拼命尝试让 Canvas 为我们工作之后,我们也选择了 SVG。我们有一个非常大的图表,而 SVG 是迄今为止最有效的,而且视网膜屏幕上的自动缩放是一个巨大的好处。
  • knut 和@Fijjit 您是否考虑过使用 DIV 而不是 SVG?如果给定一个基本尺寸(例如 1280x800),您不能手动缩放 DIV 以使它们看起来像 SVG 一样清晰吗?感谢您的帮助!
【解决方案3】:

了解 SVG 和 Canvas 之间的区别将有助于选择正确的。

画布

SVG

  • 独立于分辨率
  • 支持事件处理程序
  • 最适合具有大渲染区域的应用程序(Google 地图)
  • 如果复杂,渲染速度会很慢(任何经常使用 DOM 的东西都会 慢)
  • 不适合游戏应用

【讨论】:

  • 为什么人们说 Canvas 依赖于分辨率?我知道一旦位图被渲染,它就不能很好地缩放。但是你可以重绘分辨率大小的变化,那么这个分辨率怎么不是独立的呢?
  • @AlexBollbach - 画布依赖于分辨率,因为您需要考虑(依赖)分辨率才能获得良好的结果。使用 SVG,您不必关心分辨率。祝您在 2400DPI 打印机和基于 Canvas 的渲染上获得非锯齿线。 SVG 没问题。
【解决方案4】:

虽然上述大多数答案仍有一些道理,但我认为它们值得更新:

多年来,SVG 的性能有了很大提高,现在 SVG 的硬件加速 CSS 过渡和动画完全不依赖于 JavaScript 性能。当然,JavaScript 的性能也得到了提升,Canvas 的性能也随之提升,但不如 SVG 的提升那么多。还有一个“新手”,现在几乎所有浏览器都可以使用,那就是 WebGL。使用 Simon 上面使用的相同词:它击败了 Canvas 和 SVG。不过,这并不意味着它应该是首选技术,因为它是一种可以使用的野兽,而且它只在非常特定的用例中速度更快。

恕我直言,对于当今的大多数用例,SVG 提供了最佳的性能/可用性比。可视化需要非常复杂(相对于元素的数量)并且同时非常简单(每个元素),这样 Canvas 甚至 WebGL 才能真正发光。

this answer to a similar question 中,我提供了更多详细信息,为什么我认为结合所有三种技术有时是您拥有的最佳选择。

【讨论】:

  • Unix 用户应该注意,Firefox 和 Chromium 上默认禁用硬件加速,到 2019 年中期仍然如此。
  • @NVRM - 这是关于 CSS 和 SVG 的硬件加速,而不是关于视频解码。 AFAIK 前者已存在多年:Check output of chrome://gpu
  • Firefox 中的 layers.acceleration.force-enabled 与视频解码无关。这是众所周知的事实。使用 requestAnimationFrame 完成循环是另一个级别,允许更多重绘。根本与视频无关。
  • 总结目前的情况:在 Chrome 和 Chromium 上为我工作。在 Linux 上。在 2019 年。在我测试的所有实例上,都没有进行特殊配置。 Firefox/Mozilla 是 working on it for Linux,但是进程外渲染对于 FF 来说也不是什么新鲜事,而且在 SVG、CSS 等方面总是比在 Canvas 上更好。
  • @Sebastian 谢谢,我阅读了blog in your other answer,但它仅在一个“复杂”测试用例中显示 SVG 比 Canvas 更快,他们说:where only simple... ...the performance of Canvas is actually better if you have lots and lots of elements on the screen at the same time. 这是我见过的最好的调查互动演示非常棒!尽管我自己进行了测试,但在复杂情况下我看不出 svg/canvas 之间有多大区别,所以我仍然想知道 SVG 能胜过 canvas 到底有多真实?
【解决方案5】:

我同意 Simon Sarris 的结论:

我将 Protovis (SVG) 中的一些可视化与 Processingjs (Canvas) 进行了比较,后者显示 > 2000 个点,并且 processingjs 比 protovis 快得多。

使用 SVG 处理事件当然要容易得多,因为您可以将它们附加到对象上。在 Canvas 中,您必须手动完成(检查鼠标位置等),但对于简单的交互,它应该不难。

还有道场工具包的dojo.gfx 库。它提供了一个抽象层,您可以指定渲染器(SVG、Canvas、Silverlight)。这可能也是一个可行的选择,尽管我不知道额外的抽象层增加了多少开销,但它使编写交互和动画变得容易,并且与渲染器无关。

以下是一些有趣的基准:

【讨论】:

    【解决方案6】:

    关于 divs 选项只需我的 2 美分。

    Famous/Infamous 和 SamsaraJS(可能还有其他)使用绝对定位的非嵌套 div(具有非平凡的 HTML/CSS 内容),结合 matrix2d/matrix3d 进行定位和 2D/3D 转换,并在适度的移动硬件,所以我反对 div 是一个缓慢的选择。

    在 Youtube 和其他地方有大量屏幕录像,高性能 2D/3D 内容在浏览器中运行,所有内容都是 DOM 元素,您可以在 60FPS(混合使用 WebGL 获得某些效果,但不适用于渲染的主要部分)。

    【讨论】:

      【解决方案7】:

      出于您的目的,我建议您使用 SVG,因为您可以获得 DOM 事件,例如鼠标处理,包括拖放,您不必实现自己的重绘,也不必跟踪你的对象的状态。当您必须进行位图图像操作时使用 Canvas,当您想要操作在 HTML 中创建的内容时使用常规 div。至于性能,你会发现现代浏览器现在都在加速这三个方面,但到目前为止,canvas 受到的关注最多。另一方面,如何编写好 javascript 对于使用画布获得最佳性能至关重要,因此我仍然建议使用 SVG。

      【讨论】:

      • 实际上使用纯 HTML 与 CSS 图像结合起来性能最高。
      【解决方案8】:

      在谷歌搜索时,我在http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

      找到了关于 SVGCanvas 的使用和压缩的很好的解释

      希望对你有帮助:

      • SVG 和 HTML 一样,使用保留渲染:当我们想要绘制一个 屏幕上的矩形,我们在我们的 DOM。然后浏览器将绘制一个矩形,但它也会创建 表示矩形的内存中 SVGRectElement 对象。这 对象是我们可以操纵的东西——它是 保留。随着时间的推移,我们可以为其分配不同的位置和大小。 我们还可以附加事件侦听器以使其具有交互性。
      • Canvas使用立即渲染:当我们draw a rectangle时,浏览器立即在屏幕上渲染一个矩形,但是有 永远不会是代表它的任何“矩形对象”。有 只是画布缓冲区中的一堆像素。我们无法移动 长方形。我们只能再画一个矩形。我们无法回应 矩形上的点击或其他事件。我们只能响应事件 在整个画布上。

      因此,canvas 是一种比 SVG 更底层、更严格的 API。但是有一个 与之相反的是,使用画布你可以做更多的事情 相同数量的资源。因为浏览器不必创建 并维护我们拥有的所有事物的内存对象图 绘制,它需要更少的内存和计算资源来绘制相同的 视觉场景。如果您有一个非常大且复杂的可视化 画,帆布​​可能是你的票。

      【讨论】:

        【解决方案9】:

        各有优劣,下面对比一下。

        Canvas 将具有整体最佳性能,但前提是您正确使用它。

        Divs:

          • 性能良好
          • 您可以使用 DOM 对其进行操作
          • 您可以访问 DOM 事件
          • CSS 支持
        1. 很难制作复杂的形状

        在这里进行性能测试:https://kajam.hg0428.repl.co/pref/

        画布:

          • 更好的形状支持
          • 出色的性能
          • 强大的浏览器支持
        1. 无 CSS

        在这里进行性能测试:https://js-game-engine.hg0428.repl.co/canvasTest/preform.html

        SVG:

          • 更好的形状支持
        1. 对我们来说更难
          • 良好的浏览器支持
        2. 没有 CSS,但是有很多不同的 SVG 东西
        3. 糟糕的表现

        我还没有对这个进行性能测试,但是根据其他测试,它非常糟糕。

        **

        使 Canvas 快速:

        ** Canvas 可以具有非常动态的性能,因此让我们回顾一些技巧。 避免使用ctx.rectctx.fill,改用ctx.fillRect,这是最大的一个,即使是最简单的游戏也可能会毁掉。 不要使用带有fillstroke 的形状,而是使用fill[Shape]

        如果您不记得使用画布时,您的游戏将被毁掉。这是我从经验中学到的。

        【讨论】:

          猜你喜欢
          • 2011-11-04
          • 1970-01-01
          • 2012-07-29
          • 2013-07-19
          • 2013-11-07
          • 2012-06-26
          • 2012-08-30
          • 2013-03-07
          • 2021-07-31
          相关资源
          最近更新 更多