HTML5画布与SVG与div


476

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

我了解HTML5提供了三个使之成为可能的元素:svgcanvasdiv。对于我想做什么,这些元素中的哪一个将提供最佳性能?

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


13
您可能会发现这很有趣:关于何时使用Canvas和SVG的想法
罗伯茨2011年

1
对于本技术的新手,该视频涵盖SVG和Canvas以及有关如何在html5上集成的其他详细信息。
Paulo Bueno 2012年

12
简短的答案:画布用于MS Paint,就像SVG用于MS Powerpoint。画布是栅格,SVG是矢量。
GetFree 2014年

2
亲爱的读者:带着一点点的兴趣在这里进行所有比较和陈述,并查看发布和评论的日期。时代已经改变,并且将会改变。相对性能,甚至您拥有的选项都会改变。例如,大多数答案是在没有WebGL的情况下写的,这绝对是另一种选择-几年后它也会过时,但到今天为止,它可能已经很重要了。
塞巴斯蒂安'18

@Sebastian,您今天推荐哪一个?如果给定基本大小(例如1280x800),并且您愿意一直在代码中手动缩放元素或始终使用百分比,那么SVG相对于使用DIV是否有优势?
Crashalot

Answers:


563

简短的答案:

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

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

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


长答案:

HTML5 Canvas只是位图的绘图表面。您设置进行绘制(用颜色和线条粗细说),绘制该东西,然后Canvas不知道该东西:它不知道它在哪里或刚刚绘制的是什么,它是只是像素。如果要绘制矩形并使其移动或可以选择,则必须从头开始编写所有代码,包括要记住已绘制矩形的代码。

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

这些SVG DOM参考意味着处理您绘制的事物的一些步法工作已为您完成。渲染非常大的对象时,SVG更快,但是渲染许多对象时,SVG则更慢。

在Canvas中,游戏可能会更快。大型地图程序在SVG中可能会更快。如果你想用画布,我对获得可移动物体和运行一些教程在这里

对于更快的事物和繁重的位图操作(例如动画),Canvas会更好,但是如果您需要大量的交互性,Canvas将需要更多的代码。

我在用HTML DIV绘制的图形和通过Canvas绘制的图形上运行了大量数字。我可以就每种产品的优势发表大量文章,但我将给出一些测试相关结果,以供您针对特定应用进行考虑:

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

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

HTML测试标签花费了很多时间(时间略少于5分钟,chrome要求第一次杀死该页面)。Chrome的任务管理器说该标签占用了168MB。当我查看时,它占用12-13%的CPU时间,当我不查看时,它占用0%的CPU时间。

“画布”选项卡在一秒钟内加载,占用30MB。不管是否有人看,它一直都在占用CPU时间的13%。(2013编辑:他们基本上已经解决了这个问题)

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

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

结论:

  • SVG可能更适合于项目较少的应用程序和应用程序(少于1000个?取决于实际情况)
  • Canvas对于成千上万的对象和仔细的操作来说是更好的选择,但是要使它投入使用,还需要更多的代码(或库)。
  • HTML Divs笨拙且无法缩放,仅可以使用圆角制作一个圆形,可以制作复杂的形状,但涉及数百个微小的像素级div。疯狂随之而来。

4
蛋糕库是在画布上做移动物体和动画与物体的另一个例子
SiggyF

错误的:P div可以缩放,如果浏览器使用硬件加速CSS引擎,css艺术就不同了,除了Canvas和SVG是这里的正确选择,CSS art / div art只是当您不需要过度杀伤一个小的覆盖层时:P
ShrekOverflow 2012年

关于DIV,如果您想制作圆形/特殊形状并且不打算适当地更改其图像/精灵,则可以只创建一个PNG并将其用作background-image...尽管您可以在SVG /画布中做类似的事情
luiges90

4
如果要创建交互式地图游戏该怎么办?:p
Anthony

这是使用(非嵌套)DIV和CSS 3D转换创建的,因此我想说DIV一点也不慢:youtube.com/watch?
v

39

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

我发现在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);

2
在拼命让Canvas为我们工作之后,我们也选择了SVG。我们有一个非常大的图表,而SVG是迄今为止效率最高的,此外,视网膜屏幕上的自动缩放功能是一大优势。
Fijjit,2015年

knut和@Fijjit您是否考虑使用DIV而不是SVG?如果给定基本尺寸(例如1280x800),您是否不能手动缩放DIV,使它们看起来像SVG一样清晰?谢谢你的帮助!
Crashalot

24

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

帆布

SVG

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

8
人们为什么说Canvas取决于分辨率?我知道,一旦渲染了位图,它就无法很好地缩放。但是您可以重新绘制分辨率大小的更改,那么分辨率又是如何独立的呢?
Alex Bollbach '17

@AlexBollbach-画布取决于分辨率,因为您需要考虑(取决于)分辨率才能获得良好的效果。使用SVG,您无需担心分辨率。祝您好运,在2400DPI打印机和基于Canvas的渲染上获得不锯齿的线条。SVG没问题。
塞巴斯蒂安

18

我同意Simon Sarris的结论:

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

使用SVG处理事件当然要容易得多,因为您可以将事件附加到对象上。在“画布”中,您必须手动进行操作(检查鼠标位置等),但是对于简单的交互而言,这并不难。

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

以下是一些有趣的基准:


17

关于divs选项,只有2美分。

著名/臭名昭著和SamsaraJS(可能还有其他)使用绝对定位的非嵌套div(具有非琐碎的HTML / CSS内容),结合matrix2d / matrix3d进行定位和2D / 3D转换,并在中等移动硬件上实现稳定的60FPS ,因此我反对divs是一个缓慢的选择。

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


14

尽管上面的大多数答案仍然有些道理,但我认为它们值得更新:

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

在当今大多数用例中,恕我直言,SVG提供了最佳的性能/可用性比。可视化必须非常复杂(就元素数量而言),同时又必须非常简单(每个元素),以便Canvas甚至更多,WebGL才能真正发挥作用。

回答类似问题时,我提供了更多详细信息,为什么我认为有时将这三种技术结合起来是您最好的选择。


Unix用户应注意,Firefox和Chromium均默认禁用硬件加速,这在2019
。– NVRM

@NVRM-这是关于CSS和SVG的硬件加速,而不是视频解码。AFAIK前者已经使用了多年:检查chrome:// gpu的输出
Sebastian

layers.acceleration.force-enabled在Firefox中与视频解码无关。这是众所周知的事实。完成循环时,使用requestAnimationFrame是另一个级别,从而可以进行更多重绘。与视频完全无关。
NVRM

@NVRM-您能否提供Linux上这些GPU问题的FF和Chromium错误链接?另外请注意,通过“硬件加速”我不仅指的是GPU加速,而且多线程的合成和动画,就像是守虽然没有JavaScript的运行旋转或如装载微调,而正在执行JS。对于Canvas而言,这是不可能的,相对于纯“ JavaScript”而言,确实是某种硬件加速(多线程),在所有平台上的Chrome和FF中都绝对可以使用。谢谢!
塞巴斯蒂安

1
总结当前情况:适用于Chrome和Chromium。在Linux上。在2019年。在所有实例上,我都进行了特殊配置的测试。Firefox / Mozilla正在Linux上运行它,但是,进程外渲染对于FF来说也不是什么新鲜事,并且与SVG,CSS等相比,始终可以比Canvas更好地工作。
塞巴斯蒂安

13

出于您的目的,我建议您使用SVG,因为您会获得DOM事件,例如包含鼠标操作(包括拖放)在内的DOM事件,因此您不必实现自己的重绘,也不必跟踪状态。你的对象。当您需要进行位图图像处理时,请使用Canvas;而当您要处理用HTML创建的内容时,请使用常规div。关于性能,您会发现现代浏览器现在正在加速这三种浏览器,但是到目前为止,canvas是最受关注的。另一方面,JavaScript编写的好坏对于使画布发挥最大性能至关重要,因此我仍然建议您使用SVG。


1
实际上,与CSS图像结合使用纯HTML效果最佳。
雷诺斯2011年

16
@Raynos:来源?
Janus Troelsen

3

在谷歌搜索时,我在http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html中找到了有关SVGCanvas的使用和压缩的很好的解释。

希望能帮助到你:

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

因此,canvas是比SVG更底层的限制性API。但这有一个缺点,那就是使用画布您可以用相同的资源量执行更多操作。因为浏览器不必创建和维护我们绘制的所有对象的内存对象图,所以它需要更少的内存和计算资源即可绘制相同的视觉场景。如果您要绘制非常大而复杂的可视化效果,则Canvas可能是您的理想选择。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.