简单的Canvas刮刮乐带动画效果的实例

今天做了个刮刮乐领奖品的小活动,感觉挺有用的,整理在这儿记录下

上个效果图先:

简单的Canvas刮奖带动画效果的实例

简单的Canvas刮奖带动画效果的实例

简单的Canvas刮奖带动画效果的实例

简单的Canvas刮奖带动画效果的实例

加了个简单的 css 动画效果

下面贴上主要代码:

index.html

<!DOCTYPE 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">8</span> 次刮奖机会<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; 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 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

猜你喜欢

转载自blog.csdn.net/zsjangel/article/details/78894149