动态创建元素并能够移动它们的最佳方法是什么?例如,假设我想创建一个矩形、圆和多边形,然后选择这些对象并移动它们。
我知道HTML5提供了三个元素来实现这一点:svg, 帆布和div。对于我想做的事情,这些元素中哪一个会提供最好的性能?
为了比较这些方法,我想创建三个视觉上相同的网页,每个网页都有一个页眉、页脚、小部件和文本内容。第一个页面中的小部件将完全使用canvas元素创建,第二个页面完全使用svg元素创建,第三个页面使用普通的div元素、HTML和CSS创建。
canvas
svg
div
出于您的目的,我建议使用SVG,因为您获得了DOM事件,如鼠标处理(包括拖放),因此您不必实现自己的重绘制,也不必跟踪对象的状态。当你必须做位图图像操作时使用Canvas,当你想操作在HTML中创建的东西时使用常规div。至于性能,你会发现现在的浏览器都在加速这三个方面,但迄今为止画布受到了最多的关注。另一方面,javascript编写得好不好是获得canvas最佳性能的关键,因此我仍然建议使用SVG。
SVG应该是更容易,因为已经内置了选择和移动它。SVG对象是DOM对象,因此它们有“点击”处理程序等。
div是可以的,但是很笨重,并且在大量加载时具有可怕的性能。
Canvas无疑具有最好的性能,但是您必须自己实现托管状态的所有概念(对象选择等),或者使用库。
HTML5 Canvas只是一个位图的绘制表面。你设置了绘制(比如用颜色和线条粗细),绘制了那个东西,然后Canvas没有那个东西的知识:它不知道它在哪里,也不知道你刚刚画的是什么,它只是像素。如果你想要绘制矩形,并让它们四处移动或可选择,那么你必须从头开始编码,包括代码来记住你画了它们。
另一方面,SVG必须维护对其呈现的每个对象的引用。您创建的每个SVG/VML元素都是DOM中的真实元素。默认情况下,这允许您更好地跟踪您创建的元素,并使处理鼠标事件等事情更容易默认,但当有大量对象时,它会显着变慢
这些SVG DOM引用意味着一些处理所绘制事物的步法已经为您完成了。SVG在呈现非常大的对象时更快,但在呈现许多对象时更慢。
在Canvas中游戏可能会更快。大型地图程序使用SVG可能会更快。如果你确实想使用画布,我有一些教程获得可移动的对象,并运行在这里。
Canvas更适合于快速的内容和重位图操作(如动画),但如果你想要大量的交互性,则需要更多的代码。
我在HTML div制作的绘图和canvas制作的绘图上运行了一堆数字。我可以写一篇关于每种方法的好处的文章,但我将给出一些相关的测试结果,以供您考虑特定的应用程序:
我制作了Canvas和HTML DIV测试页面,两者都有可移动的“节点”。Canvas节点是我在Javascript中创建并跟踪的对象。HTML节点是可移动的div。
我在两个测试中分别添加了100,000个节点。他们的表现完全不同:
HTML测试标签永远加载(时间略低于5分钟,chrome要求第一次杀死页面)。Chrome的任务管理器说这个选项卡占用了168MB。当我看着它时,它会占用12-13%的CPU时间,当我不看着它时,它会占用0%的CPU时间。
Canvas标签在一秒内加载,占用30MB。它还会一直占用13%的CPU时间,无论你是否在看它。# EYZ0
在HTML页面上拖动更流畅,这是设计所期望的,因为当前的设置是在Canvas测试中每30毫秒重绘EVERYTHING。为此,Canvas有很多优化。(画布失效是最简单的,还有剪切区域,选择性重绘等。这取决于你有多喜欢执行)
毫无疑问,在这个简单的测试中,你可以让Canvas在对象操作上更快,当然在加载时间上也更快。在Canvas中绘制/加载更快,也有更多的优化空间(也就是说,排除屏幕外的东西是非常容易的)。
我同意Simon Sarris的结论:
我比较了Protovis (SVG)和Processingjs (Canvas)中的一些可视化,后者显示> 2000点,Processingjs比Protovis快得多。
使用SVG处理事件当然要容易得多,因为您可以将它们附加到对象上。在Canvas中,你必须手动操作(检查鼠标位置等),但对于简单的交互来说,这应该不难。
还有dojo工具包的dojo.gfx库。它提供了一个抽象层,你可以指定渲染器(SVG、Canvas、Silverlight)。这可能也是一个可行的选择,尽管我不知道额外的抽象层增加了多少开销,但它使编码交互和动画变得容易,并且与渲染器无关。
以下是一些有趣的基准测试:
为了补充这一点,我一直在做一个图表应用程序,最初是从画布开始的。该图由许多节点组成,而且它们可以变得相当大。用户可以在图中拖动元素。
我发现,在我的Mac上,对于非常大的图像,SVG更好。我有一台MacBook Pro 2013 13英寸Retina,它在下面的操作非常好。图像是6000x6000像素,有1000个对象。当用户在图中拖动对象时,canvas中的类似结构对我来说是不可能进行动画化的。
在现代显示器上,您还必须考虑不同的分辨率,在这里SVG免费为您提供了所有这些。
小提琴:# EYZ0
全屏:# EYZ0
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);
只是我对divs选项的意见。
《Famous/Infamous》和《samyazare》(可能还有其他游戏)使用绝对定位的非嵌套divs(带有非繁琐的HTML/CSS内容),结合matrix2d/matrix3d进行定位和2D/3D转换,并在中等移动硬件上实现了稳定的60FPS,所以我不认为divs是一个缓慢的选择。
Youtube和其他地方有大量的屏幕记录,高性能的2D/3D东西在浏览器中运行,所有东西都是一个DOM元素,你可以检查元素, 60FPS(混合WebGL用于某些效果,但不用于渲染的主要部分)。
了解SVG和Canvas之间的区别将有助于选择正确的格式。
帆布
SVG
在谷歌搜索的时候,我发现了一个关于SVG和帆布在http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html的使用和压缩的很好的解释
希望能有所帮助:
SVG,像HTML一样,使用保留的呈现:当我们想要绘制一个 矩形中,我们声明式地使用元素 DOM。然后浏览器将绘制一个矩形,但它也将创建 内存中表示矩形的SVGRectElement对象。这 对象是停留在我们周围让我们操纵的东西-是的 保留。随着时间的推移,我们可以给它分配不同的位置和大小。 我们还可以附加事件监听器,使其具有交互性 Canvas使用立即呈现:当我们使用画一个矩形时,浏览器立即在屏幕上呈现一个矩形,但确实存在 永远不会有任何“矩形对象”来表示它。有 只是画布缓冲区中的一堆像素。我们动不了 矩形。我们只能再画一个矩形。我们无法回应 矩形上的单击或其他事件。我们只能对事件作出反应 在整个画布。李< / > 所以canvas是一个比SVG更低级、更有限制性的API。但是有一个 另一方面,就是你可以用canvas做更多 同样数量的资源。因为浏览器不需要创建 维护内存中所有东西的对象图 绘制时,需要较少的内存和计算资源 视觉场景。如果你有一个非常大和复杂的可视化
虽然上面的大多数答案仍然有一定的道理,但我认为它们值得更新:
多年来,SVG的性能有了很大的提高,现在有了硬件加速CSS转换和SVG动画,它完全不依赖于JavaScript的性能。当然,JavaScript的性能也得到了改善,Canvas的性能也得到了改善,但改善的程度不及SVG。此外,现在几乎所有浏览器都可以使用WebGL。用Simon上面用过的同样的词:It 胜过Canvas和SVG hands down。不过,这并不意味着它应该成为首选技术,因为它很难使用,而且只在非常特定的用例中速度更快。
恕我直言,对于今天的大多数用例,SVG提供了最好的性能/可用性比率。可视化需要非常复杂(就元素数量而言),同时又非常简单(每个元素),这样Canvas和WebGL才能真正发挥作用。
在这是一个类似问题的答案中,我提供了更多的细节,为什么我认为结合是所有三种技术中有时是最好的选择。
它们都有好的方面和坏的方面,下面我们来比较一下。
Canvas将具有最佳的整体性能,但前提是您正确使用它。
性能测试:https://kajam.hg0428.repl.co/pref/
性能测试此处:https://js-game-engine.hg0428.repl.co/canvasTest/preform.html
我还没有对此进行性能测试,但根据其他测试,它并不好。
ctx.rect
ctx.fill
ctx.fillRect
fill
stroke
fill[Shape]
如果你不记得在使用canvas时,你的游戏将会非常慢。这是我从经验中学到的。