以下是 Canvas移动手机刮刮卡特效代码 的示例演示效果:
部分效果截图:
HTML代码(index.html):
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas移动手机刮刮卡特效</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="max-width">
<p>在这个例子中,当你刮开90%的面积时,回调函数就会被执行。</p>
<div class="scratch_container">
<div class="scratch_viewport">
<canvas id="js-scratch-canvas"></canvas>
</div>
</div>
</div>
<script src="js/Scratch.js"></script>
<script type="text/javascript">
var scratch = new Scratch({
canvasId: 'js-scratch-canvas',
imageBackground: './images/win.jpg',
pictureOver: './images/foreground.jpg',
cursor: {
png: './images/piece.png',
cur: './images/piece.cur',
x: '20',
y: '17'
},
radius: 20,
nPoints: 100,
percent: 90,
callback: function () {
alert('I am Callback.');
},
pointSize: { x: 3, y: 3}
});
</script>
<!-- No javascript -->
<noscript>
<p class="browserupgrade">
Votre navigateur ne supporte pas ou à desactivé javascript.
<br>
L'application ne peut pas fonctionner correctement.
<br>
Pour accéder au site veuillez activer javascript.
</p>
</noscript>
<!-- No javascript end -->
</body>
</html>
JS代码(Scratch.js):
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);
}
/** * Scratch constructor * @param options * @constructor */
var Scratch = function(options){
this.cursor ={
png:'',// Modern browserscur:'',// for IEx: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 canvaspointSize:this.pointSize,percent: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 Scratchthis.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 canvasthis.setBackground();
this.setCursor();
var scratchMove = function(e){
e.preventDefault();
_this.scratch(e);
var clear = _this.clear();
if (clear){
_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 eventsthis.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 etcScratch.prototype.update = function(){
this.zone = this.canvas.getBoundingClientRect();
}
;
Scratch.prototype.redraw = function (){
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);
}
}
;
Scratch.prototype.setBackground = function(){
var _this = this;
this.image.onload = function(){
_this.zone = _this.canvas.getBoundingClientRect();
// Draw image_this.ctx.drawImage(this,0,0);
// When the canvas have been drawnvar IMG = document.createElement('img');
IMG.classList.add('scratch_picture-under');
IMG.src = _this.options.imageBackground;
_this.canvas.parentElement.insertBefore(IMG,_this.canvas);
}
;
}
;
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;
i<len;
i++){
var 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 clearvar 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){
callback();
}
}
;
return Scratch;
}
)();
CSS代码(style.css):
body{height:20px;padding:0;margin:0;font-family:"Microsoft YaHei","Segoe UI","Lucida Grande",Helvetica,Arial,sans-serif;}
.text-intro{position:relative;margin:0 auto 50px auto;text-align:center;max-width:600px;}
.max-width{position:relative;margin:0 auto;max-width:600px;}
.code{background-color:#e5e5e5;border-radius:10px;}
/* Scratch */
.scratch_container{position:relative;margin:0 auto;max-width:1024px;}
.scratch_viewport{position:relative;max-width:250px;max-height:250px;margin:0 auto;z-index:0;}
.scratch_picture-under{position:absolute;top:0;left:0;width:100%;display:block;z-index:-1;}
.scratch_container canvas{position:relative;width:100%;height:auto;z-index:1;}