动态创建元素并能够移动它们的最佳方法是什么?例如,假设我想创建一个矩形、圆形和多边形,然后选择这些对象并移动它们。
我知道 HTML5 提供了三个可以实现这一点的元素:svg、canvas 和 div。对于我想做的事情,其中哪一个元素将提供最佳性能?
为了比较这些方法,我正在考虑创建三个视觉上相同的网页,每个网页都有页眉、页脚、小部件和文本内容。第一个页面中的小部件将完全使用 canvas
元素创建,第二个页面完全使用 svg
元素创建,第三个页面使用纯 div
元素、HTML 和 CSS。
div
就可以了。我更喜欢 SVG,因为它比 div 简单、明确(坐标和对 CSS 更改的免疫)。当然,复杂的文本渲染使用 HTML 更容易。如果只是矩形(但有数万个),WebGL 值得一看,否则就大材小用了。
简短的回答:
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。疯狂随之而来。
除此之外,我一直在做一个图表应用程序,最初是从画布开始的。该图由许多节点组成,它们可以变得很大。用户可以拖动图表中的元素。
我发现在我的 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);
了解 SVG 和 Canvas 之间的区别将有助于选择正确的。
帆布
取决于分辨率
不支持事件处理程序
文本渲染能力差
您可以将生成的图像保存为 .png 或 .jpg
非常适合图形密集型游戏
SVG
独立于分辨率
支持事件处理程序
最适合具有大渲染区域的应用程序(谷歌地图)
如果复杂则渲染缓慢(任何使用 DOM 的东西都会很慢)
不适合游戏应用
虽然上述大多数答案仍有一些道理,但我认为它们值得更新:
多年来,SVG 的性能有了很大的提高,现在有硬件加速的 CSS 过渡和动画,它们完全不依赖于 JavaScript 性能。当然,JavaScript 的性能也得到了提升,Canvas 的性能也随之提升,但没有 SVG 的提升那么多。此外,该块还有一个“新孩子”,如今几乎所有浏览器都可以使用,那就是 WebGL。使用 Simon 上面使用的相同的话:它击败了 Canvas 和 SVG。不过,这并不意味着它应该是首选技术,因为它是一种可以使用的野兽,而且它只会在非常特定的用例中更快。
恕我直言,对于当今的大多数用例,SVG 提供了最佳的性能/可用性比。可视化需要非常复杂(相对于元素的数量)并且同时非常简单(每个元素),这样 Canvas 甚至 WebGL 才能真正发光。
在 this answer to a similar question 中,我提供了更多详细信息,为什么我认为结合所有三种技术有时是您拥有的最佳选择。
layers.acceleration.force-enabled
与视频解码无关。这是众所周知的事实。使用 requestAnimationFrame 完成循环是另一个级别,允许更多重绘。根本不是关于视频的。
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 到底有多真实?
我同意 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/
只是我关于 divs 选项的 2 美分。
Famous/Infamous 和 SamsaraJS(可能还有其他)使用绝对定位的非嵌套 div(具有非平凡的 HTML/CSS 内容),结合 matrix2d/matrix3d 进行定位和 2D/3D 转换,并在中等移动硬件上实现稳定的 60FPS ,所以我反对 divs 是一个缓慢的选择。
Youtube 和其他地方有很多屏幕录像,高性能 2D/3D 内容在浏览器中运行,所有内容都是 DOM 元素,您可以在 60FPS 上检查元素(与 WebGL 混合以获得某些效果,但不适用于渲染的主要部分)。
出于您的目的,我建议使用 SVG,因为您获得了 DOM 事件,例如鼠标处理,包括拖放,您不必实现自己的重绘,也不必跟踪你的对象。当您必须进行位图图像操作时使用 Canvas,当您想要操作在 HTML 中创建的内容时使用常规 div。至于性能,你会发现现代浏览器现在都在加速这三个方面,但到目前为止,canvas 受到的关注最多。另一方面,如何编写 javascript 对于使用画布获得最佳性能至关重要,所以我仍然建议使用 SVG。
在谷歌搜索时,我在 http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html 找到了关于 SVG 和 Canvas 的使用和压缩的很好的解释
希望能帮助到你:
SVG 和 HTML 一样,使用保留渲染:当我们想在屏幕上绘制一个矩形时,我们在 DOM 中声明式地使用一个元素。然后浏览器将绘制一个矩形,但它也会在内存中创建一个表示该矩形的 SVGRectElement 对象。这个对象是我们可以操纵的东西——它被保留了。随着时间的推移,我们可以为其分配不同的位置和大小。我们还可以附加事件侦听器以使其具有交互性。 Canvas 使用立即渲染:当我们绘制一个矩形时,浏览器会立即在屏幕上渲染一个矩形,但永远不会有任何“矩形对象”来表示它。画布缓冲区中只有一堆像素。我们不能移动矩形。我们只能再画一个矩形。我们无法响应矩形上的点击或其他事件。我们只能响应整个画布上的事件。所以 canvas 是一个比 SVG 更底层、更严格的 API。但有一个反面,那就是使用画布,你可以用相同数量的资源做更多的事情。因为浏览器不必创建和维护我们绘制的所有事物的内存对象图,它需要更少的内存和计算资源来绘制相同的视觉场景。如果您要绘制非常大且复杂的可视化效果,Canvas 可能是您的选择。
他们都有好事和坏事,所以让我们在下面进行比较。
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.rect
和 ctx.fill
,改用 ctx.fillRect
,这是最大的一个,即使是最简单的游戏也会毁掉。不要使用带有 fill
和 stroke
的形状,而是使用 fill[Shape]
。
如果你不记得使用画布时,你的游戏会很慢。我从经验中学到了这一点。
不定期副业成功案例分享
background-image
...尽管您可以在 SVG/ 中做类似的事情帆布