今天做了个刮刮乐领奖品的小活动,感觉挺有用的,整理在这儿记录下
上个效果图先:
加了个简单的 css 动画效果
下面贴上主要代码:
index.html
<html lang="zh-CN">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0, user-scalable=0, minimum-scale=1, maximum-scale=1">
<meta charset="UTF-8">
<title>H5 Canvas 刮刮乐title>
<link rel="stylesheet" type="text/css" href="css/layout.css">
head>
<body>
<div class="main">
<div class="ggl-wrapper">
<div class="ggl-bg-top-bolang">div>
<div id="scratch-ct" class="scratch-ct">
<div id="scratch-inner" class="inner-ct">
<div id="content-ct" class="content-ct" style="visibility: hidden;">
<img id="gift-cover" class="gift-cover" src="img/gift-cover.jpg" alt="">
div>
<canvas id="scratch-canvas" class="scratch-canvas">canvas>
<div id="cav-cover" class="cav-cover"><div id="start-gg-bt" class="start-gg-bt">开始刮奖div><div class="notice-gg-times">今日还有 <span style="color:red">8span> 次刮奖机会<br>http://blog.csdn.net/zhouzme/div>div>
div>
div>
<div class="ggl-bg-bottom-bolang">div>
div>
<div id="gift-show-ct" class="gift-show-ct">
<span id="close-bt" class="close-bt">×span>
<div class="show-inner small">
<div class="panel-head">div>
<div class="panel-body">
<img class="gift-cover" src="img/gift-cover.jpg" alt="">
<div class="operator-ct"><a id="go-to-bt" class="go-to-bt" href="http://blog.csdn.net/zhouzme/" target="_blank">立即领取a>div>
div>
div>
div>
div>
<script src="./js/scratch.js">script>
<script src="./js/main.js">script>
body>
html>
scratch.js
/**
* 配置参数
* 该Canvas刮刮卡插件的可用配置参数有:
canvasId:canvas的id。
imageBackground:背景图片(刮开后呈现的图片)。
pictureOver:前景图片。
sceneWidth:canvas的宽度。
sceneHeight:canvas的高度。
radius:清除区域的半径。
nPoints:清除区域的杂点数量。
percent:在清除多少区域之后清空canvas。
cursor:光标。
png:png格式的光标。
x:Move position x。
y:Move position y。
cur:cur格式的光标(IE使用)。
*/
var Scratch = (function () {
/**
* Merge properties between two objects
* @param obj1
* @param obj2
* @returns {{}}
*/
function mergeOptions(obj1, obj2){
var obj3 = {};
for (var key in obj1) { obj3[key] = obj1[key]; }
for (var key in obj2) { obj3[key] = obj2[key]; }
return obj3;
}
/**
* Generate a random number
* @param min
* @param max
* @returns {Number}
*/
function randomPoint(min, max) {
var random = Math.abs(Math.random()*(max - min) + min);
return random = parseInt(random.toFixed(0), 10);
}
var isCallbackCalled = false;
/**
* Scratch constructor
* @param options
* @constructor
*/
var Scratch = function(options) {
this.cursor = {
png: '', // Modern browsers
cur: '', // for IE
x: 0,
y: 0,
default: 'auto'
};
this.pointSize = {
x: 5,
y: 5
};
this.defaults = {
canvasId: '', // Canvas id
imageBackground: '', // Path [src]
pictureOver: '', // Path [src]
cursor: this.cursor, // Custom pointer
sceneWidth: 250, // Canvas width
sceneHeight: 250, // Canvas height
radius: 40, // Radius of scratch zone
nPoints: 10, // n points for clear canvas
pointSize: this.pointSize,
percent: null,
onCovered: null,
callback: null
};
this.options = mergeOptions(this.defaults, options);
this.options.cursor = mergeOptions(this.cursor, options.cursor);
this.options.pointSize = mergeOptions(this.pointSize, options.pointSize);
// init Scratch
this.init();
};
Scratch.prototype.init = function () {
var _this = this; // Save the "this" :)
this.canvas = document.getElementById(this.options.canvasId);
this.ctx = this.canvas.getContext('2d');
this.canvas.width = this.options.sceneWidth;
this.canvas.height = this.options.sceneHeight;
this.image = new Image();
this.image.src = this.options.pictureOver;
this.percent = 0;
this.zone = null;
this.pixelRatio = window.devicePixelRatio;
// Set background after draw the canvas
this.setBackground();
this.setCursor();
var scratchMove = function(e) {
e.preventDefault();
_this.scratch(e);
var clear = _this.clear();
if (clear && !isCallbackCalled) {
_this.canvas.style.pointerEvents = 'none';
_this.callback(_this.options.callback);
}
};
window.addEventListener('resize', function() {
_this.update();
// Resize the canvas
_this.redraw();
});
window.addEventListener('scroll', function() {
_this.update();
});
// Mouse & Touch events
this.canvas.addEventListener('mousedown', function(e) {
_this.canvas.addEventListener('mousemove', scratchMove);
document.body.addEventListener('mouseup', function _func() {
_this.canvas.removeEventListener('mousemove', scratchMove);
this.removeEventListener('mouseup', _func);
});
});
this.canvas.addEventListener('touchstart', function(e) {
_this.canvas.addEventListener('touchmove', scratchMove);
document.body.addEventListener('touchend', function _func() {
_this.canvas.removeEventListener('touchmove', scratchMove);
this.removeEventListener('touchend', _func);
});
});
};
Scratch.prototype.setCursor = function() {
var string = '';
if (document.documentElement.classList.contains('is-ie') || navigator.userAgent.indexOf('Trident') != -1 || navigator.userAgent.indexOf('Edge') != -1) {
string += 'url(' + this.options.cursor.cur + '), auto';
} else {
string += 'url(' + this.options.cursor.png + ') ' + this.options.cursor.x + ' ' + this.options.cursor.y + ', pointer';
}
this.canvas.setAttribute('style', 'cursor:' + string + ';');
};
// Update positions etc
Scratch.prototype.update = function() {
this.zone = this.canvas.getBoundingClientRect();
};
Scratch.prototype.redraw = function () {
if (this.options.pictureOver) {
var oldWidth = this.options.sceneWidth;
var newWidth = this.zone.width;
if(newWidth < oldWidth) {
this.ctx.clearRect(0, 0, this.zone.width, this.zone.height);
this.canvas.width = this.zone.width;
this.canvas.height = this.zone.height;
this.ctx.drawImage(this.image, 0, 0, this.zone.width, this.zone.height);
}
} else {
var fontEm = parseInt(window.getComputedStyle(document.documentElement, null)["font-size"]); //这是为了不同分辨率上配合@media自动调节刮的宽度
//画出来是透明的
this.ctx.beginPath();
this.ctx.arc(x, y, fontEm * 1.6, 0, Math.PI * 2, true);
drawFillOver(this);
}
};
function drawFillOver(_this) {
_this.ctx.globalCompositeOperation = "source-over";
_this.ctx.fillStyle = '#aaaaaa';
_this.ctx.fillRect(0, 0, _this.options.sceneWidth, _this.options.sceneHeight);
_this.ctx.fill();
_this.ctx.font = "Bold 20px Arial";
_this.ctx.textAlign = "center";
_this.ctx.fillStyle = "#ebebeb";
_this.ctx.fillText("惊喜在后头,快刮我", _this.options.sceneWidth / 2, _this.options.sceneHeight / 2);
//把这个属性设为这个就可以做出圆形橡皮擦的效果
//有些老的手机自带浏览器不支持destination-out,下面的代码中有修复的方法
_this.ctx.globalCompositeOperation = 'destination-out';
_this.ctx.fill();
_this.canvas.style.display = 'none';
_this.canvas.offsetHeight;
_this.canvas.style.display = 'inherit';
}
Scratch.prototype.setBackground = function() {
var _this = this;
if (_this.options.pictureOver) {
this.image.onload = function () {
_this.zone = _this.canvas.getBoundingClientRect();
// Draw image
_this.ctx.drawImage(this, 0, 0);
// When the canvas have been drawn
if (_this.options.imageBackground) {
var IMG = document.createElement('img');
IMG.classList.add('scratch_picture-under');
IMG.src = _this.options.imageBackground;
_this.canvas.parentElement.insertBefore(IMG, _this.canvas);
}
if (typeof _this.options.onCovered == "function") {
_this.options.onCovered.call();
}
};
} else {
_this.zone = _this.canvas.getBoundingClientRect();
drawFillOver(_this);
if (typeof _this.options.onCovered == "function") {
_this.options.onCovered.call();
}
}
};
Scratch.prototype.clearPoint = function (x1, y1) {
var radius = this.options.radius;
var x = Math.random() * 2 * radius - radius;
var ylim = Math.sqrt(radius * radius - x * x);
var y = Math.random() * 2 * ylim - ylim;
x += radius;
y += radius;
x = parseInt(x, 10);
y = parseInt(y, 10);
return {
x: x + x1,
y: y + y1
}
};
Scratch.prototype.getPosition = function(e) {
var posX, posY;
switch (e.type) {
case 'touchmove':
posX = e.touches[0].clientX - this.options.radius - window.pageXOffset;
posY = e.touches[0].clientY - this.options.radius - window.pageYOffset;
break;
case 'mousemove':
posX = e.clientX - this.options.radius - window.pageXOffset;
posY = e.clientY - this.options.radius - window.pageYOffset;
break;
}
return {
x: posX,
y: posY
}
};
Scratch.prototype.scratch = function(e) {
var position = this.getPosition(e);
var x = position.x - this.zone.left;
var y = position.y - this.zone.top + window.pageYOffset;
var i = 0;
var len = this.options.nPoints;
for(i; ivar points = this.clearPoint(x, y);
this.ctx.clearRect(points.x, points.y, this.options.pointSize.x, this.options.pointSize.y);
}
this.percent = this.getPercent();
};
Scratch.prototype.getPercent = function() {
var percent;
var counter = 0; // number of pixels clear
var imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
var imageDataLength = imageData.data.length;
for(var i = 0; i < imageDataLength; i += 4) {
if (imageData.data[i] === 0 && imageData.data[i+1] === 0 && imageData.data[i+2] === 0 && imageData.data[i+3] === 0) {
counter++;
}
}
if (counter >= 1) {
percent = (counter / (this.canvas.width * this.canvas.height)) * 100;
} else {
percent = 0;
}
return percent;
};
Scratch.prototype.clear = function() {
if (this.percent >= this.options.percent) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
return true;
}
};
Scratch.prototype.callback = function(callback) {
if (callback != null && this.percent >= this.options.percent) {
isCallbackCalled = true;
callback();
}
};
return Scratch;
})();
main.js
;(function(){
var contentCt = document.getElementById('content-ct');
var scratchInner = document.getElementById('scratch-inner');
var cavCover = document.getElementById('cav-cover');
var startGgBt = document.getElementById('start-gg-bt');
var giftShowCt = document.getElementById('gift-show-ct');
var giftShowCtInner = giftShowCt.getElementsByClassName('show-inner')[0];
var giftCover = document.getElementById('gift-cover');
var closeBt = document.getElementById('close-bt');
var newImg = document.createElement('img');
newImg.addEventListener('load', function(){
var scratch = new Scratch({
canvasId: 'scratch-canvas',
// imageBackground: './img/gift-cover.jpg',
// pictureOver: './img/gray-gg.jpg',
cursor: {
// png: 'piece.png',
// cur: 'piece.cur',
x: '20',
y: '17'
},
sceneWidth: contentCt.clientWidth,
sceneHeight: contentCt.clientHeight,
radius: 20,
nPoints: 300,
percent: 50,
onCovered: function() {
var cmFrame = window.frames[0];
var fd = null;
if (cmFrame) {
fd = cmFrame.document;
}
scratchInner.style.height = contentCt.clientHeight +'px';
cavCover.style.width = contentCt.clientWidth +'px';
cavCover.style.height = contentCt.clientHeight +'px';
startGgBt.addEventListener('click', function(){
cavCover.style.display = 'none';
contentCt.style.visibility = 'visible';
if (fd) {
var cmLogo = fd.getElementsByClassName('CMMOB_gglogo');
if (cmLogo) {
fd.getElementsByClassName('CMMOB_gglogo')[0].style.display='none';
}
}
});
closeBt.addEventListener('click', function(){
giftShowCtInner.setAttribute('class', giftShowCtInner.getAttribute('class').replace(' normal', ''));
setTimeout(function(){
giftShowCt.style.display = 'none';
}, 300);
});
},
callback: function () {
giftShowCt.style.display = 'block';
setTimeout(function(){
giftShowCt.setAttribute('class', giftShowCt.getAttribute('class').replace(/^ +| +/, '') +' with-shadow');
giftShowCtInner.setAttribute('class', giftShowCtInner.getAttribute('class').replace(/small/, 'small normal'));
}, 200);
},
pointSize: { x: 3, y: 3}
});
});
newImg.src = giftCover.src;
})();
layout.css
@charset "UTF-8";
@keyframes btwc {
0% {
transform: scale(1);
}
50% {
transform: scale(.95);
}
100% {
transform: scale(1);
}
}
html,body { padding: 0; margin: 0; background-color: #E2E2E2; }
.ggl-wrapper { padding: 20px; background: url(../img/touming.png) repeat-x top left; }
.scratch-ct { padding: 10px; background-color: #FFF; }
.scratch-ct .inner-ct { position: relative; }
.scratch-ct .content-ct { min-height: 100px; }
.scratch-ct .scratch-canvas { position: absolute; z-index: 2; left: 0; top: 0; }
.scratch-ct .cav-cover { position: absolute; z-index: 999; left: 0; right: 0; top: 0; min-height: 100px; background: url(../img/bg_1.png) repeat left top; background-size: cover; }
.scratch-ct .start-gg-bt { position: absolute; width: 150px; height:40px; line-height: 40px; left: 50%; top: 50%; margin-left: -75px; margin-top: -30px; color: #FFF; font-size: 20px; text-align: center; background: url(../img/button_start.png) no-repeat center center; background-size: contain; }
.scratch-ct .notice-gg-times { position: absolute; left: 0; right: 0; top: 50%; margin-top: 10px; color: #8f6f06; font-size: 14px; text-align: center; }
.ggl-bg-top-bolang { height: 20px; background: url(../img/gbg.png) no-repeat center top; background-size: cover; }
.ggl-bg-bottom-bolang { height: 20px; background: url(../img/gbg.png) no-repeat center bottom; background-size: cover; }
.gift-show-ct { display: none; position: absolute; z-index: 9999; left: 0; right: 0; top: 0; bottom: 0; background: rgba(0,0,0,0); transition: all .3s ease-in; }
.gift-show-ct.with-shadow { background-color: rgba(0,0,0,1); }
.gift-show-ct .show-inner { position: relative; margin: 15% auto 0 auto; padding-top: 70px; width: 350px; max-width: 85%; box-sizing: border-box;background: url(../img/sunshine.png) no-repeat center -70px; background-size: 300px auto; }
.gift-show-ct .panel-head { position: absolute; top: 30px; left: 0; right: 0; height: 60px; background: url(../img/winhead.png) no-repeat center top; background-size: contain; }
.gift-show-ct .panel-body { padding: 30px 15px 15px 15px; /*height: 200px;*/ background-color: #FFF; border: solid 4px #ffe6df; border-radius: 5px; }
.gift-show-ct .show-inner.small { transform: scale(.1); transition: all .3s ease-in; -webkit-transition: all .3s ease-in; }
.gift-show-ct .show-inner.normal { transform: scale(1); }
.gift-show-ct .close-bt { position: absolute; right: 20px; top: 20px; font-size: 34px; color: #FFF; }
.gift-cover { width: 100%; }
.operator-ct {
height: 40px; padding-top: 15px;
}
.gift-show-ct .show-inner.normal .go-to-bt {
-webkit-animation: btwc infinite 1s ease-in-out;
-o-animation: btwc infinite 1s ease-in-out;
animation: btwc infinite 1s ease-in-out;
display: block; height: 40px; line-height: 35px; margin: auto; font-size: 18px; text-decoration: none; color: #FFF; text-align: center; background: url(../img/go-to-bt.png) no-repeat center center; background-size: auto 100%;
}
需要的同学改改活动图片和按钮链接应该就可以用啦~
其它源码和图片素材下载地址:
http://download.csdn.net/download/zsjangel/10172579