canvas 和 svg 差别
HTML绘制图形功能,如今比较流行的可能就是HTML5中的Canvas了,但是并不是任何场合都适合用Canvas,HTML5草案推出之前,对于页面的图像动画,虽然各家都推出自己支持方案,但是一直以来都是由Flash统治着。IE通过调用Silverlight插件或者VML(CSS Filter)实现图形功能的,其他浏览器则是通过SVG来支持图形功能的。当然这篇文章主要是总结Canvas 和SVG的区别,然后从具体实现上区分这两种HTML图形的差别。
Canvas与SVG的主要区别
- 从图像类别区分,Canvas是基于像素的位图,而SVG却是基于矢量图形。可以简单的把两者的区别看成photoshop与illustrator的区别。
- 从渲染模式上来说,Canvas属于 即时模式,而SVG则是 保留模式 ,这两种模式的区别可以参见 cshao 的博文: http://www.lifelaf.com/blog/?p=354。
- 从结构上说,Canvas没有图层的概念,所有的修改整个画布都要重新渲染,而SVG则可以对单独的标签进行修改。
- 从操作对象上说,Canvas是基于HTML canvas标签,通过宿主提供的Javascript API对整个画布进行操作的,而SVG则是基于XML元素的。
- 从功能上讲,SVG发布日期较早,所以功能相对Canvas比较完善。
- 关于动画,Canvas更适合做基于位图的动画,而SVG则适合图表的展示。关于SVG和Canvas的运行场景可参考MSCN关于 如何为您的网站在Canvas和SVG之间做出选择:
- 从搜索引擎角度分析,由于svg是有大量标签组成,所以可以通过给标签添加属性,便于爬虫搜索。
根据上面所述,下面总结一下Canvas与SVG在应用中的主要区别:
基本图形
SVG是基于XML的矢量图形,而Canvas则是由脚本绘制出来的。尽管两者图形的绘制形式不同,但是不管是Canvas还是SVG,都是通过定义的基本形状组合其他图形的。HTML5中将Canvas的基本图形简单的分为:line,rect,path(包括arc,curve)三部分,而SVG则相对复杂一点包括:line,rect,circle,ellipse,polyline(polygon),path。SVG将circle,ellipse,polyline(polygon)给单独罗列出来,Canvas则在Path的基础上分离出来了arc,curve形状的接口,其他的两者基本相同。需要说明的是SVG中path 可以用来画任何形状(包括曲线等),而Canvas则只能通过arc,curve来绘制圆弧,而且对于Canvas在绘制path前后需要通过context.beginPath(),contex.closePath()标识。
SVG是有XML节点组成的,相对canvas脚本会稍微简单点,但是同样需要一堆数据用来表示各种参数,未免容易记混,不过还好有些规律:
- x,y表示起点坐标
- x1,y1 x2,y2 xn,yn表示控制或者连接点坐标
- c,r开头肯定是和圆弧有关了,r表示 半径 ,cx,cy表示圆心,rx,ry分别表示x轴y轴相对弧线的半径
- points,d很明显表示多个点的组合
SVG中规定的基本形状:
<line x1=0 y1=0 x2=200 y2=200 stroke=green stroke-width=4 stroke-dasharray=10,6></line> <rect x=0 y=0 rx=50 ry=100 width=300 height=150 stroke=orange stroke-width=8 stroke-dasharray=10,6 fill=yellow fill-opacity=0.8></rect> <circle cx=50 cy=50 r=50 fill=gray fill-opacity=0.6></circle> <ellipse cx=100 cy=100 rx=100 ry=80 fill=blue fill-opacity=0.4></ellipse> <polyline points="0,0 15,30 24,200 100,50" fill="none" stroke=red stroke-width=4></polyline>
``
不管是SVG还是Canvas,绘制曲线相对都是比较复杂,所以我将他们放在一起总结一下,不管是对比还是学习备忘还是很有必要的,先从复杂的说起 - SVG,先通过代码看一下SVG中path节点构成:
```html
<path fill="#c53" fill-rule="evenodd" opacity=".5" d="M 70 140 C 17.5 ,140 150,0 200,100 C 220, 140 40,100 100,0 C 127,-47 170,140 70 140"/>
通过path绘制图形时往往会被里面类似于M,C,Q等的参数给搞糊涂,如下是从《Building Web Application with SVG》一书中摘抄下来的命令表:
Commands
Parameters
Instruction
M, m
x, y
Move to a new point (x,y).
L, l
x, y
Draw a line from the current point to a new point (x,y).
H, h
x
Draw a horizontal line from the current point to a new point (x,current-point-y).
V, v
y
Draw a vertical line from the current point to a new point (current-point-x,y).
A, a
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
Draw an elliptical arc from the current point to a new point (x,y). The arc belongs to an ellipse that has radii rx and ry and a rotation with respect to the positive x-axis of x-axis-rotation (in degrees) - 需要说明一下:表示X轴与椭圆横轴的角度. If large-arc-flag is 0 (zero), then the small arc (less than 180 degrees) is drawn. A value of 1 results in the large arc (greater than 180 degrees) being drawn. If sweep-flag is 0, then the arc is drawn in a negative angular direction (counterclockwise); if it is 1, then the arc is drawn in a positive angular direction (clockwise).
Q, q
x1, y1 x, y
Draw a quadratic Bézier curve from the current point to a new point (x,y) using (x1,y1) as the control point.
T, t
x, y
Draw a smooth quadratic Bézier curve segment from the current point to a new point (x,y). The control point is computed automatically as the reflection of the control point on the previous command relative to the current point. If there is no previous command or if the previous command was not a Q, q, T, or t, the control point is coincident with the current point.
C, c
x1, y1 x2, y2 x, y
Draw a cubic Bézier curve from the current point to a new point (x,y) using (x1,y1) and (x2,y2) as control points.
S, s
x2, y2 x, y
Draw a smooth cubic Bézier curve segment from the current point to a new point (x,y). The first control point is computed automatically as the reflection of the control point on the previous command relative to the current point. If there is no previous command or if the previous command was not a C, c, S, or s, the first control point is coincident with the current point. (x2,y2) is the second control point.
而相对 Canvas 绘制弧线的 API:
- context.arc(x, y, radius, startAngle, endAngle, anticlockwise)//圆弧
- context.arcTo(x1, y1, x2, y2, radius)//圆弧 - 依赖控制点-:当前点,x1,y1与x2,y2形成的切线
- context.quadraticCurveTo(cpx, cpy, x, y)//二次方程曲线,当前点是起始点,xy表示结束点,而cpx,cpy表示控制点
- context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)//贝塞尔曲线。三个控制点 - 当前点,cp1x/cp1y,cp2x/cp2y
具体看下面的例子:
var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); context.stokeStyle = 'black'; context.beginPath(); context.moveTo(0,0); context.lineTo(100,200); context.arcTo(350,350,100,100,20) context.stroke(); context.closePath(); context.strokeStyle = 'green'; context.beginPath(); context.moveTo(100,100); context.lineTo(350,350); context.stroke(); context.closePath(); context.strokeStyle = 'green'; context.beginPath(); context.moveTo(100,200); context.lineTo(350,350); context.stroke(); context.closePath(); context.strokeStyle = 'blue'; context.beginPath(); context.moveTo(0,0); context.quadraticCurveTo(100,25,0,50); context.stroke(); context.closePath(); context.strokeStyle = 'purple'; context.beginPath(); context.moveTo(0,50); context.lineTo(100,25); context.stroke(); context.closePath(); context.strokeStyle = 'orange'; context.beginPath(); context.moveTo(150,0); context.bezierCurveTo(0,125,300,175,150,300); context.stroke(); context.closePath(); context.strokeStyle = 'red'; context.beginPath(); context.moveTo(0,125); context.lineTo(150,0); context.stroke(); context.closePath(); context.strokeStyle = 'red'; context.beginPath(); context.moveTo(300,175); context.lineTo(150,300); context.stroke(); context.closePath();
画布,群组和复用(pattern/gradient)
Canvas是通过Javascript绘制在canvas DOM区域的,而svg则是有不同的图形元素节点组合在SVG元素中的。这个很好理解,DOM中的canvas和svg都是对应的画布,然而如果希望图像仅显示在画布部分区域或者说只有部分区域的图像可以显示,该如何处理呢?当然可以通过坐标位置和图像大小来设置,然而canvas和SVG定义了clip来设置画布上的显示内容,除了clip,svg还可以通过设置mask来设置图形的显示,如果熟悉Photoshop或者illustrator的话对于这些概念一定该不会陌生。需要说明的是canvas中可以通过context.save(),context.restore()改变上下文状态来改变显示图像的作用范围,而svg则是通过预先定义clipPath或mask(里面是显示图形的组合),然后对图形设置clip-path或mask属性来设置显示的作用域。除此之外Canvas针对所有的图形,可以通过设置globalCompositeOperation来显示或隐藏不同形状重叠部分,有点类似于PS中的选取合并或蒙版。
globalCompositeOperation:copy|destination-atop|destination-in|destination-out|destination-over|lighter|source-atop|source-in|source-out|source-overxor
Canvas不像Photoshop,它没有图层的概念,更别提