ChatGPT解决这个技术问题 Extra ChatGPT

HTML5 Canvas vs. SVG vs. div

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

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

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

对于那些不熟悉此技术的人,本video涵盖了 SVG 和 Canvas 以及有关如何将其集成到 html5 的其他详细信息。
简短的回答:Canvas 之于 MS Paint,就像 SVG 之于 MS Powerpoint。画布是光栅,SVG 是矢量。
亲爱的读者:对这里的所有比较和陈述持保留态度,并查看帖子和评论的日期。时代变了,也会变。相对性能甚至您拥有的选项都会改变。例如,大多数答案都是在没有 WebGL 的情况下编写的,这绝对是一种替代方案——它也会在几年内过时,但截至今天它可能非常相关。
@Sebastian 您今天会推荐哪个?如果给定一个基本尺寸(例如,1280x800),并且如果您愿意在代码中手动缩放元素或一直使用百分比,那么使用 DIV 是否有 SVG 的优势?
@Crashalot - 没有单一的最佳解决方案。请参阅下面的回答和 here 以获得更多评论。如果您只需要几个矩形或圆形矩形,那么 div 就可以了。我更喜欢 SVG,因为它比 div 简单、明确(坐标和对 CSS 更改的免疫)。当然,复杂的文本渲染使用 HTML 更容易。如果只是矩形(但有数万个),WebGL 值得一看,否则就大材小用了。

S
Simon Sarris

简短的回答:

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

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

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

长答案:

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

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

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

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

画布对于更快的事情和繁重的位图操作(如动画)会更好,但如果你想要大量的交互性,它将需要更多的代码。

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

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

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

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

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

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

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

结论:

SVG 可能更适合项目很少的应用程序和应用程序(少于 1000 个?真的取决于)

Canvas 更适合成千上万的对象和仔细的操作,但需要更多的代码(或库)才能让它落地。

HTML div 很笨重且无法缩放,只能用圆角制作圆形,制作复杂的形状是可能的,但涉及数百个微小的像素宽 div。疯狂随之而来。


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

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

我发现在我的 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 一样清晰吗?感谢您的帮助!
C
Ciro Santilli Путлер Капут 六四事

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

帆布

取决于分辨率

不支持事件处理程序

文本渲染能力差

您可以将生成的图像保存为 .png 或 .jpg

非常适合图形密集型游戏

SVG

独立于分辨率

支持事件处理程序

最适合具有大渲染区域的应用程序(谷歌地图)

如果复杂则渲染缓慢(任何使用 DOM 的东西都会很慢)

不适合游戏应用


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

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

多年来,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 来说也不是什么新鲜事,而且总是比 Canvas 更好地处理 SVG、CSS 等。
@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 到底有多真实?
Ü
Ümit

我同意 Simon Sarris 的结论:

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

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

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

以下是一些有趣的基准:

http://svbreakaway.info/tp.php#jan21a

http://www.eleqtriq.com/2010/02/canvas-svg-flash/

http://smus.com/canvas-vs-svg-performance/


E
Erik Kaplun

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

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

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


G
Gaurav

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


实际上,使用纯 HTML 与 CSS 图像相结合是最高效的。
A
Alireza Fattahi

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

希望能帮助到你:

SVG 和 HTML 一样,使用保留渲染:当我们想在屏幕上绘制一个矩形时,我们在 DOM 中声明式地使用一个元素。然后浏览器将绘制一个矩形,但它也会在内存中创建一个表示该矩形的 SVGRectElement 对象。这个对象是我们可以操纵的东西——它被保留了。随着时间的推移,我们可以为其分配不同的位置和大小。我们还可以附加事件侦听器以使其具有交互性。 Canvas 使用立即渲染:当我们绘制一个矩形时,浏览器会立即在屏幕上渲染一个矩形,但永远不会有任何“矩形对象”来表示它。画布缓冲区中只有一堆像素。我们不能移动矩形。我们只能再画一个矩形。我们无法响应矩形上的点击或其他事件。我们只能响应整个画布上的事件。所以 canvas 是一个比 SVG 更底层、更严格的 API。但有一个反面,那就是使用画布,你可以用相同数量的资源做更多的事情。因为浏览器不必创建和维护我们绘制的所有事物的内存对象图,它需要更少的内存和计算资源来绘制相同的视觉场景。如果您要绘制非常大且复杂的可视化效果,Canvas 可能是您的选择。


H
Hg0428

他们都有好事和坏事,所以让我们在下面进行比较。

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.rectctx.fill,改用 ctx.fillRect,这是最大的一个,即使是最简单的游戏也会毁掉。不要使用带有 fillstroke 的形状,而是使用 fill[Shape]

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