1 Canvas接口元素定义
1.1 getContext()方法
为了在canvas上绘制,你必须先得到一个画布上下文对象的引用,用本方法即可完成这一操作,格式如下:
context = canvas . getContext(contextId)
方法返回一个指定contextId的上下文对象,如果指定的id不被支持,则返回null,当前唯一被强制必须支持的是“2d”,也许在将来会有“3d”,注意,指定的id是大小写敏感的。
1.2 toDataURL()方法
返回一张使用canvas绘制的图片,返回值符合data:URL格式,格式如下:
url = canvas . toDataURL( [ type, ... ])
规范规定,在未指定返回图片类型时,返回的图片格式必须为PNG格式,如果canvas没有任何像素,则返回值为:“data:,”,这是最短的data:URL,在text/plain资源中表现为空字符串。type的可以在image/png,image/jpeg,image/svg+xml等 MIME类型中选择。如果是image/jpeg,可以有第二个参数,如果第二个参数的值在0-1之间,则表示JPEG的质量等级,否则使用浏览器内置默认质量等级。
下面的代码可以从ID为codeex的canvas中取得绘制内容,并作为DataURL传递给img元素,并显示。
var canvas = document.getElementById('codeex');
var url = canvas.toDataURL();
//id为myimg的图片元素
myimg.src = url;
2 二维绘图上下文
当使用一个canvas元素的getContext(“2d”)方法时,返回的是CanvasRenderingContext2D对象,其内部表现为笛卡尔平面坐标,并且左上角坐标为(0,0),在本平面中往右则x坐标增加和往下方y坐标增加。每一个canvas元素仅有一个上下文对象。其接口如下:
interface CanvasRenderingContext2D {
// back-reference to the canvas
readonly attribute HTMLCanvasElement canvas;
// state
void restore(); // pop state stack and restore state
void save(); // push state on state stack
// transformations (default transform is the identity matrix)
void rotate(in float angle);
void scale(in float x, in float y);
void setTransform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);
void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);
void translate(in float x, in float y);
// compositing
attribute float globalAlpha; // (default 1.0)
attribute DOMString globalCompositeOperation; // (default source-over)
// colors and styles
attribute any fillStyle; // (default black)
attribute any strokeStyle; // (default black)
CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1);
CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1);
CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition);
CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition);
CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition);
// line styles
attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
attribute DOMString lineJoin; // "miter", "round", "bevel" (default "miter")
attribute float lineWidth; // (default 1)
attribute float miterLimit; // (default 10)
// shadows
attribute float shadowBlur; // (default 0)
attribute DOMString shadowColor; // (default transparent black)
attribute float shadowOffsetX; // (default 0)
attribute float shadowOffsetY; // (default 0)
// rects
void clearRect(in float x, in float y, in float w, in float h);
void fillRect(in float x, in float y, in float w, in float h);
void strokeRect(in float x, in float y, in float w, in float h);
// Complex shapes (paths) API
void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise);
void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);
void beginPath();
void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);
void clip();
void closePath();
void fill();
void lineTo(in float x, in float y);
void moveTo(in float x, in float y);
void quadraticCurveTo(in float cpx, in float cpy, in float x, infloat y);
void rect(in float x, in float y, in float w, in float h);
void stroke();
boolean isPointInPath(in float x, in float y);
// text
attribute DOMString font; // (default 10px sans-serif)
attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
void fillText(in DOMString text, in float x, in float y, optional in float maxWidth);
TextMetrics measureText(in DOMString text);
void strokeText(in DOMString text, in float x, in float y, optional in float maxWidth);
// drawing images
void drawImage(in HTMLImageElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
void drawImage(in HTMLCanvasElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
void drawImage(in HTMLVideoElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
// pixel manipulation
ImageData createImageData(in float sw, in float sh);
ImageData createImageData(in ImageData imagedata);
ImageData getImageData(in float sx, in float sy, in float sw, in float sh);
void putImageData(in ImageData imagedata, in float dx, in float dy, optional in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight);
};
interface CanvasGradient {
// opaque object
void addColorStop(in float offset, in DOMString color);
};
interface CanvasPattern {
// opaque object
};
interface TextMetrics {
readonly attribute float width;
};
interface ImageData {
readonly attribute CanvasPixelArray data;
readonly attribute unsigned long height;
readonly attribute unsigned long width;
};
interface CanvasPixelArray {
readonly attribute unsigned long length;
getter octet (in unsigned long index);
setter void (in unsigned long index, in octet value);
};
2.1 canvas的状态
每个上下文都包含一个绘图状态的堆,绘图状态包含下列内容:
1、当前的transformation matrix.
2、当前的clipping region.
3、当前的属性值:fillStyle, font, globalAlpha, globalCompositeOperation, lineCap, lineJoin, lineWidth, miterLimit, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, strokeStyle, textAlign, textBaseline
注:当前path和当前bitmap不是绘图状态的一部分,当前path是持久存在的,仅能被beginPath()复位,当前bitmap是canvas的属性,而非绘图上下文。
context . restore() //弹出堆最上面保存的绘图状态
context . save() //在绘图状态堆上保存当前绘图状态
绘图状态可以看作当前画面应用的所有样式和变形的一个快照。而状态的应用则可以避免绘图代码的过度膨胀。
2.1.1 context . restore()
2.1.2 context . save()
2.2 转换(Transformations)
当建立形状和路径时,转换矩阵被应用到其坐标上。转换的执行顺序是严格按顺序的(注:原文是反向,经试验应该是按调用顺序的)。
在做转换/变形之前先保存状态是一个良好的习惯。大多数情况下,调用restore 方法比手动恢复原先的状态要简单得多。
2.2.1 context . rotate(angle)
context . rotate(angle) //按给定的弧度旋转,按顺时针旋转
rotate方法旋转的中心始终是canvas的原点,如果要改变它,需要使用translate方法。
![](https://i-blog.csdnimg.cn/blog_migrate/3c57eb46893c4144f4cb14a3630fbc80.png)
2.2.2 context .scale(x, y)
context . scale(x, y) //按给定的缩放倍率缩放,1.0,为不变,参数比1.0小表示缩小,否则表示放大。默认情况下,canvas的1 单位就是1 个像素。举例说,如果我们设置缩放因子是0.5,1个单位就变成对应0.5 个像素,这样绘制出来的形状就会是原先的一半。同理,设置为2.0 时,1个单位就对应变成了2 像素,绘制的结果就是图形放大了2倍。
2.2.3 context . setTransform(m11, m12, m21, m22, dx, dy)
context . setTransform(m11, m12, m21, m22, dx, dy) //重设当前的转换
2.2.4 context . transform(m11, m12, m21, m22, dx, dy)
context . transform(m11, m12, m21, m22, dx, dy)
//矩阵变换,结果等于当前的变形矩阵乘上
m11 m21 dx
m12 m22 dy
0 0 1
后的结果
2.2.5 context . translate(x, y)
context . translate(x, y) //可以理解为偏移,向x,y方向偏移指定的量,其用来移动Canvas的原点到一个指定的值
2.2.5.1 示例
下面是一个利用translate方法进行绘制螺旋图案的例子:
![](https://i-blog.csdnimg.cn/blog_migrate/60776586d6461017177ee0ea2a3bec7b.png)
//绘制螺旋图案的函数
function drawSpirograph(ctx,R,r,O){
var x1 = R-O;
var y1 = 0;
var i = 1;
ctx.beginPath();
ctx.moveTo(x1,y1);
do {
if (i>20000) break;
var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))
var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72))
ctx.lineTo(x2,y2);
x1 = x2;
y1 = y2;
i++;
} while (x2 != R-O && y2 != 0 );
ctx.stroke();
}
//调用部分代码
context.fillRect(0,0,300,300);
for (var i=0;i<3;i++) {
for (var j=0;j<3;j++) {
context.save();
context.strokeStyle = "#9CFF00";
context.translate(50+j*100,50+i*100);
drawSpirograph(context,20*(j+2)/(j+1),-8*(i+3)/(i+1),10);
context.restore();
}
}
2.3 合成(Compositing)
2.3.1 context . globalAlpha
context . globalAlpha [ = value ] //0-1.0之间的数据,设定图像的透明度
2.3.2 context . globalCompositeOperation
context . globalCompositeOperation [ = value ]
//设定重叠图像的覆盖方式,可以设定为(注,值大小写敏感):
注意:下面所有图例中,B(蓝色方块)是先绘制的,即“已有的canvas 内容”,A(红色圆形)是后面绘制,即“新图形”。
![](https://i-blog.csdnimg.cn/blog_migrate/107f0c347586887601729fcf208eef62.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a2901e31c5b5ec6363c2ae62b9c6aefb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5d748ba893b2d88752cfad6275404d63.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7b750169aca355cc2bbd36b3a45d68ec.png)
2.4 颜色和风格
2.4.1 context. fillStyle
context . fillStyle [ = value ] //返回填充形状的当前风格,能被设置以用来改变当前的填充风格,其值可以是CSS颜色字串,也可以是CanvasGradient或者CanvasPattern对象,非法的值将被忽略。
2.4.2 context. strokeStyle
context . strokeStyle [ = value ] //返回当前描绘形状的风格,能被设置,其值同上。
设置Javascript例子如下:
context.strokeStyle="#99cc33";
context.fillStyle='rgba(50,0,0,0.7)';
context.lineWidth=10;
context.fillRect(20,20,100,100);
context.strokeRect(20,20,100,100);
绘制的图形如下所示。
![](https://i-blog.csdnimg.cn/blog_migrate/1d84d3b032467505b31adc9f2212c178.png)
2.4.3 gradient . addColorStop(offset, color)
gradient . addColorStop(offset, color) //在给定偏移的地方增加一个渐变颜色点,偏移量取值范围为0-1.0之间,否则产生一个INDEX_SIZE_ERR的异常,color为DOM字符串,如果不能解析,则抛出一个SYNTAX_ERR的异常。
2.4.4 context . createLinearGradient(x0, y0, x1, y1)
gradient = context . createLinearGradient(x0, y0, x1, y1) //建立一个线性渐变,如果任何一个参数不是有限值,则抛出一个NOT_SUPPORTED_ERR的异常。
2.4.4.1 addColorStop()
定义和用法
addColorStop()方法规定 gradient 对象中的颜色和位置。
addColorStop()方法与 createLinearGradient() 或 createRadialGradient() 一起使用。
注释:您可以多次调用addColorStop() 方法来改变渐变。如果您不对 gradient 对象使用该方法,那么渐变将不可见。为了获得可见的渐变,您需要创建至少一个色标。
JavaScript语法:
gradient.addColorStop(stop, color);
参数值
参数描述
stop介于 0.0 与 1.0 之间的值,表示渐变中开始与结束之间的位置。
color在结束位置显示的 CSS 颜色值
2.4.4.2 示例1
设置Javascript例子如下:
var gradient = context.createLinearGradient(0, 2, 420, 2);
gradient.addColorStop(0, 'rgba(200, 0, 0, 0.8)');
gradient.addColorStop(0.5, 'rgba(0, 200, 0, 0.7)');
gradient.addColorStop(1, 'rgba(200, 0, 200, 0.9)');
context.strokeStyle = "#99cc33";
context.fillStyle= gradient; //copyright codeex.cn
context.lineWidth = 10;
context.fillRect(20, 20, 400, 100);
context.strokeRect(20, 20, 400, 100);
绘制的图形如下所示。
![](https://i-blog.csdnimg.cn/blog_migrate/92a29abbe99ac0ac02979f22b4cba7ee.png)
2.4.4.3 示例——通过多个addColorStop() 方法来定义渐变
通过多个 addColorStop() 方法来定义渐变:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var grd=ctx.createLinearGradient(0,0,170,0);
grd.addColorStop(0,"black");
grd.addColorStop("0.3","magenta");
grd.addColorStop("0.5","blue");
grd.addColorStop("0.6","green");
grd.addColorStop("0.8","yellow");
grd.addColorStop(1,"red");
ctx.fillStyle=grd;
ctx.fillRect(20,20,150,100);
2.4.5 context. createRadialGradient(x0, y0, r0, x1, y1, r1)
gradient = context . createRadialGradient(x0, y0, r0, x1, y1, r1) //建立一个径向渐变,如果任何一个参数不是有限值,则抛出一个NOT_SUPPORTED_ERR的异常。假如r0或r1为负值,则抛出INDEX_SIZE_ERR的异常。
2.4.5.1 绘制过程
createRadialGradient(x0,y0,r0,x1,y1,r1)方法有六个参数,前三个参数表示开始的圆,其圆点在(x0,y0),半径为r0,后三个表示结束的圆,参数意义同上。其绘制过程如下:
1. 如果起始圆和结束圆重叠,则不绘制任何东西,并终止步骤;
2. x(w) = (x1-x0)w + x0 y(w) = (y1-y0)w + y0 r(w) =(r1-r0)w + r0在以(x(w),y(w))为圆点,r(w)为半径的圆周上所有点的颜色均为Color(w)。
3. 对于任意的w取值(-∞ -- +∞),确保r(w)>0,总是可以知道画布中已知点的颜色。
言而总之:这个效果就是建立一个圆锥体(手电筒效果)渲染效果,圆锥体的开始圆使用开始颜色偏移量为0,圆锥体的结束圆使用颜色偏移量为1.0,面积外的颜色均使用透明黑。
2.4.5.2 示例
设置Javascript例子如下:
var gradient = context.createRadialGradient (100,100, 20, 300,300,80);
gradient.addColorStop(0,'rgba(200,0,0,0.8)');
gradient.addColorStop(1,'rgba(200,0,200,0.9)');
context.strokeStyle="#99cc33";
context.fillStyle= gradient; //'rgba(50,0,0,0.7)';
context.lineWidth=10;
context.fillRect(10,10,400,400);
context.strokeRect(10,10,400,400);
绘制的图形如下所示。
![](https://i-blog.csdnimg.cn/blog_migrate/8449605b5aadcceb107c08951ff5dcbe.png)
2.4.6 context . createPattern(image, repetition)
上面提到可以作为渲染风格还有图案对象:CanvasPattern,其调用格式如下:
pattern = context . createPattern(image, repetition)
本方法用指定的图像和重复方向建立一个画布图案对象,image参数可以为img,canvas,video元素中的任一个,如果不满足此条件,则抛出TYPE_MISMATCH_ERR异常,如果图片编码未知或没有图像数据,则抛出INVALID_STATE_ERR异常;第二个参数可以是下列值:
repeat 默认参数,如果为空,则为此参数,表示两个方向重复
repeat-x 仅水平重复
repeat-y 仅垂直重复
no-repeat 不重复
如果image参数是一个HTMLImageElement对象,但对象的complete属性是false,则执行时抛出INVLAID_STATE_ERR异常;
如果image参数是一个HTMLVideoElement对象,但其readyState属性是HAVE_NOTHING或HAVE_METADATA,则执行时抛出抛出INVLAID_STATE_ERR异常;
如果image参数是一个HTMLCanvasElement对象,但其width属性或height属性是0,则执行时抛出抛出INVLAID_STATE_ERR异常。
图案的绘制时从左上角开始的,根据不同的参数进行重复绘制。如果传递的图片是动画,则选取海报或第一帧作为其绘制图案源,如果使用HTMLVideoElement为对象,则当前播放位置帧被作为图案源。
2.4.6.1 示例
设置HTML的核心代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/1352a33ba67eb56207357030f4b6a2ec.png)
设置Javascript例子如下:
var imgSrc = document.getElementById('psrc')
var pattern = context.createPattern(imgSrc,'repeat');
context.strokeStyle="#99cc33";
context.fillStyle= pattern;//by codeex.cn
context.lineWidth=10;
context.fillRect(10,10,200,220);
context.strokeRect(10,10,200,220);
在IE9中的显示效果如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/1a0dae87b2163ad5d17f298a9dd88a88.png)
2.5 线风格
2.5.1 context . lineCap
操作线风格的方法有4个,格式如下:
context . lineCap [ = value ] //返回或设置线段的箭头样式,仅有三个选项:butt(默认值),round,square;其他值忽略
![](https://i-blog.csdnimg.cn/blog_migrate/1709c390f3e52dde210bb66dd0d2e41b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a8c5e9c72e61fa4e4546add9f33cfb1a.png)
2.5.2 context . lineJoin
context . lineJoin [ = value ] ///返回或设置线段的连接方式,仅有三个选项:miter(默认值),round,bevel;其他值忽略
![](https://i-blog.csdnimg.cn/blog_migrate/3c75b1b672d84e7c1646bfc135913a2e.png)
2.5.3 context . lineWidth
context . lineWidth [ = value ] //返回或设置线段的线宽,非大于0的值被忽略;默认值为1.0;
2.5.4 context . miterLimit
context . miterLimit [ = value ] //返回或设置线段的连接处的斜率,非大于0的值被忽略;默认值为10.0。本属性翻译不够准确,请参看英文部分
2.5.5 线宽
线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半。因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。
想要获得精确的线条,必须对线条是如何描绘出来的有所理解。见下图,用网格来代表canvas 的坐标格,每一格对应屏幕上一个像素点。在第一个图中,填充了 (2,1) 至 (5,5) 的矩形,整个区域的边界刚好落在像素边缘上,这样就可以得到的矩形有着清晰的边缘。
![](https://i-blog.csdnimg.cn/blog_migrate/4c420eced1367be6e5385eb39779b622.png)
如果你想要绘制一条从 (3,1) 到 (3,5),宽度是 1.0的线条,你会得到像第二幅图一样的结果。实际填充区域(深蓝色部分)仅仅延伸至路径两旁各一半像素。而这半个像素又会以近似的方式进行渲染,这意味着那些像素只是部分着色,结果就是以实际笔触颜色一半色调的颜色来填充整个区域(浅蓝和深蓝的部分)。
要解决这个问题,你必须对路径施以更加精确的控制。已知粗 1.0 的线条会在路径两边各延伸半像素,那么像第三幅图那样绘制从(3.5,1) 到 (3.5,5) 的线条,其边缘正好落在像素边界,填充出来就是准确的宽为1.0 的线条。
对于那些宽度为偶数的线条,每一边的像素数都是整数,那么你想要其路径是落在像素点之间(如那从(3,1) 到 (3,5)) 而不是在像素点的中间。如果不是的话,端点上同样会出现半渲染的像素点。
2.6 阴影(Shadows)
有关阴影的四个全局属性将影响所有的绘画操作。有关定义如下:
context . shadowBlur [ = value ] //返回或设置阴影模糊等级,非大于等于0的值被忽略;
context . shadowColor [ = value ] //返回或设置阴影颜色
context . shadowOffsetX [ = value ]
context . shadowOffsetY [ = value ] //返回或设置阴影的偏移量
注意:上面的值均不受坐标转换的影响,可以看做是绝对值。
在上面的例子中增加下列语句,可以得到设置阴影的图像:
context.shadowBlur=7;
context.shadowColor='rgb(200,0,0)';
context.shadowOffsetX = 3;
context.shadowOffsetY=3;
![](https://i-blog.csdnimg.cn/blog_migrate/c0dbceeb7fc91ee885c2ae8ef626532d.png)
2.7 简单形状(矩形)
形状的绘制不影响当前路径(path),形状是剪切区域的主题,也是阴影(Shadow)效果,全局透明(alpha),全局组合(composition)操作等的主题。其由下面三个方法来进行简单的操作:
2.7.1 context. clearRect(x, y, w, h)
context. clearRect(x, y, w, h) \\在给定的矩形内清除所有的像素为透明黑(transparentblack)
2.7.2 context. fillRect(x, y, w, h)
context. fillRect(x, y, w, h) //用当前的填充风格填充给定的区域
2.7.3 context . strokeRect(x, y, w, h)
context. strokeRect(x, y, w, h) //使用当前给定的线风格,绘制一个盒子区域,影响其绘制风格的有:strokeStyle,lineWidth,lineJoin,miterLimit(可能)。
2.8 复杂形状(路径-paths)
绘图上下文总有一个当前路径,并且是仅此一个,它不是绘图状态的一部分。
一个路径有0个或多个子路径列表。每个子路径包含一个或多个点列表(这些点组成直的或弯曲的线段),和一个标识子路径是否闭合的标志。少于两个点的子路径在绘图时被忽略。操作这些形状的方法稍微多些,如下所示:
默认情况下,图形上下文的路径有0个子路径。
2.8.1 路径起始函数
调用格式:
context . beginPath() //清空子路径
context . closePath() //闭合路径
方法概述:
2.8.1.1 context. beginPath()
beginPath方法重设绘图上下文的子路径列表,并清空所有的子路径。
2.8.1.2 context. closePath()
ClosePath方法在绘图上下文如果没有子路径时,什么也不做;否则,它先把最后一个子路径标示为闭合,然后建立一个包含最后子路径的第一个点的子路径,并加入到绘图上下文。有点拗口,其一般可以看为,假如最后一个子路径,我们命名为spN,假设spN有多个点,则用直线连接spN的最后一个点和第一个点,然后关闭此路径和moveTo到第一个点。
2.8.2 绘制函数
调用格式:
context . stroke()
context . fill()
context . clip()
方法概述:
2.8.2.1 context. stroke()
stroke方法使用lineWidth,lineCap,lineJoin,以及strokeStyle对所有的子路径进行填充。
2.8.2.2 context. fill()
fill方法使用fillStyle方式填充子路径,未闭合的子路径在填充式按照闭合方式填充,但并不影响实际的子路径集合。
2.8.2.3 context. clip()
clip方法使用计算所有的子路径而建立新的剪切区域,未闭合的子路径在填充式按照闭合方式填充,但并不影响实际的子路径集合,新的剪切区域将替换当前的剪切区域。
2.8.3 剪切(clip)
裁切路径和普通的 canvas 图形差不多,不同的是它的作用是遮罩,用来隐藏没有遮罩的部分。如下图所示。红边五角星就是裁切路径,所有在路径以外的部分都不会在canvas 上绘制出来。
![](https://i-blog.csdnimg.cn/blog_migrate/f8dbeadc929a7476be1e294ec12282fe.png)
如果和上面介绍的 globalCompositeOperation 属性作一比较,它可以实现与source-in 和 source-atop 差不多的效果。最重要的区别是裁切路径不会在canvas 上绘制东西,而且它永远不受新图形的影响。这些特性使得它在特定区域里绘制图形时相当好用。
2.8.3.1 随机星星示例
效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/eb96aaf2507ac756bc01b4a997f52919.png)
首先,我画了一个与 canvas 一样大小的黑色方形作为背景,然后移动原点至中心点。然后用 clip方法创建一个弧形的裁切路径。裁切路径也属于 canvas 状态的一部分,可以被保存起来。如果我们在创建新裁切路径时想保留原来的裁切路径,我们需要做的就是保存一下canvas 的状态。
裁切路径创建之后所有出现在它里面的东西才会画出来。在画线性渐变时这个就更加明显了。然后在随机位置绘制50 大小不一(经过缩放)的颗,当然也只有在裁切路径里面的星星才会绘制出来。
代码如下:
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.fillRect(0,0,150,150);
ctx.translate(75,75);
// Create a circular clipping path
ctx.beginPath();
ctx.arc(0,0,60,0,Math.PI*2,true);
ctx.clip();
// draw background
var lingrad = ctx.createLinearGradient(0,-75,0,75);
lingrad.addColorStop(0, '#232256');
lingrad.addColorStop(1, '#143778');
ctx.fillStyle = lingrad;
ctx.fillRect(-75,-75,150,150);
// draw stars
for (var j=1;j<50;j++){
ctx.save();
ctx.fillStyle = '#fff';
ctx.translate(75-Math.floor(Math.random()*150), 75-Math.floor (Math. random () *150));
drawStar(ctx,Math.floor(Math.random()*4)+2);
ctx.restore();
}
}
function drawStar(ctx,r){
ctx.save();
ctx.beginPath()
ctx.moveTo(r,0);
for (var i=0;i<9;i++){
ctx.rotate(Math.PI/5);
if(i%2 == 0) {
ctx.lineTo((r/0.525731)*0.200811,0);
} else {
ctx.lineTo(r,0);
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
2.8.4 辅助方法—context. isPointInPath(x, y)
调用格式:
context . isPointInPath(x, y)
方法概述:
给定的坐标(x,y)是否在当前路径中,坐标(x,y)为绘图坐标系坐标,并不受转换的影响。
2.8.5 moveTo方法
调用格式:
context . moveTo(x, y)
方法概述:
建立新的子路径,并制定其第一个点为(x,y)。
2.8.6 lineTo方法
调用格式:
context . lineTo(x, y)
方法概述:
如果绘图上下文没有子路径,则其等同于moveTo(x,y),否则,其建立一条在子路径最后一个点到给定点的直线,并增加(x,y)到子路径中。
2.8.7 rect方法
调用格式:
context . rect(x, y, w, h)
方法概述:
本方法建立二个新的子路径,第一个子路径包含四个点:(x,y),(x+w,y),(x+w,y+h),(x,y+h),四个点的连接方式为直线,该子路径被标示为闭合路径;最后再增加一个子路径,其仅有一个点(x,y)。
![](https://i-blog.csdnimg.cn/blog_migrate/ebbcf5cbd14997429697cb9c132fdc99.png)
2.8.8 圆弧context. arc(x, y, radius, startAngle, endAngle, anticlockwise)
方法调用格式:
context . arc(x, y, radius, startAngle,endAngle, anticlockwise)
方法概述:
本方法先增加一条直线到子路径列表,然后增加一个圆弧子路径到子路径列表。直线子路径是由上一个点到圆弧子路径的起始点,而圆弧则为按照给定的开始角度、结束角度和半径描述的按照给定的方向[布尔类型,anticlockwise-逆时针(true)]圆弧上;假如半径为负值,抛出INDEX_SIZE_ERR的异常;
![](https://i-blog.csdnimg.cn/blog_migrate/2455aa83e074fe12aade87b9cc827ce5.png)
JS代码:
context.beginPath();
context.moveTo(100,50);
context.arc(250,50,50,1.5708,3.14,true);
context.stroke();
注释掉moveTo语句,则仅仅绘制圆弧:
![](https://i-blog.csdnimg.cn/blog_migrate/22941ec652fe7711f72325cae68ec55c.png)
2.8.9 最短圆弧context. arcTo(x1, y1, x2, y2, radius)
方法调用格式:
context . arcTo(x1, y1, x2, y2, radius)
方法概述:
本方法绘制出子路径最后一个点(x0,y0)和(x1,y1)以及(x1,y1)和(x2,y2)构成的两条直线间半径为radius的最短弧线,并用直线连接(x0,y0);假如半径为负值,抛出INDEX_SIZE_ERR的异常;
如图所示,绘制曲线由1,开始绘制。
![](https://i-blog.csdnimg.cn/blog_migrate/a91a46784f26488d3a7fdc4862be7bfb.png)
JS代码如下:
context.beginPath();
context.moveTo(150,50);
context.arcTo(200,50,100,200,20);
context.arcTo(200,50,100,200,40);
context.arcTo(200,50,100,200,80);
context.arcTo(200,50,100,200,120);
context.arcTo(200,50,100,200,160);
context.stroke();
2.8.10 二次方、三次方贝塞尔曲线
贝塞尔曲线的一般概念:在数学的数值分析领域中,贝赛尔曲线(Bezier curve)是电脑图形学中相当重要的参数曲线。更高维度的贝赛尔曲线被称作贝塞尔曲面。对于n阶贝塞尔曲线可如下推断,给定P0、P1、P2…Pn,其贝赛尔曲线即为
![](https://i-blog.csdnimg.cn/blog_migrate/f9c83a95cfbdd3793287f612443ef682.png)
用平常话说,n阶的贝赛尔曲线就是双n-1阶贝赛尔曲线之间的插值。
由公式可以得出二次方贝塞尔曲线公式如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a88af8422bfaa147ad496be72651449d.png)
TrueType字型就运用了以贝塞尔样条组成的二次方贝赛尔曲线。
方法调用格式:
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
quadraticCurveTo(cpx, cpy, x, y)
方法概述:
上面分别是三次贝赛尔曲线和二次贝赛尔曲线的调用格式。其主要区别在于控制曲线的控制点式不一样的。其起始点均为子路径的最后一个点,结束点均为(x,y);在最后均要把(x,y)点加入到子路径中。
其绘制图形的例子如下,三次贝赛尔曲线有两个红点作为曲线平滑的控制点,而二次贝塞尔曲线仅有一个控制点。
![](https://i-blog.csdnimg.cn/blog_migrate/9eaf823d863539d7081d4b5982c5950f.png)
2.8.10.1 二次贝赛尔曲线quadraticCurveTo(cpx, cpy, x,y)
2.8.10.2 三次贝赛尔曲线bezierCurveTo(cp1x, cp1y, cp2x,cp2y, x, y)
2.9 文字
绘图上下文提供了得到和设置文字样式的接口方法。
2.9.1 context.font[=value]
获得和设置文字设置: context.font[=value],可以参考CSS中对font风格的设置。
2.9.2 context.textAlign[=value]
获取或设置文字对齐方式:context.textAlign[=value],取值如下:
start 默认值,与canvas风格中的direction定义有关
end 与canvas风格中的direction定义有关
left 左
right 右
center 居中
2.9.3 context.textBaseline
获得和设置文字对齐基线:context.textBaseline[=value],value的取值如下:
![](https://i-blog.csdnimg.cn/blog_migrate/811cf57b21df65966ce47324e778af64.png)
2.9.4 context.fillText(text, x, y[,maxWidth])
绘制填充的文字,
2.9.5 context.strokeText(text, x, y[,maxWidth])
对文字进行描边,不填充内部区域。
2.9.6 context.measureText(text)
按照当前字体对给定的文字进行测量:
metrics = context.measureText(text),该方法返回一个TextMetrics对象,可以调用对象的width属性得到文字的宽度。
2.10 绘制图片
2.10.1 drawImage方法
要在绘图上下文中绘制图片,可以使用drawImage方法。该方法有三种不同的参数:
![](https://i-blog.csdnimg.cn/blog_migrate/cd8b04bc2116652813db8c1e13a91d81.png)
其中的image参数可以是HTMLImageElement、HTMLCanvasElement和HTMLVideoElement中的任一个对象。
绘制参数的含义可以参看下图:
![](https://i-blog.csdnimg.cn/blog_migrate/e393bb04cf4a4a4102f81d432f0aff63.png)
异常:
如果第一个参数不是指定的元素类型,抛出一个TYPE_MISMATCH_ERR异常,如果图片不能进行解码,则抛出INVALID_STATE_ERR异常,如果第二个参数不是允许的值,则抛出SYNTAX_ERR异常。
参数默认值:
如果没有指定dw和dh,则默认等于sw和sh,如果sx,sy,sw,sh均没有提供,则默认为sx,xy=0,0;sw和sh为图片的像素宽高。
2.10.2 图片调用方式
下面给出图片的几种调用方式:
1.引用页面内图片:
我们可以通过 document.images 集合、document.getElementsByTagName方法又或者document.getElementById 方法来获取页面内的图片(如果已知图片元素的 ID。
2.引用canvas元素
用 document.getElementsByTagName 或document.getElementById 方法来获取其它 canvas 元素。但你引入的应该是已经准备好的canvas。一个常用的应用就是为另一个大的 canvas 做缩略图。
3.创建图像
我们可以用脚本创建一个新的 Image对象,但这种方法的主要缺点是如果不希望脚本因为等待图片装置而暂停,还得需要突破预装载。
var img = new Image(); // Create new Image
img.src = 'myImage.png'; // Set source path
当脚本执行后,图片开始装载。若调用 drawImage 时,图片没装载完,脚本会等待直至装载完毕。如果不希望这样,可以使用onload 事件:
var img = new Image(); // Create new Image
img.onload = function(){
// 执行drawImage 语句
}
img.src = 'myImage.png'; // Set source path
如果你只用到一张图片的话,这已经够了。但一旦需要不止一张图片,那就需要更加复杂的处理方法,但图片预装载策略超出本规范的范围。
4.通过 data: url 方式嵌入图像
我们还可以通过 data: url 方式来引用图像。Data urls 允许用一串Base64 编码的字符串的方式来定义一个图片。其优点就是图片内容即时可用,无须再到服务器兜一圈。(还有一个优点是,可以将 CSS,JavaScript,HTML 和 图片全部封装在一起,迁移起来十分方便。)缺点就是图像没法缓存,图片大的话内嵌的url数据会相当的长,例如:
var img_src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAyCAYAAADLLVz8AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAALESURBVGhD7ZUxSFVhFMfvezi8wcFBSMjhRYNBQUEOQQ4ODYFBQmOLUVtCDQ1By4OGBoeKgkYTh4gGl6CCIByaLDIqKAo0KhIUEmoUX7//49zHh/Tgil4x+F/4c8533nfPPd/Pcz6zzI8JmIAJmIAJmIAJmIAJmIAJmIAJmIAJmIAJmIAJmIAJmIAJmIAJmEC5BCrlps+yZtas842FSlbp+K31bH0yraOaVc+VXdd25a9uV6Kt5AHuGO9/wM5KW8m10+9uqgPppl6kw+7loFNonvUwOoP/g/hd7B8dQvvQYdyXxB7lHUjsBBph/Rbdj71N7D7Wi7HuxY6jW8RW6dDL+M/pzPc5IHJ0Ry37iT1kXw3bozh2AE2x/0vZQAt3IIWpuDkKOo4+4a9xsJPYB6xnBQvdUcHEx/EncAX1YnJowb4X718KAK2f8bVuKAaMFexBdA2N8vN5Yh+TPLWoZUS5Iq7c0/hH0SB6Uja8TeUXFPQ5fYn1DBKo1l2H/xtbw77BXo34EL46TGAn0LQg6d5Dgq93m/g3c4Cxt5/YMlpAx9LvxvvL2K4EaoN97yJfn3IidXKpT+EOpIo9qN0FUZUKVJfpWaJLND4HkMYrH5/vyQkO4evQdfZ+Rc/y3/Bvo0Y+1oyf3tPIdqfdF/v7sIvE1zbQWdGa+FLEVU+pT2GAFPWaSnR/1ZOK5vFPq+vQKbQakJ9iz6pDFE/2C1hXgGrD+tcJk/F+jH9De7BH6DL9EV6RYxBfo/r/PDFmGjeN1QWNCHYOfUO/UAtWHPRnxCbzEd6wX2M+Fvs1bqmGYnwFSaOsq2E4rgzdc7oOrsfo69tXNP7YFznNyJf+sXcH6Ljj+tNqOt01xHs6dJf+m7fvr6Ini05P7z11/u6DVPRA3mcCJmACJmACJmACJmACJmACJmACJmACJmACJmACJmACJrBTBP4C/mNz5egh3WQAAAAASUVORK5CYII=';
有兴趣的朋友可以使用<img src=’上述变量值’>的方法显示出上面的图片。
2.11 像素级操作(good)
2D Context API 提供了三个方法用于像素级操作:createImageData, getImageData, 和putImageData。
ImageData对象保存了图像像素值。每个对象有三个属性: width, height 和data。data 属性类型为CanvasPixelArray,用于储存width*height*4个像素值。每一个像素有RGB值和透明度alpha值(其值为 0 至255,包括alpha在内)。像素的顺序从左至右,从上到下,按行存储。
Canvas提供像素级数据,为很多算法的应用提供了平台,实现photoshop中的众多神奇图像效果在前端都已成为可能。甚至于我们还能实现电影的蓝幕效果——针对video的帧,通过drawImage绘进canvas,再做rgba处理,将规定颜色的像素的alpha值设为0,就能使特定部分变成透明,进而实现视频合成。查看演示
canvas的像素级操作——1.引子
http://cssass.com/blog/2012/1140.html
canvas的像素级操作——2.RGBA通道调色
http://cssass.com/blog/2012/1158.html
canvas的像素级操作——3.使用卷积矩阵
http://cssass.com/blog/2012/1165.html
canvas的像素级操作——4.关注性能
http://cssass.com/blog/2012/1179.html
[Color]彩色转灰度算法彻底学习
http://www.cnblogs.com/zyl910/archive/2006/05/22/2186658.html
在HTML5 的CANVAS 中应用卷积矩阵对图像处理
http://shawphy.com/2011/08/convolution-matrix-in-canvas.html
2.11.1 createImageData方法
imagedata = context . createImageData(sw, sh)
imagedata = context . createImageData(imagedata)
方法概述:
createImageData方法根据给定的CSS像素宽高或指定的imagedata具有的宽高建立一个ImageData对象,该对象为透明黑。该方法具体实例化一个新的空ImageData对象。
2.11.2 getImageData方法
imagedata = context . getImageData(sx,sy,sw, sh)
方法概述:
getImageData方法根据给定的绘图画布矩形面积(sx,sy,sw,sh),生成画布上该矩形面积的图形内容,并综合为ImageData对象返回。画布外的像素作为透明黑返回。
2.11.3 putImageData方法
imagedata = context . putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])
方法概述:
在绘图画布上绘制给定的ImageData对象。假如脏矩形被提供,则只有在脏矩形上面的像素被绘制。本方法对全局透明、阴影和全局组合属性均忽略。
异常:假如第一个参数不是ImageData对象,抛出TYPE_MISMATCH_ERR异常,假如任一数字参数是无穷或非数字,则抛出NOT_SUPPORTED_ERR错误。
putImageData参数有(ImageData,dx, dy [, DirtyX] [, DirtyX] [, DirtyWidth] [, DirtyHeight])
imageData:包含了图像的width,height,还有一个CanvasPixelArray,前面已经提了。
dx, dy:表示绘图起始位置。相对于canvas区域左上角。
后面四个可选参数:表示可见区范围。相对于起绘点,即上面的参数dx,dy表示的点。缺省为0,0,ImageData.width,ImageData.height。
2.11.3.1 具体用法
通过将源canvas中像素数据ImageData,输出(putImageData)到新的canvas中,达到复制作用。
![](https://i-blog.csdnimg.cn/blog_migrate/a53b5ffbb44283e75a0845165e579680.png)
<script type="text/javascript">
function draw(){
/*在canvas中绘制image*/
var canvas1 =document.getElementById("MyCanvas");
var ctx1 =canvas1.getContext("2d");
ctx1.drawImage(imgObj,0,0);
}
function clone(){
/*在canvas2中绘制canvas1——普通复制*/
var origin =document.getElementById("MyCanvas");
var canvas2 =document.getElementById("YourCanvas");
var ctx2 =canvas2.getContext("2d");
ctx2.drawImage(origin,0,0);//drawImage不仅可以绘image,也可以绘canvas对象,甚至还可以绘video的帧
}
function cloneData(canvasObj){
/*获取canvas1中的ImageData,在canvas3中输出 ——像素级复制*/
var origin =document.getElementById("MyCanvas");
var canvas3 =document.getElementById("GodCanvas");
var ctx3 =canvas3.getContext("2d");
var canvasCtx = origin.getContext("2d");
var imagePix = canvasCtx.getImageData(0,0,origin.width,origin.height); //获取canvas1绘图环境下的参数范围内的imageData。
ctx3.putImageData(imagePix,0,0); //putImageData输出图像
}
/* 以下与示例代码无关*/
function Load(canvas){
/* canvas Loading效果*/
var backCtx =canvas.getContext('2d');
backWidth= canvas.width;
backHeight= canvas.height;
var drawIntervalID,
spokes= 7;
var drawPad =document.createElement('canvas');
drawPad.width= 30;
drawPad.height= 30;
var drawCtx = drawPad.getContext('2d');
drawCtx.translate(drawPad.width/2,drawPad.height/2);
drawCtx.lineWidth= 5;
drawCtx.lineCap= "round";
drawCtx.strokeStyle= "rgba(0,0,0,0.1)";
drawCtx.fillStyle= "#fff";
var draw =function(){
drawCtx.fillRect(0,0,drawPad.width ,drawPad.height);
drawCtx.rotate(Math.PI*2/spokes);
for(var i=0; i
drawCtx.rotate(Math.PI*2/spokes);
drawCtx.beginPath();
drawCtx.moveTo(0,8);
drawCtx.lineTo(0,10);
drawCtx.stroke();
}
backCtx.drawImage(drawPad,(backWidth- drawPad.width)/2, (backHeight - drawPad.height)/2);
}
this.loading =function(){
drawIntervalID = setInterval(draw,200);
}
this.loaded =function(){
clearInterval(drawIntervalID);
backCtx.clearRect((backWidth- drawPad.width)/2, (backHeight - drawPad.height)/2, drawPad.width,drawPad.height);
}
}
var imgObj = document.getElementById("imgObj");
var canvas = document.getElementsByTagName('canvas');
for(var i = 0, l = canvas.length; i < l; i++ ){
var loadObj = newLoad(canvas[i]);
(function(obj){
obj.loading();
imgObj.addEventListener('load',obj.loaded,false);
})(loadObj);
}
imgObj.addEventListener('load',function(){
draw();
clone();
cloneData();
},false);
</script>
2.11.4 示例
下面展示了对一张图片进行反色、透明的一个例子,从例子中可以看出,有了像素级的控制能力,我们可以很轻易的对原有图片进行各种图像滤镜操作。图示如下:
![](https://i-blog.csdnimg.cn/blog_migrate/eae113e9c249fa16df91cf6bff58b1b5.png)
JS代码:[当你在word中选择上面的图片,会发现反色滤镜常用在选择操作里]
var imgSrc = document.getElementById('codeex.cn')
context.drawImage(imgSrc,10,10);
var imgd = context.getImageData(10,10,100,122);
var pix = imgd.data;
//反色处理
for(var i=0,n=pix.length;i
{
pix[i] = 255 - pix[i]; //红
pix[i+1] = 255-pix[i+1]; //绿
pix[i+2] = 255-pix[i+2]; //蓝
pix[i+3] = pix[i+3]; //alpha
}
context.putImageData(imgd,130,10);
imgd = context.getImageData(10,10,100,122);
pix = imgd.data;
//透明处理 透明度0.6
for(var i=0,n=pix.length;i
{
pix[i] = pix[i]; //红
pix[i+1] = pix[i+1]; //绿
pix[i+2] = pix[i+2]; //蓝
pix[i+3] = pix[i+3]*0.6; //alpha
}
context.putImageData(imgd,260,10);
2.11.5 性能优化示例
canvas像素级操作
http://blog.sina.com.cn/s/blog_502364000100qwc8.html
2.12 绘图模型
在本文描述的画布中绘图,浏览器一般按照下面的顺序进行绘制:
1.准备形状或图片,此时图片假设为A,形状必须被所有属性描述的形状,且经过坐标转换;
2.当绘制阴影时,准备图片A,并绘制阴影,形成图片B;
3.当绘制阴影时,为B的每个像素乘上alpha值;
4.当绘制阴影时,则根据组合参数对B和本画布剪贴区域内的图片进行组合;
5.在图片A上每个像素乘上alpha值;
6.在图片A上根据组合参数对A和本画布剪贴区域内的图片进行组合;
3 Canvas动画库——KineticJS
以下教程是根据2012年教程整理的,部分接口有调整,后续注意逐步整理更新
KineticJS中文系列教程
How It Works
https://github.com/ericdrowell/KineticJS/wiki
4 Canvas动画库——Collie
Collie——基于 HTML5 的高性能
JavaScript 动画库
http://www.cnblogs.com/lhb25/archive/2012/12/17/create-highly-optimized-animations-using-html5.html
5 Canvas动画库——EaselJS
EaselJS(CreateJS)屏幕适配
CreateJS基础
http://www.jikexueyuan.com/course/276.html
6 特效合集
6.1 星星图形
function drawStar(ctx,r){
ctx.save();
ctx.beginPath()
ctx.moveTo(r,0);
for (var i=0;i<9;i++){
ctx.rotate(Math.PI/5);
if(i%2 == 0) {
ctx.lineTo((r/0.525731)*0.200811,0);
} else {
ctx.lineTo(r,0);
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
7 参考链接
HTML5 canvas addColorStop() 方法
http://www.w3school.com.cn/tags/canvas_addcolorstop.asp
canvas像素级操作
http://blog.sina.com.cn/s/blog_502364000100qwc8.html
专栏——HTML5 Canvas编程
http://blog.csdn.net/column/details/canvas-programming.html
专栏——html5 Canvas画图系列教程目录
http://jo2.org/html5-canvas-tutorial-list/
[Canvas系列]Canvas绘制圆弧形状_04
http://blog.csdn.net/baihuaxiu123/article/details/53619435
HTML5 Canvas 画圆教程
http://www.108js.com/article/article7/70206.html?id=1036
6.5 径向渐变