canvas
首先来学习看一下基础html结构
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>canvas</title>
<meta name="description" content="学习canvas">
<meta name="keywords" content="学习canvas">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=7">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body>
<canvas id="myCanvas" width="500" height="500"></canvas>
<script type="text/javascript">
window.onload = function() {
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d')
// 画一个矩形
context.save(); // 记录状态
context.fillStyle = 'red'; // 设置填充颜色
context.fillRect(10,10,100,100); // 画一个矩形
context.restore(); // 恢复状态
}
</script>
</body>
</html>
常用的方法或名词
-
save 记录画布当前状态
context.save(); -
restore 恢复画布状态
context.restore(); -
fillStyle 设置填充颜色
context.fillStyle = 'red'; // 支持 #ff0000,颜色单词,rgb -
fill 填充
context.save(); context.beginPath(); context.moveTo(100,50); context.lineTo(150,150); context.lineTo(50,150); context.closePath(); context.fill(); -
fillRect 绘制矩形(四个参数,分别是x, y, w, h)
context.fillRect(0,0,100,100) -
strokeStyle 设置轮廓颜色
context.strokeStyle = 'red'; context.strokeRect(0,0,100,100) -
stroke 绘制轮廓
context.save(); context.beginPath(); context.moveTo(0,0); context.lineTo(120,120); context.closePath(); context.stroke(); context.restore(); -
strokeRect 绘制矩形轮廓(四个参数,分别是x, y, w, h)
context.strokeRect(0,0,100,100) -
lineWidth 轮廓宽度
context.lineWidth = 6; -
beginPath/ closePath 开始与闭合路径
context.save(); context.beginPath(); // 开始一段新的路径的标志 context.moveTo(0,0); context.lineTo(120,120); context.closePath(); // 闭合路径,它会试图从当前路径的终点连一条路径到起点,让整个路径闭合起来。但是,这并不意味着它之后的路径就是新路径了 context.stroke(); context.restore(); -
moveTo 起点(两个参数, 分别是x,y)
-
lineTo 终点或途经点(两个参数, 分别是x,y)
-
arc 绘制圆形(六个参数, 分别是 x, y, radius(圆弧半径), startAngle开始角度,endAngle 结束角度,anticlockwise 是否逆时针绘制(布尔值))
context.beginPath(); // 开始路径 context.arc(230, 90, 50, 0, Math.PI * 2, false); // 绘制一个圆形 context.closePath(); context.fill(); // 填充 // 注意: 角度换算弧度 // let degress = 1; // 1 角度 // let radians = degress * (Math.PI / 180); // 0.0175弧度 // 1角度 等于 0.0175弧度 // fillRect 绘制填充 // strokeRect 绘制轮廓 // fill 填充 // stroke 轮廓 -
font字体大小,字体类型
context.font = '30px "宋体"' -
strokeText 字体轮廓 (三个参数,分别是:内容,x, y)
context.strokeText('内容主体', 100, 100) -
fillText 字体填充 (三个参数,分别是:内容,x, y)
context.fillText('内容', 50, 50); -
clearRect 清除指定画布(四个参数, 分别是:x,y,w,h)
context.clearRect(0,0,100,100) -
translate平移(平移的是原点,后面的x,y是相对于平移之后的点作为原点计算x,y)(两个参数,分别是:x,y)
context.save(); context.fillRect(100,100,100,100); context.translate(100, 100); context.strokeRect(110,110, 100,100); context.restore(); -
scale缩放(缩放倍数,两个参数,分别是:x, y的倍数)
context.save(); context.strokeRect(0,0,100,100); context.scale(0.5, 0.5); context.strokeRect(0,0,100,100); context.restore(); -
rotate旋转(旋转原点,一个参数,为:弧度 Math.PI)
context.save(); context.strokeRect(200,0,100,100); context.rotate(Math.PI/4); context.strokeRect(200,0,100,100); context.restore(); -
transform / setTransform 设置矩阵 (六个参数,分别是: a, b, c, d, e, f) 矩阵格式:
a (默认值1) c(默认值0) e(默认值0) b(默认值0) d(默认值1) f(默认值0) 0 0 1 等同于(下面表格)
x轴缩放 x轴倾斜 x轴平移 y轴倾斜 y轴缩放 y轴平移 0 0 1 context.setTransform(1,0,0,1,0,0); // 将矩阵重置为单位矩阵context.save(); let xScale = Math.cos(0.7854); let ySkew = -Math.sin(0.7854); let xSkew = Math.sin(0.7854); let yScale = Math.cos(0.7854); let xTrans = 200; let yTrans = 200; context.transform(xScale, ySkew, xSkew, yScale, xTrans, yTrans) context.fillRect(-50, -50, 100, 100) context.restore(); -
globalAlpha 全局阿尔法值(取值范围: 0.0 ~ 1.0, 默认为 1.0)
context.save(); context.fillStyle = 'red'; context.fillRect(0,0,100,100); context.globalAlpha = 0.5; context.fillStyle = 'green' context.fillRect(60, 0, 100, 100); context.restore(); -
globalCompositeOperation 全局合成参数
值 说明 source-over 默认值, 表示绘制的图形(源)将画在现有画布(目标)之上 destination-over 表示目标绘制在源之上, 与source-over相反 source-atop 将源绘制在目标之上,但是在重叠区域上两者都是不透明的,绘制在其他位置的目标是不透明的,但源是透明的 destination-atop 目标绘制在源之上,其中在重叠区域上两者都是不透明的,但绘制在其他位置是不透明的,而目标变成透明, 与source-atop相反 source-in 在源与目标重叠的区域只绘制源,而不重叠的部分都变成透明的(个人理解:取相交的部分,展示优先级是源) destination-in 与source-in相反,在源于目标重叠的区域保留目标,而不重复的部分变成透明(个人理解:取相交部分,展示优先级是目标) source-out 在与目标不重复的区域上绘制源,其他部分都变成透明的(个人理解:取源不相交的部分展示) destination-out 与source-out相反,在与目标不重复的区域上保留目标,其他部分都变成透明的(个人理解:取目标不相交的部分展示) lighter 这个值与顺序无关,如果源与目标重叠,就将这两者的颜色值相加,得到的颜色值的最大取值为255, 也就是白色 copy 这个值与顺序无关, 只绘制源,覆盖掉目标 xor(异或) 这个值与顺序无关,只绘制出不重复的源于目标区域,所有重叠的部分都变成透明的 context.save(); context.fillStyle = 'green'; context.fillRect(400,10,100,100); context.globalCompositeOperation = 'source-out'; context.fillStyle = 'yellow'; context.fillRect(450,10,100,100); context.restore(); -
shadowBlur阴影模糊(默认为0)
context.shadowBlur = 20; -
shadowColor 阴影颜色(支持 #ff0000,颜色单词, rgb, rgba)
context.shadowColor = 'red'; -
shadowOffsetX 阴影x轴偏移 / shadowOffsetY 阴影y轴偏移
context.save(); context.fillRect(10,10,100,100); context.shadowBlur = 0; context.shadowColor = 'rgba(0,0,0,0.2)'; context.shadowOffsetX = 10; context.shadowOffsetY = 10; context.fillRect(10, 200, 100, 100); context.restore(); -
createLinearGradient 线性渐变(四个参数,分别是:渐变起点x,y、渐变终点x,y)
let gradient = context.createLinearGradient(0,0,0,500); // addColorStop 第一个参数 颜色的偏移值(0表示渐变起点, 1表示终点), 第二个参数 偏移的颜色值 gradient.addColorStop(0, 'rgb(0,0,0)'); gradient.addColorStop(1, 'rgb(255,255,255)'); context.fillStyle = gradient; context.globalCompositeOperation = 'destination-over'; context.fillRect(0,0,600,500); -
createRadialGradient 放射渐变(6个参数 前3个参数描述一个圆(开始圆), 后3个参数描述另一个圆(结束圆))
// 例: 光晕的效果(开始圆和结束圆放在同一个位置) let radial = context.createRadialGradient(300,300,0, 300,300, 300); // addColorStop 第一个参数 颜色的偏移值(0表示渐变起点, 1表示终点), 第二个参数 偏移的颜色值 radial.addColorStop(0, 'rgb(0,0,0)'); radial.addColorStop(1, 'rgb(150,150,150)'); context.fillStyle = radial; context.globalCompositeOperation = 'destination-over'; context.fillRect(0,0, 600, 500); -
quadraticCurveTo创建二次贝塞尔曲线(四个参数: 控制点的x,y坐标值, 以及目标点的 x,y 值)
context.save(); context.lineWidth = 6; context.beginPath(); context.moveTo(50,250); context.quadraticCurveTo(250, 100, 450,250); context.stroke(); context.restore(); -
bezierCurveTo创建三次贝塞尔曲线(六个参数: 第一个控制点x,y坐标,第二控制点的x,y坐标, 目标点 x,y坐标)
context.save(); context.lineWidth = 6; context.beginPath(); context.moveTo(50,250); context.bezierCurveTo(150,50,350,450,450,250); context.stroke(); context.restore(); -
toDataURL 导出图像(特殊的,用dom操作)
const data = document.getElementById('myCanvas').toDataURL(); // data 为base64的字符,需要自行转换 let img = document.createElement('img') img.src = data; img.style.width = '120px'; img.style.height = '130px'; document.body.appendChild(img); -
drawImage 加载图像(至少三个参数,最多九个参数) 三个参数: 图片实例(img), x(坐标), y(坐标) ---- 不做任何处理 五个参数: 图片实例(img), x(坐标), y(坐标), width(图像展示宽度), height(图像展示高度) ---- 图像调整大小 九个参数:图片实例(img),x(图片剪切原点),y(图片剪切原点), width(图片剪切宽度), height(图片剪切高度) ,x(图片实际绘制原点),y(图片实际绘制原点), width(图片实际绘制宽度), height(图片实际绘制高度) --- 图像剪切大小
let img = new Image(); img.src = './img/1.png'; img.onload = function() { // 加载图片 // context.drawImage(img, 0, 0); // 不做任何处理 // 加载调整图片尺寸 let bi = img.width / img.height; context.drawImage(img, 0,0, 500, 500/bi); // 裁剪图像 // context.drawImage(img, 0,0, 500, 500, 0, 0, 500, 500) } // 解释: 500 为画布的大小,可以动态获取,例子这里固定了 -
getImageData 访问像素 (四个参数,分别是:x,y w, h)(访问像素区域的x,y坐标点, 以及像素区域宽高范围)
// 主要留意: getImageData方法返回三个参数:data, width, height; data属性,为一个数组, 每四个组成一个rgba颜色 // 经典例子 --- 取色器 let img = new Image(); img.src = './img/1.png'; img.onload = function() { context.drawImage(img, 0, 0, 500, 500/(img.width/img.height)) } canvas.addEventListener('click', function(e) { let canvasX = Math.floor(e.pageX - canvas.offsetLeft); let canvasY = Math.floor(e.pageY - canvas.offsetTop); let imgData = context.getImageData(canvasX, canvasY, 1, 1); let pixel = imgData.data; let pixelColor = `rgba(${pixel[0]},${pixel[1]},${pixel[2]},${pixel[3]})`; document.body.style.background = pixelColor }) -
createImageData 创建图像 (两个参数, 分别是: w, h) (图像的宽高)
// createImageData 方法返回三个参数, data, width, height,主要关注data参数 let imgData = context.createImageData(200, 200); let pixels = imgData.data; console.log(pixels, 'pixels'); let numPixels = imgData.width*imgData.height; // 绘制红色 for(let i = 0; i < numPixels; i++) { pixels[i*4] = 255; pixels[i*4 + 1] = 0; pixels[i*4 + 2] = 0; pixels[i*4 + 3] = 255; } // 这里讲上面更改了data的数组应用到画布上,不然不生效 context.putImageData(imgData, 0, 0); // 随机绘制像素 for(let i = 0; i < numPixels; i++) { pixels[i*4] = Math.floor(Math.random()*255); // 红 pixels[i*4 + 1] = Math.floor(Math.random()*255); // 绿 pixels[i*4 + 2] = Math.floor(Math.random()*255); // 蓝 pixels[i*4 + 3] = Math.floor(Math.random()*255); // 透明度 } context.putImageData(imgData, 250, 0); -
putImageData 绘制更改的图像(三个参数: imgData, x , y)
let imgData = context.createImageData(200, 200); let pixels = imgData.data; let numPixels = imgData.width*imgData.height; // 绘制红色 for(let i = 0; i < numPixels; i++) { pixels[i*4] = 255; pixels[i*4 + 1] = 0; pixels[i*4 + 2] = 0; pixels[i*4 + 3] = 255; } // 这里讲上面更改了data的数组应用到画布上 context.putImageData(imgData, 0, 0);