原生JS实现刮奖效果(PC和移动端通用)
最近在看《HTML5...案例》,看到一个刮奖,便参照其写了一下, 并做了一些改变
图片使用的是书中的的图片素材
一、需求
实现刮奖的效果,在PC和移动端都能刮奖(PC使用鼠标操作刮奖)。
书中的代码主要是为了讲解移动端的touch
操作,所以我在想是否能够在PC端使用鼠标进行刮奖,实现同样的效果。
二、关键点
1、使用一个 canvas 实现刮奖的效果
2、使用一张刮奖结果图(如上面的恭喜您获奖的图片)做 canvas 的背景
<div class="container">
<h1>刮奖</h1>
<div id="canvas">
<canvas id="mask" width="240" height="65"></canvas>
</div>
<h3 id="result"></h3>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
background: #dfdfdf;
text-align: center;
}
.container h1 {
padding-top: 50px;
}
.container #result {
padding-top: 50px;
color:red;
}
#canvas {
width: 240px;
height: 65px;
background: url('result.png');
background-size: 100% 100%;
margin: 0 auto;
margin-top: 50px;
}
3、将 canvas 画满一个遮罩层
var canvas = document.getElementById('mask');
var context = canvas.getContext("2d");
context.fillStyle = "#d1d1d1";
context.fillRect(0, 0, 240, 65);
4、启用 globalCompositeOperation
说实话,我之前都没见过和使用过这个属性。
它可以进行遮盖,遮盖的方式有12中,具体地址:
context.globalCompositeOperation = 'destination-out';
使用 destination-out
能够把之前画过的这部分内容变成透明:
5、画圆时透明遮罩层
启用了globalCompositeOperation= = 'destination-out'
之后,在 canvs 上绘制的新的图形,就会使得之前的 mask 变成透明的,从而显示出背景图片来。
为了比较好看的效果,会使用画圆的方式来进行。
而画圆需要有一个圆心,至于半径可以定死就可以,比如下面的画圆方式:
需要拿到触发事件的点的横纵坐标(pageX和pageY),然后根据 canvas 的
offsetLeft
和 canvas 的offsetTop
计算需要画的圆的点.
需要减去 canvas 的 offsetLeft 和 offsetTop 是因为画圆的(X,Y
是 canvas 的坐标,pageX
和pageY
是页面上鼠标的坐标
// 根据某个点在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();
}
这样每画一个圆,画布上就出现一个圆形的透明区域,显示背景图片。
6、 判断是否完成刮奖
刮奖过程中需要进行判断是否已经完成刮奖,从而实现某些业务逻辑。
下面的方法也是刘欢书中的代码。不过我使用了 80%
的达成条件。
基本的思想是:
上面提到了,启用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
的数值
< 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();
}
}
三、事件监听
基本的布局做好了,然后就是进行事件的监听.
移动端比较简单,书中主要是移动端使用了 touchmove
,为了扩展到PC端网站,使用mousemove
PC上需要关注的问题是:
mousedown
的时候使用 addEventListener 给canvas增加一个mousemove
事件mouseup
的时候使用removeEventListener
移除mousemove
因此我将 handle 抽出来做了一个function,这样子能够方便的使用removeEventListener
// 鼠标按下 增加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);
}
四、效果
文章版权:Postbird-There I am , in the world more exciting!
本文链接:http://www.ptbird.cn/js-scratch.html
转载请注明文章原始出处 !