百度云盘:传送门 密码:6p5q
纯CSS模拟刮奖效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <style> *{ margin: 0; padding: 0; } p { position: fixed; top: 60%; left: 0; right: 0; text-align: center; transform: translateY(-50%); font-size: 40px; font-weight: 900; color: white; text-shadow: 0 0 50px black; text-transform: capitalize; font-family: 'Roboto','Helvetica','Arial',sans-serif; letter-spacing: 5px; } .box{ margin: 80px; position: relative; width: 300px; height: 180px; left: 460px; } #canvas{ position: absolute; top: 0; left: 0; z-index: 5; } .bk{ width: 300px; height: 180px; background: #fff; position: absolute; top: 0; left: 0; text-align: center; line-height: 180px; } #freshBtn{ margin-left: 660px; user-select: none; background: #ddd; width: 80px; height: 40px; text-align: center; line-height: 40px; } </style> <body> <p>Gary</p> <div class="box"> <div class="bk"> 一等奖 </div> <canvas id="canvas"></canvas> </div> <div id="freshBtn">重置</div> </body> <script src="./js/canvas.js"></script> <script> var canvas = new canvasInit({ id: 'canvas', text: '刮开抽奖', cover: '#1f1f1f', coverType: 'color', 300, height: 180, drawPercentCallback: (num) => { if(num > 30) { alert('恭喜获得一等奖') canvas.fresh() // 重置 } } }) </script> </html>
class canvasClass { constructor (id,text,cover,coverType,width,height,drawPercentCallback) { this.conId = id; /*canvasID */ this.conNode = document.getElementById(this.conId); this.ctx = this.conNode.getContext('2d'); this.coverText = text; this.cover = cover; /**图层颜色或图片 */ this.coverType = coverType; /**图层类型(image/color) */ this.width = width; this.height = height; this.drawPercentCallback = drawPercentCallback this.clientRect = null; this.isMouseDown = false; } /** * 绘制canvas */ fillCanvas () { this.conNode.setAttribute('width', this.width); this.conNode.setAttribute('height', this.height); if (this.coverType == 'color') { this.ctx.save(); this.ctx.fillStyle = this.cover; this.ctx.fillRect(0, 0, this.width, this.height); this.ctx.restore(); this.ctx.save(); var fontSize = 30; this.ctx.font = '30px Arial'; this.ctx.textAlign = 'center'; this.ctx.fillStyle = '#fff'; this.ctx.fillText(this.coverText, this.width/2, this.height/2+fontSize/2); this.ctx.restore(); this.ctx.globalCompositeOperation = 'destination-out'; } else if (this.coverType == 'image') { var image = new Image(this.width, this.height) image.onload = () => { this.ctx.drawImage(image, 0, 0, this.width, this.height); } image.src = this.cover; } this.clientRect = this.conNode ? this.conNode.getBoundingClientRect() : null } /** * 事件监听 */ bindEvent () { /**移动端检测 */ var device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); var clickEvt = device ? 'touchstart' : 'mousedown'; var moveEvt = device ? 'touchmove' : 'mousemove'; var x1,y1,x2,y2; if (!device) { document.addEventListener('mouseup', (e) => { this.isMouseDown = false; }) } else { document.addEventListener("touchmove", (e) => { if (this.isMouseDown) { e.preventDefault(); } }) document.addEventListener("touchend", (e) => { this.isMouseDown = false; }) } /**添加监听 */ this.conNode.addEventListener(clickEvt, (e) => { this.isMouseDown = true; x1 = device ? e.touches[0].offsetX : e.offsetX; y1 = device ? e.touches[0].offsetY : e.offsetY; this.drawPoint(x1, y1) }) this.conNode.addEventListener(moveEvt, (e) => { if (!device && !this.isMouseDown) { return false; } this.isMouseDown = true; x2 = device ? e.touches[0].offsetX : e.offsetX; y2 = device ? e.touches[0].offsetY : e.offsetY; this.drawPoint(x1, y1, x2, y2) // console.log(x1,x2,y1,y2) x1 = x2 y1 = y2 // [x1, y1] = [x2, y2] }) } /** * 抹去, 返回百分比 */ drawPoint (x1, y1, x2, y2) { var bar = 20; // 半径 this.ctx.beginPath(); if (x2) { /** * 优化绘制路径 */ var asin = bar*Math.sin(Math.atan((y2-y1)/(x2-x1))); var acos = bar*Math.cos(Math.atan((y2-y1)/(x2-x1))) var x3 = x1+asin; var y3 = y1-acos; var x4 = x1-asin; var y4 = y1+acos; var x5 = x2+asin; var y5 = y2-acos; var x6 = x2-asin; var y6 = y2+acos; this.ctx.save(); this.ctx.beginPath(); this.ctx.moveTo(x3,y3); this.ctx.lineTo(x5,y5); this.ctx.lineTo(x6,y6); this.ctx.lineTo(x4,y4); this.ctx.closePath(); this.ctx.clip(); this.ctx.clearRect(0,0,this.width,this.height); this.ctx.restore(); this.ctx.arc(x2, y2, bar, 0, Math.PI*2, true); } else { this.ctx.arc(x1, y1, bar, 0, Math.PI*2, true); } this.ctx.fill(); if (this.drawPercentCallback) { this.drawPercentCallback(this.getTransparentPercent()); } } getTransparentPercent () { var imgData = this.ctx.getImageData(0, 0, this.width, this.height), pixles = imgData.data, transPixs = []; for (var i = 0, j = pixles.length; i < j; i += 4) { var a = pixles[i + 3]; if (a < 128) { transPixs.push(i); } } return (transPixs.length / (pixles.length / 4) * 100).toFixed(2); } } function canvasInit(json) { var arr = [] for (let item in json) { arr.push(json[item]) } this.init = new canvasClass(...arr) this.init.fillCanvas() this.init.bindEvent() var btn = document.querySelector('#freshBtn'); btn.addEventListener('click', (e) => { this.init.fillCanvas() }); } canvasInit.prototype.fresh = function () { console.log(this.init) this.init.fillCanvas() this.init.isMouseDown = false }
(直接复制就可以使用了O(∩_∩)O~ ES6编写)
=>是es6语法中的arrow function(箭头函数)
举例:
(x) => x + 6
相当于
function(x){
return x + 6;
}
实现过程
CSS
画板.class
class canvasClass { constructor (id,text,cover,coverType,width,height,drawPercentCallback) { this.conId = id; /*canvasID */ this.conNode = document.getElementById(this.conId); this.ctx = this.conNode.getContext('2d'); this.coverText = text; this.cover = cover; /**图层颜色或图片 */ this.coverType = coverType; /**图层类型(image/color) */ this.width = width; this.height = height; this.drawPercentCallback = drawPercentCallback this.clientRect = null; this.isMouseDown = false; } /** * 绘制canvas */ fillCanvas () { this.conNode.setAttribute('width', this.width); this.conNode.setAttribute('height', this.height); if (this.coverType == 'color') { this.ctx.save(); this.ctx.fillStyle = this.cover; this.ctx.fillRect(0, 0, this.width, this.height); this.ctx.restore(); this.ctx.save(); var fontSize = 30; this.ctx.font = '30px Arial'; this.ctx.textAlign = 'center'; this.ctx.fillStyle = '#fff'; this.ctx.fillText(this.coverText, this.width/2, this.height/2+fontSize/2); this.ctx.restore(); this.ctx.globalCompositeOperation = 'destination-out'; } else if (this.coverType == 'image') { var image = new Image(this.width, this.height) image.onload = () => { this.ctx.drawImage(image, 0, 0, this.width, this.height); } image.src = this.cover; } this.clientRect = this.conNode ? this.conNode.getBoundingClientRect() : null } /** * 事件监听 */ bindEvent () { /**移动端检测 */ var device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); var clickEvt = device ? 'touchstart' : 'mousedown'; var moveEvt = device ? 'touchmove' : 'mousemove'; var x1,y1,x2,y2; if (!device) { document.addEventListener('mouseup', (e) => { this.isMouseDown = false; }) } else { document.addEventListener("touchmove", (e) => { if (this.isMouseDown) { e.preventDefault(); } }) document.addEventListener("touchend", (e) => { this.isMouseDown = false; }) } /**添加监听 */ this.conNode.addEventListener(clickEvt, (e) => { this.isMouseDown = true; x1 = device ? e.touches[0].offsetX : e.offsetX; y1 = device ? e.touches[0].offsetY : e.offsetY; this.drawPoint(x1, y1) }) this.conNode.addEventListener(moveEvt, (e) => { if (!device && !this.isMouseDown) { return false; } this.isMouseDown = true; x2 = device ? e.touches[0].offsetX : e.offsetX; y2 = device ? e.touches[0].offsetY : e.offsetY; this.drawPoint(x1, y1, x2, y2) // console.log(x1,x2,y1,y2) x1 = x2 y1 = y2 // [x1, y1] = [x2, y2] }) } /** * 抹去, 返回百分比 */ drawPoint (x1, y1, x2, y2) { var bar = 20; // 半径 this.ctx.beginPath(); if (x2) { /** * 优化绘制路径 */ var asin = bar*Math.sin(Math.atan((y2-y1)/(x2-x1))); var acos = bar*Math.cos(Math.atan((y2-y1)/(x2-x1))) var x3 = x1+asin; var y3 = y1-acos; var x4 = x1-asin; var y4 = y1+acos; var x5 = x2+asin; var y5 = y2-acos; var x6 = x2-asin; var y6 = y2+acos; this.ctx.save(); this.ctx.beginPath(); this.ctx.moveTo(x3,y3); this.ctx.lineTo(x5,y5); this.ctx.lineTo(x6,y6); this.ctx.lineTo(x4,y4); this.ctx.closePath(); this.ctx.clip(); this.ctx.clearRect(0,0,this.width,this.height); this.ctx.restore(); this.ctx.arc(x2, y2, bar, 0, Math.PI*2, true); } else { this.ctx.arc(x1, y1, bar, 0, Math.PI*2, true); } this.ctx.fill(); if (this.drawPercentCallback) { this.drawPercentCallback(this.getTransparentPercent()); } } getTransparentPercent () { var imgData = this.ctx.getImageData(0, 0, this.width, this.height), pixles = imgData.data, transPixs = []; for (var i = 0, j = pixles.length; i < j; i += 4) { var a = pixles[i + 3]; if (a < 128) { transPixs.push(i); } } return (transPixs.length / (pixles.length / 4) * 100).toFixed(2); } }
1、绘制canvas画布
2、添加事件监听
3、刮奖效果
构造函数省略...
1、绘制canvas画布
fillCanvas () {
this.conNode.setAttribute('width', this.width);
this.conNode.setAttribute('height', this.height);
if (this.coverType == 'color') {
this.ctx.save();
this.ctx.fillStyle = this.cover;
this.ctx.fillRect(0, 0, this.width, this.height);
this.ctx.restore();
this.ctx.save();
var fontSize = 30;
this.ctx.font = '30px Arial';
this.ctx.textAlign = 'center';
this.ctx.fillStyle = '#fff';
this.ctx.fillText(this.coverText, this.width/2, this.height/2+fontSize/2);
this.ctx.restore();
this.ctx.globalCompositeOperation = 'destination-out';
} else if (this.coverType == 'image') {
var image = new Image(this.width, this.height)
image.onload = () => {
this.ctx.drawImage(image, 0, 0, this.width, this.height);
}
image.src = this.cover;
}
this.clientRect = this.conNode ? this.conNode.getBoundingClientRect() : null
}
2、添加事件监听
bindEvent () {
/**移动端检测 */
var device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
var clickEvt = device ? 'touchstart' : 'mousedown';
var moveEvt = device ? 'touchmove' : 'mousemove';
var x1,y1,x2,y2;
if (!device) {
document.addEventListener('mouseup', (e) => {
this.isMouseDown = false;
})
} else {
document.addEventListener("touchmove", (e) => {
if (this.isMouseDown) {
e.preventDefault();
}
})
document.addEventListener("touchend", (e) => {
this.isMouseDown = false;
})
}
/**添加监听 */
this.conNode.addEventListener(clickEvt, (e) => {
this.isMouseDown = true;
x1 = device ? e.touches[0].offsetX : e.offsetX;
y1 = device ? e.touches[0].offsetY : e.offsetY;
this.drawPoint(x1, y1)
})
this.conNode.addEventListener(moveEvt, (e) => {
if (!device && !this.isMouseDown) {
return false;
}
this.isMouseDown = true;
x2 = device ? e.touches[0].offsetX : e.offsetX;
y2 = device ? e.touches[0].offsetY : e.offsetY;
this.drawPoint(x1, y1, x2, y2)
// console.log(x1,x2,y1,y2)
x1 = x2
y1 = y2
// [x1, y1] = [x2, y2]
})
}
3、刮奖效果
drawPoint (x1, y1, x2, y2) {
var bar = 20; // 半径
this.ctx.beginPath();
if (x2) {
/**
* 优化绘制路径
*/
var asin = bar*Math.sin(Math.atan((y2-y1)/(x2-x1)));
var acos = bar*Math.cos(Math.atan((y2-y1)/(x2-x1)))
var x3 = x1+asin;
var y3 = y1-acos;
var x4 = x1-asin;
var y4 = y1+acos;
var x5 = x2+asin;
var y5 = y2-acos;
var x6 = x2-asin;
var y6 = y2+acos;
this.ctx.save();
this.ctx.beginPath();
this.ctx.moveTo(x3,y3);
this.ctx.lineTo(x5,y5);
this.ctx.lineTo(x6,y6);
this.ctx.lineTo(x4,y4);
this.ctx.closePath();
this.ctx.clip();
this.ctx.clearRect(0,0,this.width,this.height);
this.ctx.restore();
this.ctx.arc(x2, y2, bar, 0, Math.PI*2, true);
} else {
this.ctx.arc(x1, y1, bar, 0, Math.PI*2, true);
}
this.ctx.fill();
if (this.drawPercentCallback) {
this.drawPercentCallback(this.getTransparentPercent());
}
}
初始化canvas.class画布
function canvasInit(json) {
var arr = []
for (let item in json) {
arr.push(json[item])
}
this.init = new canvasClass(...arr)
this.init.fillCanvas()
this.init.bindEvent()
var btn = document.querySelector('#freshBtn');
btn.addEventListener('click', (e) => {
this.init.fillCanvas()
});
}
按钮
#freshBtn{
margin-left: 660px;
user-select: none;
background: #ddd;
80px;
height: 40px;
text-align: center;
line-height: 40px;
}
刮奖区域
.box{
margin: 80px;
position: relative;
300px;
height: 180px;
left: 460px;
}
DOM
设置文档内容和显示文本
<div class="box"> <div class="bk"> 一等奖 </div> <canvas id="canvas"></canvas> </div> <div id="freshBtn">重置</div>
模拟抽奖效果时bk中文字可以用随机
给canvas.class画布传参
<script> var canvas = new canvasInit({ id: 'canvas', text: '刮开抽奖', cover: '#1f1f1f', coverType: 'color', 300, height: 180, drawPercentCallback: (num) => { if(num > 30) { alert('恭喜获得一等奖') canvas.fresh() // 重置 } } }) </script>