Canvas对象
HTML的canvas元素;
它定义了一个在客户端使用脚本绘图的API,可以直接为这个对象定义width和height。
也可以用toDataURL()方法从画布中导出图片。
不过实际绘图API是由getContent()方法返回的一个独立“上下文”对象 —> CanvasRenderingContext2D
CanvasRenderingContext2D
通过Canvas的getContext方法获得
lat canvas =document.getElementById('canvas');
let ctx = canvas.getContext('2d');
以下合成都是基于该对象操作的
合成
通常在画布上绘制图像时,新画的图像会在之前绘制内容上的上面,并根据透明度,部分或者全部遮住旧的。
通过设置属性globalCompositeOperation的值来控制合成效果
学习合成前先了解几个概念
源:正要在画布上画的像素 S
目标:画布上现有像素 D
结果:源像素与目标像素混合之后的像素 R
常用的3个属性:
- ‘source-over’:
默认值,源像素绘制在目标像素上面,如果源像素是半透明的,目标像素也会受到影响
计算公式R= S + (1 - 源像素的透明度)* D
- ‘copy’:
关闭合成,源像素原封不动的绘制到画布上(目标像素会被清空)
合成公式 R= S
- ‘destination-over’:
源像素绘制到目标像素下面,如果目标像素是半透明的,源像素颜色会受到影响
计算公式 R=(1 - 目标像素的透明度)* S + D
其他属性
- lighter
混合后的颜色是目标像素和源像素的简单相加,如果和大于最大值则舍去超出部分 - destination-atop
在目标像素下面绘制源像素,如果源像素是透明的,结果也是透明的(即不在源像素区域内的目标像素会变透明) - source-atop
在目标像素上面绘制源像素,透明度是源像素与目标像素的透明的乘积,如果目标像素是透明的则什么都不画(即只能在目标像素区域内绘制源像素) - destination-out
如果源像素不透明则目标像素转为透明的,如果源像素透明则目标像素不变,忽略颜色(把目标像素与源像素相交的部分抹掉,只留下目标里不相交的部分,即擦除效果)
计算公式 R= (1 - 源像素透明度) * D
可用于实现刮刮乐效果
- source-out
跟上面的刚好相反,如果目标像素是透明的,结果是源像素,忽略目标像素的颜色(只绘制源像素里与目标像素不相交的内容)
计算公式 R = (1 - 目标像素透明度) * S
-
destination-in
将目标像素的值与源像素的透明度相乘,忽略源像素颜色(留下相交部分) -
source-in
将源像素的值与目标元素的透明度相乘,目标像素的颜色忽略。如果目标像素是透明的,结果也是透明的
刮刮乐效果的实现
本demo是针对于PC端,移动端需要把监听事件改成对应的touchstart, touchmove, touchend。
以下demo里包含了两种实现思路:
- 通过globalCompositeOperation = ‘destination-out’
- 通过ctx.clearRect(x, y, width, height)
<style>
.gua {
position: relative;
width: 200px;
height: 150px;
}
.result {
position: absolute;
width: 100%;
line-height: 150px;
text-align: center;
font-size: 20px;
}
#canvas {
position: absolute;
z-index: 1;
}
</style>
<div class="gua">
<div class="result">
谢谢惠顾!
</div>
<canvas id="canvas" height="150" width="200"></canvas>
</div>
let canvas = document.getElementById('canvas')
let ctx = canvas.getContext('2d');
let { width, height, offsetLeft, offsetTop } = canvas;
ctx.fillStyle = 'gray';
let parentNode = canvas.offsetParent;
while (parentNode !== document.body) {
offsetTop += parentNode.offsetTop;
parentNode = parentNode.offsetParent;
}
ctx.fillRect(0,0,width, height);
ctx.save();
// 关键点
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.lineWidth= 30;
function handleGua (e) {
let { clientX, clientY } = e;
let x = clientX - offsetLeft, y = clientY - offsetTop;
ctx.lineTo(x, y);
ctx.stroke();
// 不用合成的话,可以通过清除来达到刮刮乐的效果
// ctx.clearRect(clientX, clientY, 20,20);
}
canvas.addEventListener('mousedown', function (e) {
canvas.addEventListener('mousemove', handleGua);
}, false)
document.body.addEventListener('mouseup', function (e) {
canvas.removeEventListener('mousemove', handleGua);
}, false)