移動端-刮刮樂的實現方式


原創:轉載請備明鏈接

  程序員有一種慣性思維,就是看見一些會動的東西(帶點科技含量的,貓啊,狗啊就算了),總要先想一遍,這玩意用代碼是怎么控制的。比如電梯,路邊的霓虹燈,遙控器,小孩子的玩具等,都統統被程序員“意淫”過。

  有時候還會感覺程序員看世界會看的透徹一點.............

  

  想必大家都玩過刮刮樂,下面就介紹一種刮刮樂的移動端實現方式!用到canvas

1、用HTML 5 canvas globalCompositeOperation 屬性實現刮刮樂

思路:

  (1)首先需要一個盒子定位,確定刮刮樂區域想要放在哪里

  (2)定位盒子里有個放內容的盒子,也就是放獎品的

  (3)用一個畫布(canvas)把上面的盒子蓋住

  (4)當手觸摸移動的時候,可以擦除部分畫布,露出獎品區

  (5)當擦除足夠多(3/4)的時候,可以選擇讓畫布自動消失,慢慢淡出(這個效果選做)

 

主要是第四步,如何擦除?

這里選用 globalCompositeOperation,即Canvas中的合成操作。簡單來說,Composite(組合),就是對你在繪圖中,后繪制的圖形與先繪制的圖形之間的組合顯示效果,比如在國畫中,你先畫一筆紅色,再來一筆綠色,相交的部分是一種混色,而在油畫中,綠色就會覆蓋掉相交部分的紅色,這在程序繪圖中的處理就是Composite,Canvas API中對應的函數就是globalCompositeOperation。

globalCompositeOperation中有個屬性值是“destination-out",也就是當繪畫重疊時顯示透明。剛好用到這里,我們就可以在畫布上亂畫,畫過的地方就是重疊的地方,就會變成透明,然后露出畫布下的東西,也就是我們想要的效果。

html 代碼如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <title></title>
        <link rel="stylesheet" type="text/css" href="css/guaguale.css"/>
    </head>
    <body>
        <!-- 大的背景盒子-->
        <div id="main">
            <!-- 定位的盒子-->
            <div class="canvasBox">
                <!-- 放內容的盒子-->
                <span id="prize">
                    恭喜發財,紅包拿來
                </span>
                <!-- 蒙版畫布-->
                <canvas id="canvas"></canvas>
            </div>
        </div>
    </body>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext('2d');
        /* 畫布偏移量,下面用到的時候再介紹*/
        var arr = getOffset(canvas);
        var oLeft = arr[0];
        var oTop = arr[1];
        
        /* 初始化畫布*/
        ctx.beginPath();
        ctx.fillStyle = '#ccc';
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.closePath();
        
        /* 增加觸摸監聽*/
        document.addEventListener("touchstart",function(){
            /* 初始化畫筆*/
            ctx.beginPath();
            /* 畫筆粗細*/
            ctx.lineWidth = 30;
            /* 設置組合效果*/
            ctx.globalCompositeOperation = 'destination-out';
            /* 移動畫筆原點*/
            ctx.moveTo(event.touches[0].pageX-oLeft,event.touches[0].pageY-oTop);
        },false)
        
        document.addEventListener("touchmove",function(){
            /* 根據手指移動畫線,使之變透明*/
            ctx.lineTo(event.touches[0].pageX-oLeft,event.touches[0].pageY-oTop);
            /* 填充*/
            ctx.stroke();
        })
        
        /* 之所以會用到下面的那個函數getOffset(obj)
         * 是因為event.touches[0].pageX、pageY獲取的是相對於可視窗口的距離
         * 而lineTo畫筆的定位是根據畫布位置定位的
         * 所以就要先獲取到畫布(canvas)相對於可視窗口的距離,然后計算得出觸摸點相對於畫布的距離 
         * */
        
        
        /* 獲取該元素到可視窗口的距離*/
        function getOffset(obj){
            var valLeft = 0,valTop = 0;
            function get(obj){
                valLeft += obj.offsetLeft;
                valTop += obj.offsetTop;
                /* 不到最外層就一直調用,直到offsetParent為body*/
                if (obj.offsetParent.tagName!='BODY') {
                    get(obj.offsetParent);
                }
                return [valLeft,valTop];
            }
            return get(obj);
        }
        
    </script>
</html>

css代碼如下:

*{
    margin: 0;
    padding: 0;
}
#main{
    width: 100%;
    padding: 20px 0;
    background-color: red;
}

.canvasBox{
    width: 78%;
    height: 160px;
    border-radius: 10px;
    background-color: #FFF;
    margin-left: 11%;
    line-height: 160px;
    text-align: center;
    position: relative;
}

#canvas{
    width: 96%;
    height: 96%;
    position: absolute;
    left: 2%;
    top: 2%;
    background-color: transparent;
}

 

第五步要用到canvas像素點的獲取(這塊注意,像素級操作,要在服務器環境下打開)

getImageData(int x,int y,int width,int height):該方法獲取canvas上從(x,y)點開始,寬為width、高為height的圖片區域的數據,該方法返回的是一個CanvasPixelArray對象,該對象具有width、height、data等屬性。data屬性為一個數組,該數組每4個元素對應一個像素點。

(對圖片的反相操作也可以這樣做,改變rgba值)

getImageData(int x,int y,int width,int height)返回的對象,data里面存儲的是像素點信息

我們再打印data,data屬性為一個數組,每4個元素對應一個像素點(以rgba的形式保存每一個像素點的信息)。

所以我們就可以根據像素點的opcity值來判斷這個像素點是不是透明,是不是等於0?

透明的像素點數量/總像素點數量 = 擦除比例

js代碼: 

document.addEventListener("touchend",function(){
            /* 獲取imageData對象*/
            var imageDate =    ctx.getImageData(0,0,canvas.width,canvas.height);
            /* */
            var allPX = imageDate.width * imageDate.height;
            
            var iNum = 0;//記錄刮開的像素點個數
            
            for(var i=0;i<allPX;i++){
                if(imageDate.data[i*4+3] == 0){
                    iNum++;
                }
            }
            if(iNum >= allPX*3/4){
                // disappear里面寫了緩慢清除的css3動畫效果
                canvas.setAttribute('class','disappear');     
            }
        },false)

" .disappear " 的css樣式,css3消失動畫

.disappear{
    -webkit-animation: disa 2s 1;
    animation: disa 2s 1;
    -webkit-animation-fill-mode: forwards;
    -moz-animation-fill-mode: forwards;
    -o-animation-fill-mode: forwards;
    animation-fill-mode: forwards;
}

@keyframes disa{
    0%{opacity:1;}
    100%{opacity: 0;}
}

 

相對比網上的其他一些實現方式,這種還是比較簡單的一種,大家相互學習。有什么其他的辦法可以留言相互學習

 

 

參考鏈接:

1、【HTML5】Canvas之globalCompositeOperation屬性詳解  (講屬性值)

2、Canvas里的globalCompositeOperation (講兼容)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM