簡單入門canvas - 通過刮獎效果來學習


一 、前言

一直在做PC端的前端開發,從互聯網到行業軟件。最近發現移動端已經成為前端必備技能了,真是不能停止學習。HTML5新增的一些東西,canvas是用的比較多也比較復雜的一個,簡單的入門了一下,通過一個刮獎效果來學習。

 

二、canvas基礎

本文的目標是做一個刮獎效果,但是如果都不知道canvas是怎么回事,那么肯定也無法進行下去,所以先講講canvas基礎吧。

首先,該怎么理解canvas,思來想去,最好的理解辦法應該就是把canvas理解為一個空白的畫紙,一張你可以在上面畫畫的紙。

然后,你通過HTML標簽定義canvas,例如:

<canvas id="canvas" width="200" height="200">你的瀏覽器不支持canvas</canvas>

這樣,你就設置好了一張200×200的畫紙了。

這里要注意的是,canvas元素的寬高需要直接寫在標簽上或者通過js來設置。如果用css設置,那么瀏覽器會理解為把這張紙縮放成你設置的寬高。跟預期還是不一樣的。

 

然后,有了紙第二步就是畫東西了,畫東西需要的就是筆了。得到畫筆:

var ctx = document.getElementById("canvas").getContext("2d");

這樣,就有了這只筆了,叫ctx。

 

然后就是繪畫,這里要重點說明的是,canvas畫東西需要兩步

  • 第一步:告訴系統你要畫的東西的路徑
  • 第二步:告訴系統你需要用哪種方式填充路徑

簡單來說,你畫一條直線,那么代碼應該是告訴系統我要從0,0點到100,100點設置一條路徑,然后用黑色描邊這條路徑。

用代碼來描述我上面的那句話:

ctx.beginPath();    // 開始畫路徑
ctx.moveTo(0, 0);    // 移動到0,0點
ctx.lineTo(100, 100);    // 畫條直線到100,100點
ctx.closePath();    // 閉合路徑
ctx.lineWidth = "5";    // 設置線寬5px
// 至此路徑描述已經結束
ctx.strokeStyle = "#000";    // 設置描邊顏色為黑色
ctx.stroke();    // 執行描邊

上面代碼就可以畫一條直線了。當然,canvas能做的遠遠不止這些。

因為是基礎嘛,所以canvas就講到這里啦。關於canvas的東西太多,但原理基本都是這樣,當然除了描邊,還有填充(fill),填充各種形狀(fillRect),畫圖形(drawImage)等。系統學習canvas確實需要一本書或者一系列教程,因為我也是剛學,就不誤人子弟啦。這些基礎其實也夠理解下面的例子啦。

 

三、刮獎效果 

最簡單的一個刮獎效果原理大概就是這樣,放一張底圖(或者是文字,例如謝謝惠顧呀),然后再它之上覆蓋一個canvas,遮住這張圖,接着綁定touchstart(mousedown),touchmove(mousemove),touchend事件。然后移動的時候用“透明”填充canvas,那么被canvas遮住的部分就會呈現出來了。

直接看代碼吧,最簡單的實現

 

  1 <!DOCTYPE html>
  2 <!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->
  3 <!--[if IE 7]><html class="no-js lt-ie9 lt-ie8"><![endif]-->
  4 <!--[if IE 8]><html class="no-js lt-ie9"> <![endif]-->
  5 <!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
  6 
  7 <head>
  8     <meta charset="utf-8">
  9     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 10     <title>刮獎</title>
 11     <meta name="description" content="刮獎">
 12     <meta name="viewport" content="width=device-width, initial-scale=1">
 13     
 14     <style>
 15         body{margin: 0;}
 16         #price{width: 200px; height: 100px; font-size: 40px; color: #f60; line-height: 100px; text-align: center;}
 17         #canvas{position: absolute; top: 0; left: 0;}
 18     </style>
 19 </head>
 20 
 21 <body>
 22 
 23     <div id="price">謝謝惠顧</div>
 24     <canvas id="canvas" width="200" height="100">你的瀏覽器不支持canvas</canvas>
 25 
 26     <script>
 27         
 28         // 得到畫筆
 29         var cvs = document.getElementById("canvas"),
 30             ctx = cvs.getContext("2d"),
 31             touchRadius = 5;    // 默認手指觸摸半徑,可以自定義設置
 32         
 33         // 默認填充灰色來遮住文字
 34         ctx.fillStyle = "#ccc";
 35         ctx.fillRect(0, 0, 200, 100);    // fillRect,用矩形填充
 36         
 37         // 畫園的方法
 38         // @param { integer } 圓心的x坐標
 39         // @param { integer } 圓心的y坐標
 40         // @param { integer } 圓心半徑
 41         // @param { string } 填充的顏色(本例中會通過其余代碼設置為‘透明’,所以這個設置可以忽略)
 42         var fillCircle = function (x, y, radius, fillColor) {
 43             this.fillStyle = fillColor || "#eee";
 44             this.beginPath();
 45             this.moveTo(x, y);
 46             this.arc(x, y, radius, 0, Math.PI * 2, false);    // 標准畫圓
 47             this.fill();
 48         };
 49         
 50         // 得到塗抹的百分比(此處參考了部分他人代碼,出處http://www.cnblogs.com/jscode/p/3580878.html)
 51         var getTransparentPercent = function (ctx, width, height) {
 52             var imgData = ctx.getImageData(0, 0, width, height),    // 得到canvas的像素信息
 53                 pixles = imgData.data,
 54                 transPixs = [];
 55             for (var i = 0, j = pixles.length; i < j; i += 4) {    // 因為存儲的結構為[R, G, B, A],所以要每次跳4個長度
 56                 var a = pixles[i + 3];    // 拿到存儲alpha通道的值
 57                 if (a === 0) {    // alpha通道為0,就代表透明
 58                     transPixs.push(i);
 59                 }
 60             }
 61             return (transPixs.length / (pixles.length / 4) * 100).toFixed(2);
 62         }
 63         
 64         // 綁定事件(此處參考了部分他人代碼,出處http://www.cnblogs.com/jscode/p/3580878.html)
 65         // 需要判斷是PC還是手機
 66         var device = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()),
 67             clickEvtName = device ? 'touchstart' : 'mousedown',
 68             moveEvtName = device ? 'touchmove' : 'mousemove';
 69         
 70         // 判斷是不是開始觸摸等
 71         if (!device) {
 72             var isMouseDown = false;
 73             document.addEventListener('mouseup', function (e) {
 74                 isMouseDown = false;
 75             }, false);
 76         } else {
 77             document.addEventListener("touchmove", function (e) {
 78                 if (isMouseDown) {
 79                     e.preventDefault();
 80                 }
 81             }, false);
 82             document.addEventListener('touchend', function (e) {
 83                 isMouseDown = false;
 84             }, false);
 85         }
 86         
 87         // 開始移動
 88         cvs.addEventListener(clickEvtName, function (e) {
 89             isMouseDown = true;
 90             var x = (device ? e.touches[0].clientX : e.clientX);
 91             var y = (device ? e.touches[0].clientY : e.clientY);
 92             ctx.globalCompositeOperation = 'destination-out';    // 關鍵部分,描述當在canvas上再次繪畫時候的情況,這個設置便是之前所說的透明
 93             fillCircle.call(ctx, x, y, touchRadius);
 94             console.log("當前塗抹比例為:" + getTransparentPercent(ctx, 200, 100));
 95         }, false);
 96         
 97         // 移動中
 98         cvs.addEventListener(moveEvtName, function (e) {
 99             if (!device && !isMouseDown) {
100                 return false;
101             }
102             var x = (device ? e.touches[0].clientX : e.clientX);
103             var y = (device ? e.touches[0].clientY : e.clientY);
104             ctx.globalCompositeOperation = 'destination-out';
105             fillCircle.call(ctx, x, y, touchRadius);
106             console.log("當前塗抹比例為:" + getTransparentPercent(ctx, 200, 100));
107         }, false);
108     </script>
109 </body>
110 
111 </html>

 

上面的代碼完全是按照順序來寫的,所以應該很容易看懂的吧。其中關鍵的就是設置透明,還有就是設備的判斷。

Update:增加了一個判斷刮開了多少比例的代碼,因為實際需求很可能是刮開多少就告訴用戶刮獎結束。這里,因為刮開的部分是“透明的”,在代碼中就是說RGBA顏色值中的A是透明的,通過getImageData方法可以得到每個像素點的RGBA值,然后計算一下比例即可。在控制台可以看到刮開的比例數據。

至此,也算是用canva完成了第一個小效果了。

 

 

 

轉載本站文章請注明作者和出處 奇葩一朵朵 – http://www.cnblogs.com/season-huang/ ,請勿用於任何商業用途


免責聲明!

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



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