HTML5 绘制图形 Canvas 与 SVG 的基本用法

HTML5 绘制图形 Canvas 与 SVG 的基本用法(笔记)

Canvas和SVG是HTML5中主要的2D图形技术,前者提供画布标签和绘制API,后者是一整套独立的矢量图形语言,二者有各自的优势和特点,可适用于不同的场景。


Canvas 与 SVG简单比较

Canvas SVG
提供API通过JavaScript 绘制 SVG使用 XML 格式定义基于矢量的图形
逐像素进行渲染 每个被绘制的图形均被视为对象
依赖分辨率 不依赖分辨率(图像在放大或改变尺寸的情况下其图形质量不会有损失)
渲染速度快 适合图像密集型的游戏 复杂度高会减慢渲染速度 不适合游戏应用

Canvas基本用法

首先,在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>

canvas API简单介绍

  • 座标
    canvas座标系统与大多数绘图API一样,画布左上角座标为(0,0),x轴方向水平向右,y轴方向垂直向下,单位为像素:
    这里写图片描述
  • 绘制矩形
    首先介绍两种绘制方法:context.fill() 和 context.stroke(),其中fill()为填充方法,stroke()为绘制轮廓的方法,以绘制矩形为例:
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();    //绘制矩形轮廓

绘制结果如图:
这里写图片描述
需要在绘制图形前设置样式和颜色,颜色设置一般有以下几种方式:

  1. ctx.fillStyle = “orange”;
  2. ctx.fillStyle = “#FFA500”;
  3. ctx.fillStyle = “rgb(255,165,0)”;
  4. ctx.fillStyle = “rgba(255,165,0,1)”;
    其中,rgba第四个参数为透明度。

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()不会。

绘制一般的形状,基本都可以使用创建路径的方式,还有一些其他方法可以创建弧线、曲线等路径,从而可以绘制出更复杂的图形:

  1. 弧形

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]); //绘制文本边框
    直接看示例:

<canvas id="myCanvas" width="500" height="200" style="border:1px solid #c3c3c3;"></canvas>

<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
    context.save();
    context.strokeStyle="#0000ff";
    context.moveTo(0,50);
    context.lineTo(500,50);
    context.moveTo(0,80);
    context.lineTo(500,80);
    context.moveTo(90,0);
    context.lineTo(90,200);
    context.moveTo(0,80);
    context.lineTo(500,80);
    context.stroke();
    context.restore();
context.font="30px Arial";    //设置字体
context.textBaseline = "middle";    //基线对齐方式
context.textAlign="left";   //文本对齐方式(相对于指定座标)
context.fillText("Hello World",90,50);
context.textBaseline = "hanging";
context.textAlign="center"; 
context.strokeText("Hello World",90,80);
</script>

绘制结果:
这里写图片描述
其中灰色边框表示画布轮廓,绘制的蓝色线条显示了文本对齐的方式。

  • 绘制图像
    绘制图像方法共有三种:
    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.save();//保存当前context状态,包括fillStyle,strokeStyle等
  • context.restore();//还原保存的context状态
  • context.getImageData(sx,sy,sw,sh);//sx,sy为相对canvas座标,sw、sh为相对canvas宽高,获取像素颜色数组,数组格式为[r1,g1,b1,a1,r2,g2,b2,a2,…..]从左到右,从上到下排列的像素数组
  • context.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);//根据像素数组绘制图像,dx,dy为绘制座标,dirty为图像数据限定的矩形范围
  • context.transform(m11, m12, m21, m22, dx, dy);//图像变换,m11 水平缩放,m12 水平倾,m21 垂直倾斜,m22垂直缩放,dx 水平移动,dy 垂直移动

    SVG基本用法

    在 HTML5 中,您能够将 SVG 元素直接嵌入 HTML 页面中,Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 都支持内联SVG。

<!DOCTYPE html>
<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"/>

这里写图片描述 x1,y1为起始点座标,x2,y2为终点座标

  • 多边形
<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" />

这里写图片描述 points指定了曲线的拐点

  • 路径
<path d="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 world</textPath>
  </text>
</svg>

这里写图片描述
SVG 允许我们定义以后需要重复使用的图形元素。 建议把所有需要再次使用的引用元素定义在defs元素里面。这样做可以增加SVG内容的易读性和可访问性。 在defs元素中定义的图形元素不会直接呈现。 你可以在你的视口的任意地方利用 < use >元素呈现这些元素。
SVG 也可以根据 < path > 元素的形状来放置文字。 只要在textPath元素内部放置文本,并通过其xlink:href属性值引用< path >元素,我们就可以让文字块呈现在< path >元素给定的路径上了。

  • g元素
    元素g是用来组合对象的容器。添加到g元素上的变换会应用到其所有的子元素上。添加到g元素的属性会被其所有的子元素继承。此外,g元素也可以用来定义复杂的对象,之后可以通过< use >元素来引用它们。
<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/

嗯,暂时就这些了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章