TIP
使用canvas实现刮刮乐
html
<h1>刮一刮,得大奖</h1>
<div>已擦除:<span id="percent">0</span>%</div>
<div class="box">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
css
.box {
position: relative;
width: 300px;
height: 100px;
}
canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
js
const canvas1 = document.querySelector('#canvas1')
const canvas2 = document.querySelector('#canvas2')
const ctx1 = canvas1.getContext('2d')
const ctx2 = canvas2.getContext('2d')
canvas1.width = 300
canvas1.height = 100
canvas2.width = 300
canvas2.height = 100
ctx1.font = "50px sans-serif"
ctx1.fillText("谢谢惠顾!", 50, 70)
ctx2.fillStyle = 'rgb(192, 192, 192)'
ctx2.fillRect(0, 0, 300, 100)
ctx2.globalCompositeOperation = 'destination-out';
/**
* 擦除方法
* ctx canvas 2d
* x x坐标
* y y坐标
* d 直径
**/
function clearCircle(ctx, x, y, d) {
ctx.beginPath()
ctx.arc(x, y, d / 2, 0, 2 * Math.PI)
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
ctx.fill()
}
const moveObj = {
preX: 0,
preY: 0,
l: 2, // 移动超过绝对差值2就需要添加额外的点
d: 18, // 线条粗细
}
// 已擦除多少
function getPercentRase() {
const data = ctx2.getImageData(0, 0, 300, 100),
pixes = data.data,
len = pixes.length
let opacityPixes = 0
for(let i=0; i<len; i+=4) {
var a = pixes[i+3]
if (a===0) {
opacityPixes++
}
}
return (opacityPixes / (len / 4) * 100).toFixed(2)
}
const setPercent = (function() {
let timer = null
return function() {
if (timer) return
timer = setTimeout(() => {
const percent = getPercentRase()
document.querySelector('#percent').innerHTML = percent
timer = null
}, 300)
}
})()
const moveFn = function(e) {
const arr = []
// 添加一些点,否则速度快了会出现间断
const absX = Math.abs(e.offsetX - moveObj.preX),
absY = Math.abs(e.offsetY - moveObj.preY)
if (absX >= moveObj.l && absX > absY) {
const a = Math.floor(absX / moveObj.l)
const b = e.offsetY > moveObj.preY ? absY / a : - absY / a
const c = e.offsetX > moveObj.preX ? moveObj.l : - moveObj.l
for(let i=0; i<a; i++) {
arr.push([moveObj.preX+c*i, moveObj.preY+b*i])
}
} else if (absY >= moveObj.l && absY > absX) {
const a = Math.floor(absY / moveObj.l)
const b = e.offsetX > moveObj.preX ? absX / a : - absX / a
const c = e.offsetY > moveObj.preY ? moveObj.l : - moveObj.l
for(let i=0; i<a; i++) {
arr.push([moveObj.preX+b*i, moveObj.preY+c*i])
}
}
arr.push([e.offsetX, e.offsetY])
moveObj.preX = e.offsetX
moveObj.preY = e.offsetY
for(let [x, y] of arr) {
clearCircle(ctx2, x, y, moveObj.d)
}
setPercent()
}
function initPrev(e) {
moveObj.preX = e.offsetX
moveObj.preY = e.offsetY
}
// 内部按下鼠标时触发
canvas2.addEventListener('mousedown', initPrev)
// 按下鼠标时触发
document.addEventListener('mousedown', function() {
// 在外部按下鼠标后移入canvas2后触发
canvas2.addEventListener('mouseenter', initPrev)
canvas2.addEventListener('mousemove', moveFn)
})
document.addEventListener('mouseup', function() {
canvas2.removeEventListener('mousemove', moveFn)
canvas2.removeEventListener('mouseenter', initPrev)
})