利用canvas影像合成实现刮刮卡效果

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里包含了两种实现思路:

  1. 通过globalCompositeOperation = ‘destination-out’
  2. 通过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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值