Canvas和SVG是HTML5中主要的2D图形技术,前者提供画布标签和绘制API,后者是一整套独立的矢量图形语言,二者有各自的优势和特点,可适用于不同的场景。
Canvas | SVG |
---|---|
提供API通过JavaScript 绘制 | SVG使用 XML 格式定义基于矢量的图形 |
逐像素进行渲染 | 每个被绘制的图形均被视为对象 |
依赖分辨率 | 不依赖分辨率(图像在放大或改变尺寸的情况下其图形质量不会有损失) |
渲染速度快 适合图像密集型的游戏 | 复杂度高会减慢渲染速度 不适合游戏应用 |
首先,在HTML中添加 canvas 标签,即在html中创建了一个画布容器:
<canvas id="myCanvas" width="200" height="100">canvas>
然后在JS脚本中获取canvas DOM对象,创建context对象即可开始使用其API方法在canvas创建的画布上进行绘制了:
<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
context.fillStyle="#FF0000";
context.fillRect(0,0,150,75);
script>
context.fillStyle="#FF0000"; //设置填充样式
context.strokeStyle="rgb(0,165,255)"; //设置轮廓样式
context.lineWidth=4; //设置绘制线宽
context.rect(0,0,150,75); //创建矩形形状(x,y,width,height)
context.fill(); //填充矩形
context.stroke(); //绘制矩形轮廓
绘制结果如图:
需要在绘制图形前设置样式和颜色,颜色设置一般有以下几种方式:
rect()方法只是创建了矩形形状,并没有将其绘制出来,API也提供了直接绘制出矩形的方法fillRect(x,y,width,height), strokeRect(…),还有清除矩形的方法clearRect(…)。
/*填充三角形*/
context.beginPath(); //新建一条路径
context.moveTo(25,25); //将笔触移动到指定的坐标
context.lineTo(105,25); //创建到指定坐标的直线
context.lineTo(25,105);
context.fill();
/*描边三角形*/
context.beginPath();
context.moveTo(125,125);
context.lineTo(125,45);
context.lineTo(45,125);
context.closePath(); //闭合路径
context.stroke();
绘制结果:
其中,moveTo(x,y)方法指将路径起始点放在哪,即画路径笔放在哪个地方,这时还并没有创建出线条,继续moveTo到下一个坐标并不会产生路径,只是改变了笔的位置;而lineTo(x,y)方法则创建出了路径(并没有绘制出来),且笔触的位置也跟着改变了;另外closePath()方法指让路径闭合,如图创建出了闭合的三角形。
注:beginPath()指开始创建路径,如果画下一条路径时没有重新调用beginPath(),绘制下一条路径时,上一条路径也会重新绘制一遍;fill()会自动闭合路径,与closePath()一样,而stroke()不会。
绘制一般的形状,基本都可以使用创建路径的方式,还有一些其他方法可以创建弧线、曲线等路径,从而可以绘制出更复杂的图形:
arc(x, y, radius, startAngle, endAngle, anticlockwise);
圆心:(x,y), 半径:radius,起始弧度:startAngle ,结束弧度:endAngle,逆时针与否:anticlockwise(默认false为顺时针,true为逆时针)
示例:
context.fillStyle = "rgb(255,165,0)";
context.beginPath();
context.arc(50,50,40,Math.PI/2,Math.PI,true);
context.fill();
绘制结果:
2. 曲线
quadraticCurveTo(cp1x, cp1y, x, y)
绘制贝塞尔曲线,cp1x, cp1y为控制点,x,y为结束点
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制二次贝塞尔曲线,cp1x, cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点
如图,红色为控制点,蓝色为起始和结束点
示例:
//二次曲线
context.fillStyle="#FF0000";
context.beginPath();
context.moveTo(75,40);
context.bezierCurveTo(75,37,70,25,50,25);
context.bezierCurveTo(20,25,20,62.5,20,62.5);
context.bezierCurveTo(20,80,40,102,75,120);
context.bezierCurveTo(110,102,130,80,130,62.5);
context.bezierCurveTo(130,62.5,130,25,100,25);
context.bezierCurveTo(85,25,75,37,75,40);
context.fill();
绘制文本
绘制文本方法:
fillText(text, x, y [, maxWidth]); //填充文本,maxWidth 绘制的最大宽度(可选)
strokeText(text, x, y [, maxWidth]); //绘制文本边框
直接看示例:
绘制结果:
其中灰色边框表示画布轮廓,绘制的蓝色线条显示了文本对齐的方式。
绘制图像
绘制图像方法共有三种:
context.drawImage(image, x, y);
//x 和 y 是其在目标 canvas 里的起始坐标
context.drawImage(image, x, y, width, height);
//width 和 height,这两个参数用来控制 当像canvas画入时应该缩放的大小
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
这个方法可以实现图片切片,对应参数如图:
实例如下:
context.drawImage(img,60,100,100,100,50,0,100,100);
另外还可以通过clip()方法对图片进行裁剪:
context.beginPath();
context.arc(100,150,50,0,2*Math.PI);
context.clip();
context.drawImage(img,0,0);
结果如图:
绘制图片还可以选择平铺模式:”repeat” (x,y双向平铺),”repeat-x” (水平平铺),”repeat-y” (垂直平铺), “no-repeat” (不平铺).
实例如下:
var pattern = context.createPattern(img, 'repeat');
context.fillStyle = pattern;
context.fillRect(0,0,400,400);
context.transform(m11, m12, m21, m22, dx, dy);//图像变换,m11 水平缩放,m12 水平倾,m21 垂直倾斜,m22垂直缩放,dx 水平移动,dy 垂直移动
在 HTML5 中,您能够将 SVG 元素直接嵌入 HTML 页面中,Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 都支持内联SVG。
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190">
<polygon points="100,10 40,180 190,60 10,60 160,180"
style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;">
svg>
body>
html>
如上例,xmlns为命名空间,polygon 为创建了一个多边形图形。
svg主要有以下元素:
矩形 < rect >
圆形 < circle >
椭圆 < ellipse >
线 < line >
折线 < polyline >
多边形 < polygon >
路径 < path >
文本 < text >
<rect x="50" y="20" rx="20" ry="20" width="150" height="100"
style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/>
其中 x,y 为图形左上角相对父元素svg的坐标,rx,ry分别为x,y方向的圆角半径;style定义样式,也可以拆分成属性写法:
<rect x="50" y="20" rx="50" ry="150" width="150" height="100" fill="red" stroke="black" stroke-width=5 opacity=0.5 />
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="pink" />
cx和cy定义圆点的x和y坐标。如果省略cx和cy,圆的中心会被设置为(0, 0)
<ellipse cx="120" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" />
cx,cy定义的椭圆中心的坐标,rx,ry定义的水平和垂直半径
<line x1="0" y1="0" x2="200" y2="200"
style="stroke:rgb(255,0,0);stroke-width:2"/>
<polygon points="100,10 40,180 190,60 10,60 160,180" style="fill:red;stroke:black;stroke-width:5;fill-rule:nonzero;"/>
points 就是多边形的各个顶点
注:这里需要注意的是fill-rule,有几个属性值 nonzero | evenodd | inherit
关于fill-rule,我这里以下是引用另外一位作者的文章:
http://blog.csdn.net/mishiwjp/article/details/53484235
nonzero
字面意思是“非零”。按该规则,要判断一个点是否在图形内,从该点作任意方向的一条射线,然后检测射线与图形路径的交点情况。从0开始计数,路径从左向右穿过射线则计数加1,从右向左穿过射线则计数减1。得出计数结果后,如果结果是0,则认为点在图形外部,否则认为在内部。
evenodd
字面意思是“奇偶”。按该规则,要判断一个点是否在图形内,从该点作任意方向的一条射线,然后检测射线与图形路径的交点的数量。如果结果是奇数则认为点在内部,是偶数则认为点在外部。下图演示了evenodd 规则:
一看两幅图,你可能会有两个疑问,这些线段的箭头是什么?两组图形的第三幅图为什么是一样的?其实这些线段的方向是由我们给出的坐标的顺序决定的,points=”100,0 160,180 10,60 190,60 40,180”,起始点是最上方的点,然后是右下,最左边,最右边,再到左下。把这些点按顺序连起来就变成了五角星。
先看nozero时,怎么判断点是否在内部区域。射线1和图形线段只有一个交点,为从左到右,所以结果是1,判定为内部区域;射线2有两个交点,都是从左到右,结果是2,内部区域;射线3有三个交点,两个从左到右,一个从右到左,结果是1,内部区域;射线4有四个交点,两个从左到右,两个从右到左,结果是0,所以是外部区域。
evenodd时,只判断交点个数,所以1,3都是内部区域,2,4都是外部区域。
<polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" style="fill:white;stroke:red;stroke-width:4" />
"M150 0 L75 200 L225 200 Z" fill="orange" stroke="black" stroke-width="3" />
d定义路径属性,其中有一些路径命令:
M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Bézier curve
T = smooth quadratic Bézier curveto
A = elliptical Arc
Z = closepath
命令后接坐标值
注:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位
<svg>
<defs>
<path id="MyPath"
d="M 100 200
C 200 100 300 0 400 100
C 500 200 600 300 700 200
C 800 100 900 100 900 100" />
defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5">
<textPath xlink:href="#MyPath">Hello worldtextPath>
text>
svg>
SVG 允许我们定义以后需要重复使用的图形元素。 建议把所有需要再次使用的引用元素定义在defs元素里面。这样做可以增加SVG内容的易读性和可访问性。 在defs元素中定义的图形元素不会直接呈现。 你可以在你的视口的任意地方利用 < use >元素呈现这些元素。
SVG 也可以根据 < path > 元素的形状来放置文字。 只要在textPath元素内部放置文本,并通过其xlink:href属性值引用< path >元素,我们就可以让文字块呈现在< path >元素给定的路径上了。
<body>
<svg width="300" height="300" viewBox="0 0 95 50"
xmlns="http://www.w3.org/2000/svg">
<g stroke="green" fill="white" stroke-width="5">
<circle cx="25" cy="25" r="15" />
<circle cx="40" cy="25" r="15" />
<circle cx="55" cy="25" r="15" />
<circle cx="70" cy="25" r="15" />
g>
svg>
注: viewBox视图盒子,viewBox = x y width height,x 和 y 值决定viewBox的左上角,,width和height决定视窗的宽高。如果svg图形太大或者太小,就可以用ViewBox属性来调整在页面中的显示范围、大小。
上例svg width=”300” height=”300” viewBox=”0 0 95 50” 表示svg的宽95 高50范围显示在宽300 高300的视图。(FireFox3.6 下坐标系相反,坐标系建立在 svg 图形上。)
参考另外一位作者的解释比较接地气,容易理解:
http://www.zhangxinxu.com/wordpress/2014/08/svg-viewport-viewbox-preserveaspectratio/
嗯,暂时就这些了