Canvas库处理SVG和SVG库处理SVG的方式有什么区别?

10

我非常有兴趣在浏览器中探索图形用户界面。我非常喜欢使用.SVG文件,原因是它们可伸缩性强,并且可以轻松地在诸如Illustrator之类的程序中制作。另一个我喜欢的东西是,在许多库(如Snap.svg)中,可以选择单个图层(例如更复杂形状的圆形路径)。

然而,我也经常使用粒子并有许多对象需要绘制。因为我做的事情对音乐有反应,所以我需要绝对最快的库(以保持高FPS计数和许多对象)。

经过查看webGL、SVG和Canvas,我可以看出webGL显然是绘制图片等物品的最快方法,但我没有看到任何能够使用webGL并访问与本机SVG库具有相同路径信息的库。

有人能向我解释一下“本机”SVG库和使用Canvas元素(如paper.js fabric.js)的库以及“SVG解析器”之间的区别吗?(我甚至不知道什么是SVG解析器)。

似乎这些库会将项目绘制到画布上,这会将它们转换为光栅图像(失去了SVG的可伸缩性和分辨率独立性),我不确定SVG的单个图层/路径是否仍然可以被选择(就像在Snap等库中一样)。

我也很想知道为什么没有基于webGL的SVG库。

谢谢


画布完全不处理SVG。它是基于光栅的绘图表面;一旦数据被绘制在上面,那就是像素了。WebGL是画布可以使用的模式之一 - 对于2D光栅图形,有Canvas2D API,对于3D光栅图形,则是WebGL。 - Mike 'Pomax' Kamermans
1
正确,但是像paper.js和fabric.js这样的库使用SVG,并且能够解析它,可能是通过将SVG转换为画布像素来实现的? - Startec
Paper.js使用画布进行绘制,但可以跟踪形状,这些形状可以基于SVG输入构建,并且它知道如何将其序列化回SVG输出。 - Mike 'Pomax' Kamermans
那个库处理的方式是将SVG转换为像素,然后在画布上绘制(显示),但你所说的“序列化回SVG输出”是什么意思? - Startec
为什么会有人编写WebGL SVG库呢?每个支持WebGL的浏览器都已经支持SVG了。 - gman
显示剩余2条评论
1个回答

25

以下是一个快速概述(免责声明:我是Fabric.js的作者)

SVG库

Raphael.js、Bonsai.js、svg.js、Snap.svg等使用 SVG作为底层技术来渲染图形。这是矢量图形。它们既是抽象,也是“入口”,使您能够执行类似于这样的操作(来自Bonsai的示例):

var shape1 = new Rect(10,10,100,100).attr({fillColor: 'red'});
var group = new Group();
group.addChild(shape1);

stage.addChild(group);

并获得这个:

<svg data-bs-id="0" width="796" height="796" class=" bs-1416663517803-1" viewBox="-0.5 -0.5 796 796">
  <defs></defs>
  <g data-bs-id="1087">
    <g data-bs-id="1089">
      <path data-bs-id="1088" d="M 0 0 l 100 0 l 0 100 l -100 0 Z" 
            fill="rgba(255,0,0,1)" 
            data-stroke="rgba(0,0,0,1)" 
            transform="matrix(1,0,0,1,10,10)" 
            stroke-width="0" 
            stroke-dashoffset="0"></path>
    </g>
  </g>
</svg>

这将转化为:

img

这些库允许您通过更高级的抽象间接地使用SVG节点、属性和值进行操作。

画布库

Fabric.js、Paper.js、Kinetic.js等。

它们使用画布作为底层技术来渲染图形。这是光栅图形。它们也是抽象和"网关",使您能够执行类似于以下内容的操作(来自Fabric的示例):

var rect = new fabric.Rect({ 
  left: 100, 
  top: 100, 
  width: 100, 
  height: 100, 
  fill: 'red'
});
canvas.add(rect);

并将其呈现为这样:

img

由于这些库基于画布,所以文档中只会有<canvas>元素。其他所有内容都是用类似于以下的(更低级别的)代码在内部表示的:
var canvasEl = document.getElementById('c');    
var ctx = canvasEl.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(100, 100, 100, 100);

支持SVG解析的Canvas库

Fabric.js、canvg等是Canvas库的一部分,但支持解析SVG。这意味着库能够处理以下类似的SVG代码:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700" xml:space="preserve">
  <rect x="10" y="10" width="100" height="100" stroke="blue" fill="purple" fill-opacity="0.5" stroke-opacity="0.8"/>
</svg>

并按如下方式进行渲染:

img

这本质上是将SVG转换为画布。它还是矢量图转换为伪光栅图。之所以是伪光栅,是因为没有损失质量(至少在Fabric的情况下)。当转换矢量SVG时,Fabric会将其制作成虚拟的非光栅对象,该对象可以在任何大小、角度、位置等情况下呈现,而不会失去质量。甚至可以导出回SVG。只有在画布上呈现时,它才变成光栅图形。

WebGL库

Three.js、Babylon.js、c3DL、Pixi.js等。

这些是Canvas库的超集(基于<canvas>,而不是SVG),它们使用WebGL渲染上下文而不是“2d”上下文:

// webgl canvas libraries
canvas.getContext('webgl');

// non-webgl canvas libraries
canvas.getContext('2d');

WebGL画布库使用完全不同的API来通过画布绘制图形,与非WebGL画布库相比。它们通常也支持“2d”上下文,作为备用方案。
WebGL 2D vs 3D
WebGL库还可以分为2D和3D - 那些“专门”于2D或3D输出。最流行的3D WebGL库的例子是Three.js,而2D则是Pixi.js。
顺便说一句,一旦我们在Fabric.js中添加对WebGL渲染器的支持,该库将从“具有SVG支持的画布库”变为“具有SVG支持的WebGL-capable画布库” :)

1
一个快速的跟进:(顺便说一下,很好的分解)我喜欢Snap.svg的一件事是,你可以从.svg文件中选择路径(或对象)。也就是说,如果我有一个带有红色圆圈(单独路径)的绿色矩形,我可以选择圆圈并根据其id属性对其进行操作。我可以看到Fabric也具有此功能,但我不确定其他库(如Paper.js)是否具有此功能。哇,多么棒的库。 - Startec
@kangax 你有没有考虑在Fabric.js上添加WebGL?我已经是Paper.js的粉丝好几年了,非常想看看在这样一个库中添加WebGL后会发生什么 - 性能一直是Canvas包装器中几乎所有东西的重大障碍。 - nicholaswmin
还没有 :( 要做的事情太多,时间太少。我们现在专注于解决错误、架构改进、测试和文本相关功能——我们是唯一一家拥有如此广泛(交互式)文本支持的库,能够在画布上使用。WebGL仍然在计划中;我只是不确定我们何时会开始,但希望今年能实现。当然,任何帮助都非常欢迎! :) - kangax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接