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

我知道HTML5提供了三个元素,可以使这成为可能:svg, canvas和div。对于我想做的事情,这些元素中哪一个将提供最佳性能?

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


当前回答

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

帆布

分辨率的依赖 不支持事件处理程序 糟糕的文本渲染能力 您可以将生成的图像保存为.png或.jpg 非常适合图像密集型游戏

SVG

分辨率独立 支持事件处理程序 最适合具有大渲染区域的应用程序(谷歌Maps) 如果复杂,呈现速度会很慢(任何大量使用DOM的东西都会如此) 慢) 不适合游戏应用

其他回答

简单的回答是:

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

div还可以,但是笨重,在大量加载时性能很差。

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


长话短说:

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

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

这些SVG DOM引用意味着一些处理所绘制事物的步法已经为您完成了。SVG在呈现非常大的对象时速度更快,但在呈现许多对象时速度较慢。

在Canvas中游戏可能会更快。大型地图程序使用SVG可能会更快。如果你确实想使用Canvas,我有一些教程,让可移动的对象在这里运行。

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时间,无论你是否在看它。(2013年编辑:他们基本上已经解决了这个问题)

在HTML页面上拖动更流畅,这是设计所期望的,因为当前的设置是在Canvas测试中每30毫秒重绘EVERYTHING。为此,Canvas有很多优化。(画布失效是最简单的,还有剪切区域,选择性重绘等。这取决于你有多喜欢执行)

毫无疑问,在这个简单的测试中,你可以让Canvas在对象操作上更快,当然在加载时间上也更快。在Canvas中绘制/加载更快,也有更多的优化空间(也就是说,排除屏幕外的东西是非常容易的)。

结论:

SVG可能更适合应用程序和项目较少的应用程序(少于1000个?取决于真的) Canvas更适合成千上万的对象和仔细的操作,但需要更多的代码(或库)才能使它起步。 HTML div是笨拙的,不能缩放,制作一个圆只能用圆角,制作复杂的形状是可能的,但涉及到数百个极小的像素宽的div。疯狂。

For your purposes, I recommend using SVG, since you get DOM events, like mouse handling, including drag and drop, included, you don't have to implement your own redraw, and you don't have to keep track of the state of your objects. Use Canvas when you have to do bitmap image manipulation and use a regular div when you want to manipulate stuff created in HTML. As to performance, you'll find that modern browsers are now accelerating all three, but that canvas has received the most attention so far. On the other hand, how well you write your javascript is critical to getting the most performance with canvas, so I'd still recommend using SVG.

我同意Simon Sarris的结论:

我比较了Protovis (SVG)和Processingjs (Canvas)中的一些可视化,后者显示> 2000点,Processingjs比Protovis快得多。

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

还有道场。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/

为了补充这一点,我一直在做一个图表应用程序,最初是从画布开始的。该图由许多节点组成,而且它们可以变得相当大。用户可以在图中拖动元素。

我发现,在我的Mac上,对于非常大的图像,SVG更好。我有一台MacBook Pro 2013 13英寸Retina,它在下面的操作非常好。图像是6000x6000像素,有1000个对象。当用户在图中拖动对象时,canvas中的类似结构对我来说是不可能进行动画化的。

在现代显示器上,您还必须考虑不同的分辨率,在这里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);

只是我对divs选项的意见。

《Famous/Infamous》和《samyazare》(可能还有其他游戏)使用绝对定位的非嵌套divs(带有非繁琐的HTML/CSS内容),结合matrix2d/matrix3d进行定位和2D/3D转换,并在中等移动硬件上实现了稳定的60FPS,所以我不认为divs是一个缓慢的选择。

Youtube和其他地方有大量的屏幕记录,高性能的2D/3D东西运行在浏览器中,所有东西都是一个DOM元素,你可以在上面检查元素,60FPS(混合WebGL用于某些效果,但不适用于渲染的主要部分)。