HTML5 Canvas vs. SVG vs. div

ver*_*rdy 456 javascript html5 svg html5-canvas

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

我知道HTML5提供了三个可以实现这一目标的元素:svg,canvasdiv.对于我想要做的事情,哪一个元素将提供最佳性能?

为了比较这些方法,我考虑创建三个视觉上相同的网页,每个网页都有页眉,页脚,小部件和文本内容.第一页中的小部件将完全使用canvas元素创建,第二个完全使用svg元素创建,第三个使用plain div元素HTML和CSS创建.

Sim*_*ris 546

简短的回答:

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

资料核实是不错,但笨重,具有可怕的大量性能负载.

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


答案很长:

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

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

那些SVG DOM参考意味着处理你绘制的东西的一些步法是为你完成的.渲染非常大的对象时SVG速度更快,渲染许多对象时速度更慢.

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

Canvas对于更快的事物和繁重的位图操作(如动画)会更好,但如果你想要很多交互性,它会占用更多的代码.

我在HTML DIV制作的绘图和Canvas制作的绘图上运行了一堆数字.我可以发表一篇关于每个问题的好处的帖子,但是我会根据您的具体应用考虑我的测试的一些相关结果:

我制作了Canvas和HTML DIV测试页面,两者都有可移动的"节点".Canvas节点是我创建的对象,并在Javascript中跟踪.HTML节点是可移动的Div.

我在两次测试中都添加了100,000个节点.他们表现完全不同:

HTML测试选项卡需要永久加载(时间略短于5分钟,Chrome要求首次杀死页面).Chrome的任务经理表示该标签占用了168MB.当我看着它时占用12-13%的CPU时间,当我不看时它占用0%.

"画布"选项卡在一秒钟内加载,占用30MB.它总是占用CPU时间的13%,无论是否正在查看它.(2013年编辑:他们大多修复了)

在HTML页面上拖动更加平滑,这是设计所期望的,因为当前设置是在Canvas测试中每30毫秒重绘一次.Canvas有很多优化可供选择.(画布失效是最简单的,也是裁剪区域,选择性重绘等等.只取决于你实现的感觉)

毫无疑问,你可以让Canvas在对象操作中更快地成为那个简单测试中的div,当然在加载时间里要快得多.Canvas中的绘图/加载速度更快,并且具有更多的优化空间(即,排除屏幕外的内容非常容易).

结论:

  • SVG可能更适用于少量项目的应用程序和应用程序(少于1000个?真的取决于)
  • 对于成千上万的对象和仔细操作,Canvas更好,但需要更多的代码(或库)来实现它.
  • HTML Divs很笨重,不能缩放,只能使用圆角来制作圆形,这使得复杂的形状成为可能,但涉及数百个微小的像素范围的div.疯狂随之而来.

  • [Cake](http://code.google.com/p/cakejs/)库是另一个使用画布上的对象执行可移动对象和动画的示例 (4认同)
  • 如果您正在创建交互式地图游戏,该怎么办?:p (3认同)

knu*_*nut 38

为了补充这一点,我一直在做一个图表应用程序,最初开始使用canvas.该图由许多节点组成,它们可以变得非常大.用户可以拖动图中的元素.

我发现在我的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);
Run Code Online (Sandbox Code Playgroud)

  • 在拼命让Canvas为我们工作之后,我们也确定了SVG.我们有一个非常大的图表和SVG是目前最有效的,加上视网膜屏幕上的自动缩放是一个巨大的奖金. (2认同)

Leo*_*our 23

了解SVG和Canvas之间的差异将有助于选择正确的.

帆布

  • 取决于分辨率
  • 不支持事件处理程序
  • 文本呈现能力差
  • 您可以将生成的图像另存为.png或.jpg
  • 非常适合图形密集型游戏

SVG

  • 决议独立
  • 支持事件处理程序
  • 最适合具有大渲染区域的应用程序(谷歌地图)
  • 缓慢渲染,如果复杂(任何使用DOM的东西都会很慢)
  • 不适合游戏应用

  • 为什么人们说Canvas依赖于分辨率?据我所知,一旦渲染了位图,它就无法很好地扩展.但你可以重新绘制分辨率大小的变化,那么这个分辨率怎么不独立呢? (7认同)
  • @AlexBollbach - Canvas 依赖于分辨率,因为您需要考虑(依赖)分辨率才能获得良好的结果。使用 SVG,您不关心分辨率。祝你在 2400DPI 打印机和基于 Canvas 的渲染上获得非锯齿线。SVG 没有问题。 (3认同)

Ümi*_*mit 18

我同意Simon Sarris的结论:

我将Protovis(SVG)中的一些可视化与Processingjs(Canvas)进行了比较,后者显示> 2000点,处理js比protovis快得多.

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

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

以下是一些有趣的基准测试:


Eri*_*lun 16

关于div选项只需2美分.

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

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


Seb*_*ian 14

虽然上面的大部分答案仍有一些道理,但我认为它们值得更新:

多年来,SVG的性能已经有了很大提高,现在有了硬件加速的CSS转换和SVG动画,完全不依赖于JavaScript性能.当然,JavaScript性能也得到了提升,Canvas的性能也得到了提升,但没有SVG得到改进的那么多.此外,该块上还有一个"新手",几乎所有浏览器都可以使用它,也就是WebGL.使用Simon上面使用的相同单词:它击败了Canvas和SVG.然而,这并不意味着它应该是首选技术,因为它是一个可以使用的野兽,它在非常具体的用例中更快.

对于大多数用例来说,恕我直言,SVG提供了最佳的性能/可用性比率.可视化需要非常复杂(关于元素的数量)并且同时非常简单(每个元素),因此Canvas甚至更加如此WebGL真正闪耀.

这个类似问题的答案中,我提供了更多详细信息,为什么我认为所有这三种技术的组合有时是您的最佳选择.


Gau*_*rav 13

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

  • @Raynos:来源? (15认同)

Hg0*_*428 5

它们都有好的地方,也有不好的地方,下面我们就来比较一下。

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

分区:

    • 很好的表现
    • 您可以使用 DOM 来操作它
    • 您可以访问 DOM 事件
    • CSS 支持
    • 很难制作复杂的形状

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

帆布:

    • 更好的形状支持
    • 很好的表现;很好的绩效
    • 强大的浏览器支持
    • 没有CSS

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

SVG:

    • 更好的形状支持
    • 较难使用
    • 良好的浏览器支持
    • 没有 CSS,但是有很多不同的 SVG 东西
    • 表现不佳

我还没有对此进行性能测试,但根据其他测试,它不好。

要使 Canvas 更快:

Canvas 可以具有非常动态的性能,所以让我们回顾一下一些技巧。避免使用ctx.rectand ctx.fill,而是使用ctx.fillRect,这是最大的一个,它甚至会毁掉最简单的游戏。不要使用带有fill和 的形状strokefill[Shape]而是使用。

如果您不记得使用画布时,您的游戏将会非常慢。我从经验中学到了这一点。