动态创建元素并能够移动它们的最佳方法是什么?例如,假设我想创建一个矩形,圆形和多边形,然后选择这些对象并移动它们。
我了解HTML5提供了三个可以实现此目标的元素:svg,canvas和div。对于我想要做的事情,哪一个元素将提供最佳性能?
为了比较这些方法,我考虑创建三个视觉上相同的网页,每个网页都有页眉,页脚,小部件和文本内容。第一页中的小部件将完全使用canvas
元素创建,第二个完全使用svg
元素创建,第三个使用普通div
元素,HTML和CSS。
答案 0 :(得分:529)
SVG对你来说更容易,因为已经内置了选择和移动它.SVG对象是DOM对象,所以它们有“点击”处理程序等。
DIV很好,但很笨重,并且可怕的性能大量加载。
Canvas具有最佳性能,但您必须自己实现托管状态(对象选择等)的所有概念,或者使用库。
HTML5 Canvas只是位图的绘图表面。你设置绘制(用颜色和线条粗细说),绘制那个东西,然后画布不知道那个东西:它不知道它在哪里或者你刚刚绘制的是什么,它是只是像素。如果您想绘制矩形并让它们四处移动或可选择,那么您必须从头开始编写所有这些代码,包括代码以记住您绘制它们。
另一方面,SVG必须维护对它呈现的每个对象的引用。您创建的每个SVG / VML元素都是DOM中的真实元素。默认情况下,这允许您更好地跟踪您创建的元素,并且默认情况下更容易处理鼠标事件等事件,但是当存在大量对象时,它会显着减慢那些SVG DOM引用意味着处理你绘制的东西的一些步法是为你完成的。渲染非常大的对象时SVG速度更快,但渲染许多对象时速度更慢。
Canvas游戏可能会更快。在SVG中,一个巨大的地图程序可能会更快。如果您确实想要使用Canvas,我有一些关于使可移动对象正常运行的教程here。
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中的绘图/加载速度更快,并且具有更大的优化空间(即,排除屏幕外的内容非常容易)。
答案 1 :(得分:37)
除此之外,我还在做一个图表应用程序,最初是用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);
答案 2 :(得分:21)
了解SVG和Canvas之间的差异将有助于选择正确的。
帆布
SVG
答案 3 :(得分:18)
我同意Simon Sarris的结论:
我将Protovis(SVG)中的一些可视化与Processingjs(Canvas)进行了比较,后者显示了&gt; 2000点和processingjs比protovis快得多。
使用SVG处理事件当然要容易得多,因为您可以将它们附加到对象上。在Canvas中你必须手动完成(检查鼠标位置等),但是为了简单的交互,它应该不难。
还有dojo工具包的dojo.gfx库。它提供了一个抽象层,您可以指定渲染器(SVG,Canvas,Silverlight)。这可能也是一个可行的选择,虽然我不知道额外的抽象层增加多少开销,但它使编码交互和动画变得容易,并且与渲染器无关。
以下是一些有趣的基准:
答案 4 :(得分:16)
关于div选项只需2美分。
Famous / Infamous和SamsaraJS(可能还有其他人)使用绝对定位的非嵌套div(具有非平凡的HTML / CSS内容),结合matrix2d / matrix3d进行定位和2D / 3D转换,并实现稳定的60FPS温和的移动硬件,所以我认为反对div是一个缓慢的选择。
在Youtube和其他地方有大量的屏幕录制,在浏览器中运行的高性能2D / 3D内容,所有内容都是一个DOM元素,您可以在60FPS( Inspect Element )上打开(混合)使用WebGL获取特定效果,但不适用于渲染的主要部分。)
答案 5 :(得分:13)
出于您的目的,我建议使用SVG,因为您获得了DOM事件,例如鼠标处理(包括拖放),您不必实现自己的重绘,并且您不必跟踪你的对象的状态。当您需要进行位图图像处理时使用Canvas,并在想要操作HTML中创建的内容时使用常规div。至于性能,你会发现现代浏览器正在加速这三种,但到目前为止,该画布受到了最多的关注。另一方面,你用javascript编写javascript对于获得最佳性能至关重要,所以我仍然建议使用SVG。
答案 6 :(得分:12)
虽然上面的大多数答案仍然有一些道理,但我认为它们值得更新:
多年来,SVG的性能得到了很大改善,现在有一些硬件加速的CSS转换和SVG动画完全不依赖于JavaScript性能。当然,JavaScript性能也得到了提升,Canvas的性能也得到了提升,但没有SVG得到改进的那么多。还有一个新的孩子&#34;在今天几乎所有浏览器中都可用的块上, WebGL 。使用Simon上面使用的相同单词:击败Canvas和SVG 。但这并不意味着它应该是首选技术,因为它是一个可以使用的野兽,而且在非常具体的用例中它只会更快。
对于今天的大多数用例,恕我直言,SVG提供了最佳的性能/可用性比率。可视化需要非常复杂(关于元素的数量)并且同时非常简单(每个元素),因此Canvas甚至更加如此WebGL真正闪耀。在this answer to a similar question我提供了更多详细信息,为什么我认为所有这三种技术的组合有时候是您的最佳选择。
答案 7 :(得分:2)
在谷歌上搜索时,我发现了http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html
SVG 和画布的使用和压缩的一个很好的解释希望有所帮助:
- SVG与HTML一样,使用保留渲染:当我们想要绘制一个 在屏幕上的矩形,我们声明性地使用了我们的元素 DOM。然后浏览器将绘制一个矩形,但它也将创建 表示矩形的内存中SVGRectElement对象。这个 对象是我们操纵的东西 - 它是 保留。我们可以随着时间的推移为其分配不同的位置和大小。 我们还可以附加事件监听器以使其具有交互性。
- Canvas使用立即呈现:当我们draw a rectangle时,浏览器立即在屏幕上呈现一个矩形,但是 永远不会成为代表它的任何“矩形对象”。有 只是画布缓冲区中的一堆像素。我们不能动了 长方形。我们只能绘制另一个矩形。我们无法回应 点击或矩形上的其他事件。我们只能回应事件 在整个画布。
因此,canvas比SVG更低级,限制性更强。但是有一个 翻转到那个,这是用帆布你可以做更多的 相同数量的资源。因为浏览器不必创建 并维护我们拥有的所有东西的内存中对象图 绘制时,需要较少的内存和计算资源来绘制相同的内容 视觉场景。如果你有一个非常大而复杂的可视化 画,Canvas可能是你的票。