###canvas基本用法
1.什么是canvas(画布)
<canvas> 是 HTML5 新增的元素,可用于通过使用JavaScript中的脚本来绘制图形;
例如,它可以用于绘制图形,创建动画。<canvas> 最早由Apple引入WebKit;
我们可以使用<canvas>标签来定义一个canvas元素;
----->使用<canvas>标签时,建议要成对出现,不要使用闭合的形式。
----->canvas元素默认具有高宽 width: 300px ; height:150px
2.替换内容
<canvas>很容易定义一些替代内容。
由于某些较老的浏览器(尤其是IE9之前的IE浏览器), 不支持HTML元素"canvas",
但在这些浏览器上你应该要给用户展示些替代内容。
这非常简单:我们只需要在<canvas>标签中提供替换内容就可以。
<canvas id="test" width="300" height="300"> <span>您的浏览器不支持画布元素 请您换成支持的浏览器!!</span> </canvas>
--->支持<canvas>的浏览器将会忽略在容器中包含的内容,并且只是正常渲染canvas。
--->不支持<canvas>的浏览器会显示代替内容
3.canvas标签的两个属性
<canvas id="test" width="500" height="500"></canvas>
<canvas> 看起来和 <img> 元素很相像,唯一的不同就是它并没有 src 和 alt 属性。
实际上,<canvas> 标签只有两个属性—— width和height。这些都是可选的。
当没有设置宽度和高度的时候,canvas会初始化宽度为300px和高度为150px。
画布的高宽 : 一定要使用html的attribute的形式来定义画布的宽高
html属性设置width height时只影响画布本身不影画布内容
css属性设置width height时不但会影响画布本身的高宽,
还会使画布中的内容等比例缩放(缩放参照于画布默认的尺寸)
4.渲染上下文
<canvas> 元素只是创造了一个固定大小的画布,要想在它上面去绘制内容,我们需要找到它的渲染上下文, 有一个叫做 getContext() 的方法,这个方法是用来获得渲染上下文和它的绘画功能。
getContext()只有一个参数,上下文的格式
·----->获取方式:
var canvas = document.getElementById('box'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); }
###canvas绘制矩形
HTML中的元素canvas只支持一种原生的图形绘制:矩形。
所有其他的图形的绘制都至少需要生成一条路径.
1.绘制矩形
canvas提供了三种方法绘制矩形:
---->绘制一个填充的矩形(填充色默认为黑色)
fillRect(x, y, width, height) ctx.fillRect(0,0,100,100)
---->绘制一个矩形的边框(默认边框为:一像素实心黑色)
strokeRect(x, y, width, height) ctx.strokeRect(100,100,100,100)
strokeRect时,边框像素渲染问题,按理渲染出的边框应该是1px的,
canvas在渲染矩形边框时,边框宽度是平均分在偏移位置的两侧。
ctx.strokeRect(10,10,50,50)
: 边框会渲染在10.5 和 9.5之间,浏览器是不会让一个像素只用自己的一半的
相当于边框会渲染在9到11之间
---->清除指定矩形区域,让清除部分完全透明。
clearRect(x, y, width, height) ctx.clearRect(100,100,100,100)
ctx.clearRect(0,0,canvas.width,canvas.height) 清除整个画布
x与y指定了在canvas画布上所绘制的矩形的左上角(相对于原点)的坐标。
width和height设置矩形的尺寸。(存在边框的话,边框会在width上占据一个边框的宽度,height同理)
2.添加样式和颜色
---->fillStyle :设置图形的填充颜色。 (默认值:CSS 颜色值 #000000 黑色)
ctx.fillStyle="deeppink";
---->strokeStyle :设置图形轮廓的颜色。 (默认值:CSS 颜色值 #000000 黑色)
ctx.strokeStyle="pink";
---->lineWidth : 设置当前绘线的粗细。属性值必须为正数,默认值是1.0。
ctx.lineWidth=25;
---->lineJoin: 设定线条与线条间接合处的样式(默认是 miter)
round : 圆角 bevel : 斜角 miter : 直角
ctx.lineJoin="round";
---->lineCap :绘制每一条线段末端 (默认值是 butt)
butt :线段末端以方形结束。
round :线段末端以圆形结束
square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域
###canvas绘制路径
图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成不同形状的点的集合。
1.绘制三角形
----> beginPath() ctx.beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上准备生成路径。
生成路径的第一步叫做beginPath()。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中, 所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置, 然后我们就可以重新绘制新的图形。
---->moveTo(x, y) ctx.moveTo(x,y)
将笔触移动到指定的坐标x以及y上
当canvas初始化或者beginPath()调用后,你通常会使用moveTo()函数设置起点
---->lineTo(x, y) ctx.lineTo(x,y)
将笔触移动到指定的坐标x以及y上
绘制一条从当前位置到指定x以及y位置的直线。
---->closePath() ctx.closePath( )
闭合路径之后图形绘制命令又重新指向到上下文中。
闭合路径closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。
如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做
当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()函数。
但是调用stroke()时不会自动闭合
---->fill() ctx.fill( )
通过填充路径的内容区域生成实心的图形。
自动调用closePath()
---->stroke() ctx.stroke( )
通过线条来绘制图形轮廓。
不会自动调用closePath()
2.绘制矩形
----> rect(x, y, width, height)
绘制一个左上角坐标为(x,y),宽高为width height的矩形。
当该方法执行的时候,moveTo()方法自动设置坐标参数(0,0)。
也就是说,当前笔触自动重置会默认坐标
3.绘制圆形
---->arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise(值为 ture:逆时针, false:顺时针)给定的方向来生成(默认为顺时针)。
x,y为绘制圆弧所在圆上的圆心坐标
radius为半径
startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准
anticlockwise 为布尔值。为true时,是逆时针方向,否则顺时针方向。
----> arcTo(x1, y1, x2, y2, radius)
2个坐标,一个半径,结合moveTo(x,y)方法使用:
x,y:起始点,x1,y1:控制点, x2,y2:结束点
根据给定的控制点和半径画一段圆弧
肯定会从(x1 y1) 但不一定经过(x2 y2) ; (x2 y2)只是控制一个方向
4.贝塞尔曲线
----> quadraticCurveTo(cp1x, cp1y, x, y) 二次贝塞尔
cp1x,cp1y为一个控制点,x,y为结束点。起始点为moveto时指定的点
必须经过起点和终点
----> bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 三次贝塞尔
cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。起始点为moveto时指定的点
必须经过起点和终点
5.变换
----> translate(x, y) 移动 canvas的原点到一个不同的位置。
接受两个参数。x 是左右偏移量,y 是上下偏移量,
在canvas中translate是累加的
----> rotate(angle)
旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate 方法
在canvas中rotate是累加的
---->scale(x, y)
x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值。
值比 1.0 小表示缩小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。
放大:放大画布,画布中的一个css像素所占据的物理面积变大,画布中包含的css像素的个数变少,画布中图像所包含的css像素的个数不变
缩小:缩小画布,画布中的一个css像素所占据的物理面积变小,画布中包含的css像素的个数变多,画布中图像所包含的css像素的个数不变
在canvas中scale是累加的
6. save restore
---->save() 是 Canvas 2D API 通过将当前状态放入栈中,保存 canvas 全部状态的方法
保存到栈中的绘制状态有下面部分组成:
当前的变换矩阵。 当前的剪切区域。 当前的虚线列表.
以下属性当前的值: strokeStyle,fillStyle, lineWidth, lineCap, lineJoin...
ctx.save()
将画布当前状态(样式相关 变换相关)压入到样式栈中
---->restore() 是 Canvas 2D API 通过在绘图状态栈中弹出顶端的状态,将 canvas 恢复到最近的保存状态的方法。
如果没有保存状态,此方法不做任何改变。
ctx.restore()
将样式栈中栈顶的元素弹到样式容器中
图像最终渲染依赖于样式容器
###在canvas中操作图片
1.在canvas中插入图片(需要image对象)
canvas操作图片时,必须要等图片加载完才能操作
----> drawImage(image, x, y, width, height) ctx.drawImage(img,x,y,width,height)
其中 image 是 image 或者 canvas 对象,x 和 y 是其在目标 canvas 里的起始坐标。
这个方法多了2个参数:width 和 height,这两个参数用来控制 当像canvas画入时应该缩放的大小
window.onload=function(){ var canvas = document.querySelector("#test"); if(canvas.getContext){ var ctx = canvas.getContext("2d"); var img = new Image(); img.src="tg.png"; img.onload=function(){ ctx.drawImage(img,0,0,img.width,img.height) } } }
2. 在canvas中设置背景(需要image对象)
----> createPattern(image, repetition)
image:图像源
epetition: "repeat"/ "repeat-x" / "repeat-y" / "no-repeat"
一般情况下,我们都会将createPattern返回的对象作为fillstyle的值
img.onload=function(){ var pattern = ctx.createPattern(img,"no-repeat") ctx.fillStyle = pattern; ctx.fillRect(0,0,300,300); }
3.渐变
----> createLinearGradient(x1, y1, x2, y2) 线性渐变
表示渐变的起点 (x1,y1) 与终点 (x2,y2)
----> gradient.addColorStop(position, color)
gradient :createLinearGradient的返回值
addColorStop 方法接受 2 个参数,position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1) )
window.onload=function(){ var canvas = document.querySelector("#test"); if(canvas.getContext){ var ctx = canvas.getContext("2d"); var gradient = ctx.createLinearGradient(0, 0, 200, 200); gradient.addColorStop(0,"red"); gradient.addColorStop(0.5,"yellow"); gradient.addColorStop(0.7,"pink"); gradient.addColorStop(1,"green"); ctx.fillStyle = gradient; ctx.fillRect(0,0,300,300); } }
----> createRadialGradient(x1, y1, r1, x2, y2, r2) 径向渐变
前三个参数则定义另一个以(x1,y1) 为原点,半径为 r1 的圆,
后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
window.onload=function(){ var canvas = document.querySelector("#test"); if(canvas.getContext){ var ctx = canvas.getContext("2d"); var gradient = ctx.createRadialGradient(150, 150, 50, 150, 150, 100); gradient.addColorStop(0,"red"); gradient.addColorStop(0.5,"yellow"); gradient.addColorStop(0.7,"pink"); gradient.addColorStop(1,"green"); ctx.fillStyle = gradient; ctx.fillRect(0,0,300,300); } }
4.绘制文本
1.绘制文本
----> fillText(text, x, y) 在指定的(x,y)位置填充指定的文本
ctx.fillText("张三",100,100);
----> strokeText(text, x, y) 在指定的(x,y)位置绘制文本边框
ctx.strokeText("张三",100,100);
2.文本样式
----> font = value ctx.font="40px sans-serif"
默认的字体是 10px sans-serif。
font属性在指定时,必须要有大小和字体 缺一不可
----> textAlign = value ctx.textAlign="right";
文本对齐选项. 可选的值包括: left, right center.
left 文本左对齐。 right 文本右对齐。 center 文本居中对齐。
textAlign的值为center时候, 文本的居中是基于你在fillText的时候所给的x的值,
也就是说文本一半在x的左边,一半在x的右边
----> textBaseline = value ctx.textBaseline="middle";
描述绘制文本时,当前文本基线的属性。
top 文本基线在文本块的顶部。
middle 文本基线在文本块的中间。
bottom 文本基线在文本块的底部。
3. measureText() 方法
返回一个 TextMetrics 对象,包含关于文本尺寸的信息(例如文本的宽度)
ctx.fillText("张三",50,50);
var obj = ctx.measureText("张三");
4.canvas中文本水平垂直居中
window.onload = function(){ var canvas =document.getElementById('box'); var ctx = canvas.getContext('2d'); ctx.font = '60px impact'; ctx.textBaseline = 'middle'; var w = ctx.measureText('张三').width; ctx.fillText('张三',(canvas.width - w)/2 , (canvas.height - 60)/2); };
5. 阴影(文本阴影&盒模型阴影)
----> shadowOffsetX = float ctx .shadowOffsetX = 20;
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,
它们默认都为 0。
----> shadowOffsetY = float ctx.shadowOffsetY = 20;
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,
它们默认都为 0。
----> shadowBlur = float ctx.shadowBlur = 30;
shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。
----> shadowColor = color(必需项) ctx.shadowColor = "yellow";
shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色
5.像素操作
直接通过ImageData对象操纵像素数据,直接读取或将数据数组写入该对象中
---->ImageData对象
ImageData对象中存储着canvas对象真实的像素数据,它包含以下几个只读属性:
width:图片宽度,单位是像素,值为横向上像素点的个数
height:图片高度,单位是像素,值为纵向上像素点的个数
data:Uint8ClampedArray类型的一维数组,
包含着RGBA格式的整型数据,范围在0至255之间(包括255)
R:0 --> 255(黑色到白色)
G:0 --> 255(黑色到白色)
B:0 --> 255(黑色到白色)
A:0 --> 255(透明到不透明)
---->ctx.getImageData(sx, sy, sw, sh) 获得场景像素数据
获得一个包含画布场景像素数据的ImageData对像,它代表了画布区域的对象数据
sx:将要被提取的图像数据矩形区域的左上角 x 坐标。
sy:将要被提取的图像数据矩形区域的左上角 y 坐标。
sw:将要被提取的图像数据矩形区域的宽度。
sh:将要被提取的图像数据矩形区域的高度。
----> putImageData(myImageData, dx, dy) 在场景中写入像素数据
dx和dy参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标
----> ctx.createImageData(width, height); 创建一个ImageData对象
width : ImageData 新对象的宽度。
height: ImageData 新对象的高度。 默认创建出来的是透明的
window.onload=function(){ var canvas = document.querySelector("#test"); if(canvas.getContext){ var ctx = canvas.getContext("2d"); ctx.fillStyle="rgba(255, 192, 203,1)"; ctx.fillRect(0,0,100,100); var imageData = ctx.getImageData(0,0,100,100); 获取ImageData对象 或是 var imageData = ctx.createImageData(100,100); 创建ImageData对象 for(var i=0;i<imageData.data.length;i++){ imageData.data[4*i+3]=100; 修改 } ctx.putImageData(imageData,0,0) 放入 } }
6.单像素操作
---->获取单个像素的信息:
window.onload = function() {
var canvas = document.querySelector("#test");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "pink";
ctx.beginPath();
ctx.fillRect(50, 50, 100, 100);
ctx.restore();
var imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
var color = getPxInfo(imgdata, 49, 49);
console.log(color);
}
function getPxInfo(imgdata, x, y) {
var color = [];
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) y*w+x x:多少列 y:多少行
//r
color[0] = data[(y * w + x) * 4];
//g
color[1] = data[(y * w + x) * 4 + 1];
//b
color[2] = data[(y * w + x) * 4 + 2];
//a
color[3] = data[(y * w + x) * 4 + 3];
return color;
}
}
---->设置单个像素的信息:
window.onload = function() {
var canvas = document.querySelector("#test");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "pink";
ctx.beginPath();
ctx.fillRect(50, 50, 100, 100);
ctx.restore();
var imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
setPxInfo(imgdata,30,i,[0,0,0,255]); //设置一个
for(var i=0;i<imgdata.width;i++){ //设置一行
setPxInfo(imgdata,30,i,[0,0,0,255]);
}
ctx.putImageData(imgdata, 0, 0);
}
function setPxInfo(imgdata, x, y, color) {
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) y*w+x x:多少列 y:多少行
//r
data[(y * w + x) * 4] = color[0];
//g
data[(y * w + x) * 4 + 1] = color[1];
//b
data[(y * w + x) * 4 + 2] = color[2];
//a
data[(y * w + x) * 4 + 3] = color[3];
}
};
7.合成
---->全局透明度 globalAlpha = value
这个属性影响到 canvas 里所有图形的透明度,
有效的值范围是 0.0 (完全透明)到 1.0(完全不透明) 默认是 1.0
ctx.globalAlpha = .5;
---->覆盖合成
source:新画的图像(称为 源)
destination:已经绘制过的图形(称为 目标)
已经绘制过的图形:目标 ctx.fillStyle="pink"; ctx.fillRect(50,50,100,100); 设置源与目标的位置: ctx.globalCompositeOperation="destination-atop"; 新画的图像:源 ctx.fillStyle="green"; ctx.fillRect(100,100,100,100);
globalCompositeOperation:
source-over(默认值):源在上面,新的图像层级比较高
source-in :只留下源与目标的重叠部分( 只留下 重叠的源的那一部分)
source-out :只留下源超过目标的部分( 除了 重叠的源的那一部分)
source-atop:砍掉源溢出的部分(相对于目标来说 ,溢出目标的源的部分砍掉)
destination-over:目标在上面,旧的图像层级比较高
destination-in:只留下源与目标的重叠部分(目标的那一部分)
destination-out:只留下目标超过源的部分
destination-atop:砍掉目标溢出的部分
8.其他
---->将画布导出为图像
toDataURL(注意是canvas元素接口上的方法)
if(canvas.getContext){ var ctx = canvas.getContext("2d"); ctx.fillRect(0,0,199,199); var result = canvas.toDataURL(); console.log(result); }
---->画布上的事件操作
ctx.isPointInPath(x, y)
判断在当前路径中是否包含检测点
x:检测点的X坐标 y:检测点的Y坐标
注意,此方法只作用于最新画出的canvas图像
if(canvas.getContext){ var ctx = canvas.getContext("2d"); ctx.beginPath(); //去掉这个 则会点击画布上的全部图形 ctx.arc(100,100,50,0,360*Math.PI/180); ctx.fill(); ctx.beginPath(); //去掉这个 则会点击画布上的全部图形 ctx.arc(200,200,50,0,360*Math.PI/180); ctx.fill(); canvas.onclick=function(ev){ ev = ev||event; var x = ev.clientX - canvas.offsetLeft; var y = ev.clientY - canvas.offsetTop; if(ctx.isPointInPath(x,y)){ alert(123); } } }