js实现刮奖操作

支付宝经常支付完成,会出现一个刮奖的操作,这个需求在开发中也算比较常用的一个功能了。

1、原理:canvas与canvas的叠加

刮奖成功就是一张背景图,在背景图上方覆盖的灰色的canvas作为第一个图层,当我们用鼠标或者手指去触摸canvas图层时,再绘制第二个canvas图层。核心是

globalCompositeOperation =‘destination-out’

这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识26种遮盖方式的字符串。26种遮盖方法如下:

2、逻辑实现

1、先在图片上画满一个遮罩层,就是简单canvas绘制矩形并且填充颜色,然后此canvas启用globalCompositeOperation = ‘destination-out’

	var canvas = document.getElementById('mask');
	var context = canvas.getContext("2d");
	context.fillStyle = "#d1d1d1";
	context.fillRect(0, 0, 240, 65);
	context.globalCompositeOperation = 'destination-out';

2、画透明图层,当手指碰触到canvas时,则以手指与屏幕接触的坐标(x,y)画一个固定半径的小圆圈。这里还要减去canvas距离顶部(canvas.offsetTop)和左边的边距(canvas.offsetLeft),这个才是圆心的位置,然后半径取固定值20

// 根据某个点在canvas上画圆
			// x 坐标和 y 坐标 两个坐标是触摸点的坐标而不是画圆的圆心
			// 圆心通过计算得出
			function drawArcByPoint(x, y) {
				context.beginPath();
				context.arc(x - canvas.offsetLeft, y - canvas.offsetTop, 20, 0, Math.PI * 2);
				context.closePath();
				context.fillStyle = '#dddddd';
				context.fill();
				checkComplete();
			}

3、判断是否中奖。启用globalCompositeOperation= = 'destination-out'之后,画的圆使得这个圆是透明的,根据这个条件可以进行判断有多少像素是透明的,就代表多少像素已经被刮了,当像素比例达到80%的时候,就认为刮奖结束。

canvas 可以通过getImageData转 base64 的图片,同时通过图片的data能够拿到像素的字节数据。

比较重要的点是:

拿到的像素字节数据是每四个长度表示一个像素,分别表示rgba。也就是说,下面代码中pxData[0]表示第一个像素的r,pxData[1]表示第一个像素的g,pxData[2]表示第一个像素的b,pxData[3]表示第一个像素的a,

因此下面代码中的循环是使用了 i += 4作为每次的step,同时获取的是 pxData[i+3],拿到的是alpha的数值

拿到 alpha 之后就能够通过 < 10 来判断是否是透明的

最后计算有多少透明的,如果这个比例高于 80% 则说明刮奖结束

function checkComplete() {
				var imgData = context.getImageData(0, 0, 240, 65);
				var pxData = imgData.data; // 获取字节数据
				var len = pxData.length; // 获取字节长度
				var count = 0; // 记录透明点的个数
				// 主要的思想是 一个像素由四个数据组成,每个数据分别是 rgba() 所以第四个数据 a 表示alpha透明度
				for(var i = 0; i < len; i += 4) {
					var alpha = pxData[i + 3]; // 获取每个像素的透明度
					if(alpha < 10) {
						// 透明度小于10 
						count++;
					}
				}
				var percent = count / (len / 4); // 计算百分比
				// 如果百分比大于0.8 则表示成功
				if(percent >= 0.8) {
					showResult();
				}
			}

4、监听事件

// 鼠标按下 增加mousemove的事件监听
			canvas.addEventListener('mousedown', drawArcMouseHandle);
			canvas.addEventListener('mouseup', function(event) {
				// 鼠标抬起之后,把mousemove的事件监听撤销掉
				this.removeEventListener('mousemove', mousemoveHandle);
			});
			// 根据鼠标的move画圆
			function drawArcMouseHandle(event) {
				event.preventDefault();
				event.target.addEventListener("mousemove", mousemoveHandle);
			}
			// 为了能够移除movesemove的事件需要单独处理一下
			function mousemoveHandle(event) {
				event.preventDefault();
				drawArcByPoint(event.pageX, event.pageY);
			}
			// 监听 touchmove
			canvas.addEventListener('touchmove', drawArcTouchHandle);
			// 根据触摸点画圆 
			function drawArcTouchHandle(event) {
				event.preventDefault();
				var touch = event.touches[0];
				drawArcByPoint(touch.pageX, touch.pageY);
			}

2019-10-10更新

可以将封面更换为我们自己设计师给的图片,具有更大的发挥空间,既将图片png转为canvas作为遮罩层

function imageToCanvas() {
				var img = new Image();
				img.src = 'mask.png'

				img.onload = function() {
					img.onload = null;
					context.globalCompositeOperation = 'source-over';
					context.drawImage(img, 0, 0);
				}
			}

最后完成结果:

 

 

完整代码:https://github.com/huolala6/BlogCode/tree/master/001-js%E5%88%AE%E5%A5%96

 

欢迎转载,转载需带着文章出处链接~~

 

 

 

 

 

标签:

发表评论

邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据