刮刮卡——canvas实践

1、利用css将<li><canvas>层重叠;

  • html
<body>
    <div id="wrap">
        <!-- 灰色涂层 -->
        <canvas></canvas>
        <!-- 刮卡结果 -->
        <ul>
            <li></li>
        </ul>
    </div>      
</body>
  • css
<style type="text/css">
            *{
                margin: 0;
                padding: 0;
            }
            html,body{
                height: 100%;
                overflow: hidden;
            }
            #wrap,ul,ul>li{
                height: 100%;
            }
            ul>li{
                background: url(img/b.png);
                background-size: 100% 100%;
            }
            canvas{
                /* 利用绝对定位让灰色涂层与刮卡结果重叠 */
                position: absolute;
                left: 0;
                top: 0;
                transition: 1s;
            }
        </style>
  1. 在canvas画布上绘制刮刮卡图层图像;
var canvas = document.querySelector("canvas");
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
if(canvas.getContext){
  var ctx = canvas.getContext("2d")
  var img = new Image()
  img.src = "img/a.png"
  img.onload = function(){
    draw()
}
function draw(){
  var flag = 0  //用于后面统计刮开百分比
  ctx.drawImage(img,0,0,canvas.width,canvas.height)
}

3、在canvas画布区域监听鼠标事件或触摸事件;

// 监听鼠标和touch事件
canvas.addEventListener('mousedown', moveStart, false);
canvas.addEventListener('touchstart', moveStart, false);
canvas.addEventListener('mousemove', move, false);
canvas.addEventListener('touchmove', move, false);
canvas.addEventListener('mouseup', moveEnd, false);
canvas.addEventListener('touchend', moveEnd, false);

4、在手指移动过程中,实时计算手指在画布中的位置以及移动路径,利用canvas的globalCompositeOperation方法中的destination-out效果将刮过的地方设置为透明从而实现刮卡的效果;

canvas.addEventListener("touchstart",function(ev){
    ev = ev||event;
    var touchC = ev.changedTouches[0];
                        
    var x = touchC.clientX - canvas.offsetLeft;
    var y = touchC.clientY - canvas.offsetTop;
    //画线,解决快速画圆bug                  
    ctx.lineWidth = 40
    ctx.lineCap = "round"
    ctx.lineJoin = "round"
    ctx.globalCompositeOperation="destination-out";

    ctx.save();
    ctx.beginPath();
    ctx.moveTo(x,y)
    ctx.lineTo(x+1,y+1)
    ctx.stroke()
    ctx.restore()
})
canvas.addEventListener("touchmove",function(ev){
    ev = ev||event;
    var touchC = ev.changedTouches[0];
                        
    var x = touchC.clientX - canvas.offsetLeft;
    var y = touchC.clientY - canvas.offsetTop;
                        
    ctx.save();
    ctx.lineTo(x,y)
    ctx.stroke()
    ctx.restore()
})

5、设置当canvas涂层被刮到一定百分比时去除整个涂层;

  • 利用canvas的getImageData可以获取指定范围区域的每个像素点的rgba的信息,其中a指的是透明度,当a为0时,该像素点完全透明,当a为255时,表示该像素点完全不透明;
  • 通过遍历指定区域的像素点信息,得到透明像素点的个数
    • 透明像素点的个数/总像素点的个数=刮开区域所占百分比
    • 通过设置阈值,使得当所刮区域占比满足一定值时,刮开整个canvas涂层;
canvas.addEventListener("touchend",function(){
    var imgData = ctx.getImageData(0,0,canvas.width,canvas.height)
    var allPx = imgData.width*imgData.height
    for(var i = 0;i<allPx;i++){
        if(imgData.data[i*4+3]===0){
            flag++
        }
     }
    if(flag>=allPx/2){
        canvas.style.opacity = 0
     }
})                  

6、全部刮开以后,删canvas层

canvas.addEventListener("transitionend",function(){
    this.remove()  //自杀,删除canvas
})

完整代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
        <title></title>
        <style type="text/css">
            *{
                margin: 0;
                padding: 0;
            }
            html,body{
                height: 100%;
                overflow: hidden;
            }
            #wrap,ul,ul>li{
                height: 100%;
            }
            ul>li{
                background: url(img/b.png);
                background-size: 100% 100%;
            }
            canvas{
                position: absolute;
                left: 0;
                top: 0;
                transition: 1s;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <canvas></canvas>
            <ul>
                <li></li>
            </ul>
        </div>      
    </body>
    <script type="text/javascript">
        window.onload=function(){
            var canvas = document.querySelector("canvas");
            canvas.width = document.documentElement.clientWidth;
            canvas.height = document.documentElement.clientHeight;
            if(canvas.getContext){
                var ctx = canvas.getContext("2d")
                var img = new Image()
                img.src = "img/a.png"
                img.onload = function(){
                    draw()
                }
                function draw(){
                    var flag = 0
                    ctx.drawImage(img,0,0,canvas.width,canvas.height)
                    
                    canvas.addEventListener("touchstart",function(ev){
                        ev = ev||event;
                        var touchC = ev.changedTouches[0];
                        
                        var x = touchC.clientX - canvas.offsetLeft;
                        var y = touchC.clientY - canvas.offsetTop;
                        
                        ctx.lineWidth = 40
                        ctx.lineCap = "round"
                        ctx.lineJoin = "round"
                        ctx.globalCompositeOperation="destination-out";
                        ctx.save();
                        
                        ctx.beginPath();
                        ctx.moveTo(x,y)
                        ctx.lineTo(x+1,y+1)
                        ctx.stroke()
                        ctx.restore()
                    })
                    
                    canvas.addEventListener("touchmove",function(ev){
                        ev = ev||event;
                        var touchC = ev.changedTouches[0];
                        
                        var x = touchC.clientX - canvas.offsetLeft;
                        var y = touchC.clientY - canvas.offsetTop;
                        
                        ctx.save();
                        ctx.lineTo(x,y)
                        ctx.stroke()
                        ctx.restore()
                    })
                    
                    canvas.addEventListener("touchend",function(){
                        var imgData = ctx.getImageData(0,0,canvas.width,canvas.height)
                        var allPx = imgData.width*imgData.height
                        for(var i = 0;i<allPx;i++){
                            if(imgData.data[i*4+3]===0){
                                flag++
                            }
                        }
                        if(flag>=allPx/2){
                            canvas.style.opacity = 0
                        }
                    })
                    
                    canvas.addEventListener("transitionend",function(){
                        this.remove()  //自杀,删除canvas
                    })
                }
            }
        }
    </script>
</html>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容