站長資訊網
        最全最豐富的資訊網站

        HTML5 Canvas實戰之刮獎效果的實例詳情

        近年來由于移動設備對HTML5的較好支持,經常有活動用刮獎的效果,最近也在看H5方面的內容,就自己實現了一個,現分享出來跟大家交流。

        1、效果

        2、原理

        原理很簡單,就是在刮獎區添加兩個canvas,第一個canvas用于顯示刮開后顯示的內容,可以是一張圖片或一個字符串,第二個canvas用于顯示涂層,可以用一張圖片或用純色填充,第二個canvas覆蓋在第一個canvas上面。

        當在第二個canvas上點擊或涂抹(點擊然后拖動鼠標)時,把點擊區域變為透明,這樣就可以看到第一個canvas上的內容,即實現了刮獎效果。

        3、實現

        (1)定義Lottery類

        function Lottery(id, cover, coverType, width, height, drawPercentCallback) {      this.conId = id;      this.conNode = document.getElementById(this.conId);      this.cover = cover || '#CCC';      this.coverType = coverType || 'color';      this.background = null;      this.backCtx = null;      this.mask = null;      this.maskCtx = null;      this.lottery = null;      this.lotteryType = 'image';      this.width = width || 300;      this.height = height || 100;      this.clientRect = null;      this.drawPercentCallback = drawPercentCallback;  }

        對參數解釋一下:

        • id:刮獎容器的id

        • cover:涂層內容,可以為圖片地址或顏色值,可空,默認為 #ccc

        • coverType:涂層類型,值為 image 或 color,可空,默認為 color

        • width:刮獎區域寬度,默認為300px,可空

        • height:刮獎區域高度,默認為100px,可空

        • drawPercentCallback:刮開的區域百分比回調,可空

        然后還定義了幾個需要用到的變量:

        • background:第一個canvas元素

        • backCtx:background元素的2d上下文(context)

        • mask:第二個canvas元素

        • maskCtx:mask元素的2d上下文(context)

        • lottery:刮開后顯示的內容,可以為圖片地址或字符串

        • lotteryType:刮開后顯示的內容類型,值為 image 或 text,要跟lottery匹配

        • clientRect:用于記錄mask元素的 getBoundingClientRect() 值

        (2)添加二個canvas到刮獎容器,并獲取2d上下文

        this.background = this.background || this.createElement('canvas', {      style: 'position:absolute;left:0;top:0;'  });  this.mask = this.mask || this.createElement('canvas', {      style: 'position:absolute;left:0;top:0;'  });    if (!this.conNode.innerHTML.replace(/[wW]| /g, '')) {      this.conNode.appendChild(this.background);      this.conNode.appendChild(this.mask);      this.clientRect = this.conNode ? this.conNode.getBoundingClientRect() : null;      this.bindEvent();  }    this.backCtx = this.backCtx || this.background.getContext('2d');  this.maskCtx = this.maskCtx || this.mask.getContext('2d');

        這里用于了createElement工具方法,另外還綁定了事件,后面介紹。

        (3)繪制第一個canvas

        第一個canvas分兩種類型,image 和 string,如果是圖片直接用canvas的drawImage就可以了,如果是string,要先用白色填充,然后在上下左右居中的地方繪制字符串,代碼如下:

        if (this.lotteryType == 'image') {      var image = new Image(),          _this = this;      image.onload = function () {          _this.width = this.width;          _this.height = this.height;          _this.resizeCanvas(_this.background, this.width, this.height);          _this.backCtx.drawImage(this, 0, 0);      }      image.src = this.lottery;  } else if (this.lotteryType == 'text') {      this.width = this.width;      this.height = this.height;      this.resizeCanvas(this.background, this.width, this.height);      this.backCtx.save();      this.backCtx.fillStyle = '#FFF';      this.backCtx.fillRect(0, 0, this.width, this.height);      this.backCtx.restore();      this.backCtx.save();      var fontSize = 30;      this.backCtx.font = 'Bold ' + fontSize + 'px Arial';      this.backCtx.textAlign = 'center';      this.backCtx.fillStyle = '#F60';      this.backCtx.fillText(this.lottery, this.width / 2, this.height / 2 + fontSize / 2);      this.backCtx.restore();  }

        (4)繪制第二個canvas

        第二個canvas也分 image 或 color 填充兩種情況。

        這里有一個難點,就是如何把鼠標點擊區域變成透明的呢?答案在這里:developer.mozilla.org/en/docs/Web/Guide/HTML/Canvas_tutorial/Compositing

        即我們要把 maskCtx的 globalCompositeOperation 設置為 destination-out ,詳細的用法請參考上面給出的鏈接。

        因此,繪制第二個canvas的代碼如下:

        this.resizeCanvas(this.mask, this.width, this.height);  if (this.coverType == 'color') {      this.maskCtx.fillStyle = this.cover;      this.maskCtx.fillRect(0, 0, this.width, this.height);      this.maskCtx.globalCompositeOperation = 'destination-out';  } else if (this.coverType == 'image'){    var image = new Image(),          _this = this;      image.onload = function () {          _this.maskCtx.drawImage(this, 0, 0);          _this.maskCtx.globalCompositeOperation = 'destination-out';      }      image.src = this.cover;  }

        這里resizeCanvas是改變canvas大小的工具方法。

        (5)綁定事件

        繪制完成后,要給第二個canvas綁定事件。這里分了移動設備和PC-WEB兩處情況。移動設備是 touchstart 和 touchmove 事件,對應的PC-WEB是keydown 和 mousemove事件,另外PC-WEB方式下,要給document綁定一個mouseup事件,用來判斷鼠標是否按下。代碼如下:

        bindEvent: function () {      var _this = this;      var device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));      var clickEvtName = device ? 'touchstart' : 'mousedown';      var moveEvtName = device? 'touchmove': 'mousemove';      if (!device) {          var isMouseDown = false;          document.addEventListener('mouseup', function(e) {              isMouseDown = false;          }, false);      }      this.mask.addEventListener(clickEvtName, function (e) {          isMouseDown = true;          var docEle = document.documentElement;          if (!_this.clientRect) {              _this.clientRect = {                  left: 0,                  top:0              };          }          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 (!device && !isMouseDown) {              return false;          }          var docEle = document.documentElement;          if (!_this.clientRect) {              _this.clientRect = {                  left: 0,                  top:0              };          }          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);  }

        這里在事件中取出了鼠標坐標,調用了drawPoint進行了繪制,下面會講到。

        (6)繪制點擊和涂抹區域

        這里用到了canvas的徑向漸變,在鼠標從標處繪制一個圓形,代碼如下:

        drawPoint: function (x, y) {      this.maskCtx.beginPath();      var radgrad = this.maskCtx.createRadialGradient(x, y, 0, x, y, 30);      radgrad.addColorStop(0, 'rgba(0,0,0,0.6)');      radgrad.addColorStop(1, 'rgba(255, 255, 255, 0)');      this.maskCtx.fillStyle = radgrad;      this.maskCtx.arc(x, y, 30, 0, Math.PI * 2, true);      this.maskCtx.fill();      if (this.drawPercentCallback) {          this.drawPercentCallback.call(null, this.getTransparentPercent(this.maskCtx, this.width, this.height));      }  }

        (7)涂抹區域百分比

        在很多時候,我們還需要知道用戶涂抹了多少然后進行下一步交互,如當用戶涂抹了80%后,才允許下一張顯示。

        這個百分比如何計算呢?其實很簡單,我們可以用getImageData方法到畫布上指定矩形的像素數據,由于每個像素都是用rgba表示的,而涂抹過的區域是透明的,所以我們只需要判斷alpha通道的值就可以知道是否透明。代碼如下:

        getTransparentPercent: function(ctx, width, height) {      var imgData = ctx.getImageData(0, 0, width, height),          pixles = imgData.data,          transPixs = [];      for (var i = 0, j = pixles.length; i < j; i += 4) {          var a = pixles[i + 3];          if (a < 128) {              transPixs.push(i);          }      }      return (transPixs.length / (pixles.length / 4) * 100).toFixed(2);  }

        (8)調用入口init

        最后再提供一個入口用來進行繪制和重置,代碼如下:

        init: function (lottery, lotteryType) {      this.lottery = lottery;      this.lotteryType = lotteryType || 'image';      this.drawLottery();  }

        至此,關鍵代碼全部講解完了。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 国产第一福利精品导航| 久久精品aⅴ无码中文字字幕不卡| 国产精品无码无在线观看| 精品国产网红福利在线观看| 三级高清精品国产| 欧美亚洲国产精品久久蜜芽| 亚洲欧洲精品无码AV| 国产精品综合久久第一页| 国产精品三级国产电影| 亚洲综合精品香蕉久久网 | 热RE99久久精品国产66热| 亚洲精品在线观看视频| 国内精品伊人久久久久av一坑| 亚洲精品国产自在久久 | 亚洲精品无码久久久久| 久久精品无码一区二区app| 99热精品久久只有精品| 国产精品久久永久免费| 国产亚洲精品资源在线26u| 一本一道久久a久久精品综合| 精品国产亚洲男女在线线电影| 欧美一区二区精品| 精品亚洲综合在线第一区| 97在线精品视频| 97久久久久人妻精品专区| 精品无码av一区二区三区 | 精品免费人成视频app| 亚洲精品午夜无码电影网| 四虎国产精品永久地址入口| 久久无码人妻精品一区二区三区| 国产一区二区三精品久久久无广告| 一级香蕉精品视频在线播放| 视频二区国产精品职场同事| 欧美日韩在线亚洲国产精品| 久久这里只有精品首页| 国产精品欧美一区二区三区不卡| 国产精品后入内射日本在线观看| 国产精品日韩AV在线播放| 91精品美女在线| 国产精品久久毛片完整版| 亚洲国产精品国自产电影|