canvas学习
准备
定义 canvas 元素,以及 css 样式,使用 javascript 进行 canvas 绘制。
canvas 的绘制步骤:先描述状态,再使用绘制函数绘制。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas学习</title>
</head>
<style type="text/css">
#canvas{
display: block;
margin: 0 auto;
border: 1px solid #aaa;
}
</style>
<body>
<canvas id="canvas" width="1000" height="800">
您的浏览器不支持canvas
</canvas>
</body>
<script type="text/javascript">
// 使用context绘制
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
</script>
</html>
绘制基础
context设置
// 使用beginPath()以及closePath()来隔离两段状态
context.beginPath();
// 使用closePath()函数时,会自动将最终坐标与最初坐标用直线连接,可以不使用closePath()函数;
// 如果使用了fill()填充了颜色,closePath()不起作用
context.closePath();
// 设置了context的一些形状操作后,相关值会有叠加;可以保存和恢复context来重置,save()以及restore()
context.save();
context.restore();
// 清除canvas的内容
context.clearRect(x,y,w,h)
设置背景
简单设置
context.fillStyle="";
context.strokeStyle="";
// 设置以下值
1. #ffffff
2. #642
3. rgb(255,255,0)
4. rgba(100,100,100,0.6)
5. hsl(20,60%,60%)
6. hsla(20,60%,80%,0.6)
7. red
渐变设置
-
线性渐变
// 从(xtart,ystart)坐标到(xend,yend)的线性渐变 // grd=context.createLinearGradient(xstart,ystart,xend,yend); // 在stop处设置color,stop取值 0~1 的浮点值 // grd.addColorStop(stop,color); var grd=context.createLinearGradient(0,0,800,0); grd.addColorStop(0.0,"red"); grd.addColorStop(1.0,"yellow"); context.fillStyle=grd;
-
径向渐变
// 从圆心坐标(x0,y0)半径为r0的圆到圆心坐标(x1,y1)半径为r1的圆坐标之间的径向渐变 // grd=context.createRadialGradient(x0,y0,r0,x1,y1,r1); // 在stop处设置color,stop取值 0~1 的浮点值 // grd.addColorStop(stop,color); var grd=context.createRadialGradient(100,100,0,100,100,100); grd.addColorStop(0.0,"red"); grd.addColorStop(1.0,"yellow"); context.fillStyle=grd;
设置图片背景
context.createPattern(img,repeat-style)
repeat-style 可选值:no-repeat、repeat-x、repeat-y、repeat
var context=canvas.getContext("2d");
//将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像
var image=new Image();
image.src="img/UI-bc-2.png";
image.onload=function(){
// 必须在图像加载完之后再绘制
var pattern = context.createPattern(image,"no-repeat");
context.fillStyle=pattern;
context.fillRec(0,0,800,800);
}
createPattern() 既可以将 image 作为填充,也可以将 canvas、video 作为填充
线条属性
-
context.lineWidth
线条宽度 -
context.lineCap
设置线条尾部的突出一部分的形状可取值:butt(default---不突出)、round(圆形)、square(方形)
-
context.lineJoin
设置两条线的相交点的形状可取值:miter(default---形成尖角)、bevel(不会有尖角)、round(形成圆角)
-
context.miterLimit
只有当 lineJoin 设置为 miter 时有效,默认是10,代表两条线的相交产生的尖角长度超过10个像素时,会使用 bevel 属性相交特点。
位移、旋转、缩放操作
-
context.translate(x,y)
将图形 x 轴移动 x , y 轴移动 y -
context.rotate(deg)
将图形旋转 -
context.scale(sx,sy)
将图形 x 方向缩放 sx 倍,y 方向缩放 sy 倍,会应用到一个图形的所有属性上,例如坐标值,线条宽度等。。。 -
context.transform(a,b,c,d,e,f)
以矩阵方式进行设置a :水平缩放 1
b :水平倾斜 0
c :垂直倾斜 0
d :垂直缩放 1
e :水平位移 0
f :垂直位移 0
相当于以下矩阵:
a c e
b d f
0 0 1
如果进行多次以上操作,这些值会叠加,如果需要清除之前的操作,可以使用以下方法:
// 保存和恢复context,save()以及restore()
context.save();
context.translate(100,100);
context.restore();
// 重设transform,可以使用setTransform()
context.setTransform(1,0,0,1,100,100);
绘制
直线绘制
// 使用beginPath()以及closePath()来隔离两段状态
context.beginPath();
// 从(100,100)画到(700,700)的直线
context.moveTo(100,100);
context.lineTo(700,700);
// 可以使用多个context.lineTo()来绘制多边形,会按照先后定义的坐标值按照先后顺序画
context.lineTo(100,700);
context.lineTo(100,100);
// 使用strokeStyle来绘制线条颜色
context.strokeStyle="red";
context.lineWidth=5;
context.closePath();
// stroke()函数画线条
context.stroke();
// 填充画出的区域
context.fillStyle="blue";
context.fill();
弧绘制
基于圆绘制
context.arc(centerx,centery,radius,startAngle,endAngle,antclockwise=false)
说明:
-
centerx --- 圆心的x轴坐标
-
centery --- 圆心的y轴坐标
-
radius --- 半径
-
startAngle --- 开始弧度值
-
endAngle --- 结束弧度值
弧度值从最右边的坐标开始算起,0*Math.PI - 0.5*Math.PI - 1*Math.PI - 2*Math.PI
-
antclockwise --- 弧度绘制方向,false:顺时针;true:逆时针
context.strokeStyle="red";
context.lineWidth=3;
context.arc(300,300,100,0,1.5*Math.PI);
context.stroke();
弧度绘制
context.arcTo(x1,y1,x2,y2,radius)
以上一个绘制出的最后一个点为 (x0,y0) ,必须有上一个绘制的最终点或者moveTo()定点,根据 (x0,y0)、(x1,y1)、(x2,y2) 三个坐标绘制一个三角形,形成一个与 (x0,y0) 和 (x1,y1) 的直线和 (x1,y1) 和 (x2,y2) 的直线相切的半径为 radius 的圆弧。切点不一定是 (x0,y0) 和 (x2,y2) 。
!!! 以下贝塞尔曲线需要多次试验才好控制 !!!
二次贝塞尔曲线
context.quadraticCurveTo(x1,y1,x2,y2)
必须有上一个绘制的最终点或者moveTo()定点
(x1,y1) 作为控制点,(x2,y2) 作为结束点
三次贝塞尔曲线
context.bezierCurveTo(x1,y1,x2,y2,x3,y3)
必须有上一个绘制的最终点或者moveTo()定点
(x1,y1)、(x2,y2) 作为控制点,(x3,y3) 作为结束点
矩形绘制
var context=canvas.getContext("2d");
//绘制一个红色的方形,左上坐标(100,100),右下坐标(100+400,100+400)
context.fillStyle="red";
// 方法一
context.rect(100,100,400,400);
context.stroke();
// 方法二
context.fillRect(100,100,400,400);
// 方法三
context.strokeRect(100,100,400,400);
context.fill();
图像绘制
简单绘制
context.drawImage(image,dx,dy)
var context=canvas.getContext("2d");
//将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像
var image=new Image();
image.src="img/UI-bc-2.png";
image.onload=function(){
// 必须在图像加载完之后再绘制
context.drawImage(image,50,50);
}
改变宽高
context.drawImage(image,dx,dy,dw,dh)
var context=canvas.getContext("2d");
//将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像,并修改图片的宽高分别为dw,dh
var image=new Image();
image.src="img/UI-bc-2.png";
image.onload=function(){
// 必须在图像加载完之后再绘制
context.drawImage(image,50,50,200,200);
}
部分图像绘制
context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
将 source 图片的 (sx,sy) 坐标之后的宽为sw,高为sh的图片,根据(dx,dy,dw,dh)参数映射到 canvas 中。
var context=canvas.getContext("2d");
//将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像,并修改图片的宽高分别为dw,dh
var image=new Image();
image.src="img/UI-bc-2.png";
image.onload=function(){
// 必须在图像加载完之后再绘制
// 截取原图片的一部分图片映射到canvas中
context.drawImage(image,50,50,500,500,0,0,canvas.width,canvas.height);
}
缩放绘制
// 添加 range 滑杆控件以及样式,并通过滑杆值的改变来缩放图片
// #range{
// display: block;
// margin: 20px auto;
// width: 300px;
// }
// <input type="range" name="" id="range" min="0.5" max="3.0" step="0.01" value="1.0" />
var slider=document.getElementById("range");
//获取滑杆的值
var scale=slider.value;
//将一个图像绘制到canvas中
var image=new Image();
image.src="img/UI-bc-2.png";
image.onload=function(){
// 必须在图像加载完之后再绘制
// 根据缩放比例显示图片
drawImageByScale(scale,image);
// 根据滑杆的移动来改变图片的显示比例
slider.onmousemove=function(){
scale=slider.value;
drawImageByScale(scale,image);
}
}
function drawImageByScale(scale,image){
//清除 canvas 内容
context.clearRect(0,0,canvas.width,canvas.height);
// 计算应显示的图片宽高
var imageWidth=image.width*scale;
var imageHeight=image.height*scale;
// 方法一,裁剪图片来放大图片但是缩小图片时需要另写判断程序,以下程序不完全
// 计算sx,sy
var sx=imageWidth/2-canvas.width/2;
var sy=imageHeight/2-canvas.height/2;
context.drawImage(image,sx,sy,canvas.width,canvas.height, 0,0,canvas.width,canvas.height);
// 方法二,修改图片的(dx,dy)值来缩小放大图片
var dx=canvas.width/2-imageWidth/2;
var dy=canvas.height/2-imageHeight/2;
context.drawImage(image,dx,dy,imageWidth,imageHeight);
}
双canvas绘制
// 将 canvas_2 的图像绘制在 context 所代表的 canvas 上
context.drawImage(canvas_2,canvas.width-canvas_2.width,canvas.height-canvas_2.height);
像素绘制
-
获取一个 canvas 的图像
imageData=context.getImageData(x,y,w,h);
可以获取到 imageData 的 width、height、data
-
将获取到的图像放到 canvas 中
context.putImageData(imageData,x,y,imageDataX,imageDataY,imageDataW,imageDataH)
-
创建imageDta
imageData=context.createImageData(w,h)
imageData 的data中存储了所有像素,计算方式如下:
- 第i个像素:r=imageData.data[4*i+0];g=imageData.data[4*i+1];b=imageData.data[4*i+2];a=imageData.data[4*i+3]
- 第x行第y列的像素:i=x*width+y,r/g/b/a的计算方式仍如上所示。
文字渲染
-
context.font
可设置font-style(normal、italic---斜体字、oblique---倾斜文字)、font-variant(normal、small-caps---英文小写字母更有效)、font-weight(lighter、normal、bold、bolder、100-900)、font-size、font-family(支持@font-face),默认"20px sans-serif"
-
context.textAlign 文本水平对齐方式
left、right、center
-
context.textBaseline 文字垂直对齐方式
top、middle、bottom
alphabetic(为拉丁语准备的)、ideographic(为汉字等方块文字准备的)、hanging(为印度语准备的)
-
context.measureText(string).width 文本度量
获取在canvas中渲染文字所占的宽度
// 设置文字和位置,显示文字线条和位置
// context.fillText(string,x,y,[maxlen]);
// context.strokeText(string,x,y,[maxlen]);
// 也可以使用fillStyle来设置文字的颜色
context.font="bold 40px Arial";
context.fillText("canvas",100,100);
context.fillText("canvas",100,100,200);
阴影绘制
context.shadowColor
阴影颜色context.shadowOffsetX
阴影 x 轴的偏移量context.shadowOffsetY
阴影 y 轴的偏移量context.shadowBlur
阴影的模糊程度
其他属性
-
context.globalAlpha
这是一个全局变量的透明度设置,取值:0~1 -
context.globalCompositeOperation
图形重叠时的处理方式取值:
source-over(后绘制的覆盖前绘制的---默认)
destination-over(前覆盖后)
source-atop(显示前绘制的图形以及处于前绘制的图形中的后绘制图形的部分)
source-in(只显示处于前绘制的图形中的后绘制图形的部分)
source-out(只显示处于前绘制的图形之外的后绘制图形的部分)
destination-atop(显示后绘制的图形以及处于后绘制的图形中的前绘制图形的部分)
destination-in(只显示处于后绘制的图形中的前绘制图形的部分)
destination-out(只显示处于后绘制的图形之外的前绘制图形的部分)
lighter(重叠部分的颜色会混合重叠双方的颜色)
copy(只绘制后绘制的)
xor(重叠部分没有颜色)
-
context.clip()
剪辑区域使用之前绘制的图形作为剪辑区域
-
按照非零环绕原则确认路径方向以及封闭区域的内外
-
context.isPointInPath(x,y)
(x,y)是否在之前绘制的区域内 -
canvas.getBoundingClientRect()
获取canvas的边距示例使用:canvas.getBoundingClientRect().left
高级拓展
自定义库函数
允许将自定义的画图函数添加到context中。
CanvasRenderingContext2D.prototype.fillStar=function(){
// ...
}
context.fillStar();
// 记录MoveTo的坐标
var originalMoveTo=CanvasRenderingContext2D.prototype.moveTo;
CanvasRenderingContext2D.prototype.lastMoveToLoc={}
// 重写函数
CanvasRenderingContext2D.prototype.moveTo=function(x,y){
// 调用原函数
originalMoveTo.apply(context,[x,y]);
this.lastMoveToLoc.x=x;
this.lastMoveToLoc.y=y;
}