canvas刮刮卡

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title> - jsFiddle demo by artwl</title>
</head>
<body>
    <!-- 
        Author  : Yaodongxin
        Date     : 2016-08-31
        Tips      : 如果蒙层是图片需要放到服务前环境测试
     -->
    <button id="freshBtn">刷新</button><label>已刮开 <span id="drawPercent">0%</span> 区域。</label>
    <div style="position:relative" id = "card"></div>
    <script type='text/javascript'>
        var Card = function(options){
            this.id = options.id;
            this.width = options.width;//如果底层图层是图片,这个值会更新成图片尺寸
            this.height = options.height;//如果底层图层是图片,这个值会更新成图片尺寸
            this.wrap = null;//包裹canvas的对象
            this.mask = null;//蒙层canvas对象
            this.bacCtx = null; //context 对象
            this.maskCtx = null; //context 对象
            this.backType = options.backType || 'text'; // 'image' || 'text'
            this.backImg = options.backImg; //刮开后的图层
            this.texts = options.texts;//文字串码
            this.fontSize = options.fontSize || 36;//文字串码字体大小
            this.maskType = options.maskType || 'color';// 'color' || 'image'
            this.maskImg = options.maskImg;
            this.maskColor = options.maskColor || '#ccc';
            this.callback = options.callback || false; //是否执行刮开百分比函数 boollean类型
            this.percentDom = options.percentDom || document.getElementById('drawPercent');
        }
        Card.prototype = {
            init : function(){
                this.percentDom.innerHTML = '0%';
                this.draw();
            },
            draw : function(){
                this.wrap = document.getElementById(this.id);
                this.drawMask();
            },
            // 画底层内容
            drawCard : function(){
                var _this = this;
                _this.resizeCanvas(_this.card, _this.width, _this.height);
                _this.bacCtx = _this.card.getContext('2d');
                if(_this.backType == 'image'){
                    if(!_this.backImg){
                        console.error('A back image url is need.');
                    }else{
                        var image = new Image();
                        image.src = _this.backImg;
                        image.onload = function(){
                            _this.width = this.width;
                            _this.height = this.height;
                            _this.resizeCanvas(_this.card, this.width, this.height);
                            _this.bacCtx.drawImage(this, 0, 0); //绘背景图
                        }
                        image.error = function(){
                            console.error('image load failed. Check your url or network.');
                        }
                    }
                }else{
                    _this.texts = _this.texts || getRandomStr(6);
                    _this.bacCtx.font = 'Bold ' + _this.fontSize + 'px "microsoft yahei"';
                    _this.bacCtx.fillStyle = '#ff6600';
                    _this.bacCtx.textAlign = 'center';
                    _this.bacCtx.textBaseline = 'middle';
                    _this.bacCtx.fillText(_this.texts, _this.width/2, _this.height/2);
                }
            },

            // 绘制蒙层
            drawMask : function(){
                var _this = this;
                // _this.wrap.innerHTML = ''
                if(_this.wrap.innerHTML == ''){
                    _this.mask = document.createElement('canvas');
                    _this.wrap.appendChild(_this.mask);
                    _this.mask.setAttribute('style','position:absolute;left:0;top:0;');
                    _this.card = document.createElement('canvas');
                    _this.wrap.appendChild(_this.card);
                    this.bindEvents();
                }
                _this.resizeCanvas(_this.mask, _this.width, _this.height);
                _this.maskCtx = _this.mask.getContext('2d');
                if(_this.maskType == 'image'){
                    if(!_this.maskImg){
                        console.error('A mask image url is need.');
                    }else{
                        var image = new Image();
                        image.src = _this.maskImg;
                        image.onload = function(){
                            _this.maskCtx.drawImage(this, 0, 0); //绘蒙层
                            _this.drawCard();//绘制随机码
                        }
                        image.error = function(){
                            console.error('image load failed. Check your url or network.');
                        }
                    }
                }else{
                    _this.maskCtx.fillStyle = this.maskColor;
                    _this.maskCtx.fillRect(0, 0, _this.width, _this.height);
                    _this.drawCard();//绘制随机码
                }
                _this.clientRect = _this.wrap ? _this.wrap.getBoundingClientRect() : null;
            },

            // 绘制擦除圆
            drawPoint : function(x, y){
                this.maskCtx.globalCompositeOperation = 'destination-out';
                this.maskCtx.beginPath();
                // var radgrad = this.maskCtx.createRadialGradient(x, y, 0, x, y, 30);
                // radgrad.addColorStop(0, 'rgba(0, 0, 0, 1)');
                // radgrad.addColorStop(1, 'rgba(0, 0, 0, 1)');
                radgrad = '#fff';
                this.maskCtx.fillStyle = radgrad;
                this.maskCtx.arc(x, y, 30, 0, Math.PI * 2, true);
                this.maskCtx.fill();
            },

            //绑定事件
            bindEvents : function(){
                var _this = this,
                    device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())),
                    clickEvtName = device ? 'touchstart' : 'mousedown',
                    moveEvtName = device? 'touchmove': 'mousemove',
                    isMouseDown = false,
                    start ={x:0, y:0},
                    end = {x:0, y:0};
                if (!device) {//pc
                    isMouseDown = false;
                    document.addEventListener('mouseup', function(e) {
                        isMouseDown = false;
                        start ={x:0, y:0};
                        end = {x:0, y:0};
                    }, false);
                    document.addEventListener('mouseout', function(e) {
                        isMouseDown = false;
                        start ={x:0, y:0};
                        end = {x:0, y:0};
                    }, false);
                }else{//mobile
                    document.addEventListener('touchmove', function(e) {
                        if (isMouseDown) {
                            e.preventDefault();
                        }
                    }, false);
                    document.addEventListener('touchend', function(e) {
                        isMouseDown = false;
                        start ={x:0, y:0};
                        end = {x:0, y:0};
                    }, false);
                }
                // 绑定擦除事件
                var docEle = document.documentElement || document.body;
                _this.mask.addEventListener(clickEvtName, function(e){
                    // console.log(device)
                    start ={x:0, y:0};
                    end = {x:0, y:0};
                    isMouseDown = true;
                    var x = (device ? e.touches[0].clientX : e.clientX) - _this.clientRect.left + docEle.scrollLeft - docEle.clientLeft;
                    var y = (device ? e.touches[0].clientY : e.clientY) - _this.clientRect.top + docEle.scrollTop - docEle.clientTop;
                    _this.drawPoint(x, y);
                }, false);
                _this.mask.addEventListener(moveEvtName, function(e){
                    if (!isMouseDown) {
                        return false;
                    }
                    isMouseDown = true;
                    var x = (device ? e.touches[0].clientX : e.clientX) - _this.clientRect.left + docEle.scrollLeft - docEle.clientLeft;
                    var y = (device ? e.touches[0].clientY : e.clientY) - _this.clientRect.top + docEle.scrollTop - docEle.clientTop;
                    if(start.x!=0){
                        end.x = start.x;
                        end.y = start.y;
                    }
                    start.x = x;
                    start.y = y;
                    _this.drawPoint(x, y);
                    if(end.x!=0){
                        _this.addDraw(start, end);
                    }
                    if(_this.callback){
                        var percent = _this.drawPercent(_this.maskCtx);
                        _this.percentDom.innerHTML = percent + '%';
                    }
                }, false);
            },

            /**
             * 这个函数是用来补充move的时候中间的空白
             * @param {object} start 形式{x:10,y:10}的对象,画线开始坐标
             * @param {object} end   形式{x:20,y:20}的对象,画线结束坐标
             */
            addDraw : function(start, end){
                var _this = this;
                _this.maskCtx.lineWidth = 60;
                _this.maskCtx.lineStyle = '#f00';
                _this.maskCtx.beginPath();
                _this.maskCtx.moveTo(start.x, start.y);
                _this.maskCtx.lineTo(end.x, end.y);
                _this.maskCtx.stroke();
            },
            
            /**
             * 重置canvas的宽高
             * @param  {object} canvas canvas对象
             * @param {number} w canvas宽
             * @param {number} h canvas高
             */
            resizeCanvas : function(canvas, w, h){
                canvas.width = w;
                canvas.height = h;
            },

            /**
             *  计算刮开的百分比
             * @param  {object} ctx context2d对象
             * @return {number}     刮开图层所占百分比
             */
            drawPercent : function(ctx){
                var imgData = ctx.getImageData(0, 0, this.width, this.height),
                    pixles = imgData.data,
                    transPixs = [],
                    len = pixles.length;
                for(var i = 0; i<len; i+=4){
                    if(pixles[i+3] == 0){
                        transPixs.push(pixles[i+3]);
                    }
                }
                return (transPixs.length/(len/4)*100).toFixed(2);
            }
        }

        /**
         * 生成随机串码
         * @param  {number} len 生成随机串码的长度
         * @return {string}     生成的串码
         */
        function getRandomStr(len) {
            var text = '';
            var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            for( var i=0; i < len; i++ )
                text += possible.charAt(Math.floor(Math.random() * possible.length));
            return text;
        }

        window.onload = function(){
            var card = new Card({
                id : 'card',
                backType : 'text',
                width : '325',
                height : '174'
            });
            card.init();

            // 刷新
            document.getElementById('freshBtn').addEventListener('click', function(){
                card.init();
            }, false);
        }
    </script>
</body>
</html>

demo:预览地址

posted @ 2017-05-16 15:27  幽竹小妖  阅读(276)  评论(0编辑  收藏  举报