今天做一个刮奖的项目,要用到canvas,在用户进行刮奖时,从后台请求数据并且用canvas将奖品名字画在画布上,但是问题来了,用户在进行刮奖操作时,从后台请求的数据要画在画布上,好像是需要重新绘制图形,但是那样用户第一步刮奖的操作就无效了,请问是否能够只更新奖品名字那一部分?或者有其他更好的办法?
附代码:
$(function() { //定义Lottery类 function Lottery(id, cover, coverType, width, height, drawPercentCallback) { this.conId = id; this.conNode = document.getElementById(this.conId); this.cover = cover; this.coverType = coverType; this.background = null; this.backCtx = null; this.mask = null; this.maskCtx = null; this.lottery = null; this.lotteryType = 'image'; this.width = width || 800; this.height = height || 100; this.clientRect = null; this.drawPercentCallback = drawPercentCallback; } Lottery.prototype = { createElement: function (tagName, attributes) { var ele = document.createElement(tagName); for (var key in attributes) { ele.setAttribute(key, attributes[key]); } return ele; }, //涂抹区域百分比 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); }, //改变canvas大小的工具方法。 resizeCanvas: function (canvas, width, height) { canvas.width = width; canvas.height = height; canvas.getContext('2d').clearRect(0, 0, width, height); }, //绘制点击和涂抹区域 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, 15, 0, Math.PI * 2, true); this.maskCtx.fill(); if (this.drawPercentCallback) { this.drawPercentCallback.call(null, this.getTransparentPercent(this.maskCtx, this.width, this.height)); } }, //绑定事件 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); } else { document.addEventListener("touchmove", function (e) { if (isMouseDown) { e.preventDefault(); } }, false); document.addEventListener('touchend', 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); }, //添加两个canvas到刮奖容器,并获取2d上下文 drawLottery: function () { 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(/[\w\W]| /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'); //绘制第一个canvas 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); _this.drawMask(); } 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 = 20; this.backCtx.font = 'Bold ' + fontSize + 'px Arial'; this.backCtx.textAlign = 'center'; this.backCtx.fillStyle = '#da345f'; this.backCtx.fillText(this.lottery, this.width / 2, this.height / 2 + fontSize / 2); this.backCtx.restore(); this.drawMask(); } }, //绘制第二个canvas drawMask: function () { 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; } }, //调用入口init init: function (lottery, lotteryType) { this.lottery = lottery; this.lotteryType = lotteryType || 'image'; this.drawLottery(); } }; //加载页面绘制空白数据 window.onload = function () { var lottery = new Lottery('scratch-area', '#092f57', 'color', 300, 102,drawPercent); lottery.init("",'text'); //判断刮开的区域 function drawPercent(percent) { $("#drawPercent").html(percent); var area = $("#drawPercent").html(); //console.log(area); } //开始刮奖请求数据,并重新绘制canvas $("#scratch-area").data("flag", true).on("touchstart", function (e) { e.preventDefault(); if ($(this).data("flag")) { $.ajax({ url: '/scratchcard/lottery?eventId=' + eventId + '&mappId=' + appId, dataType: 'json', success: function (data) { console.log(data); $(".frequency-total").text(data.prizeChance); var prize = data.prizeName; //抽奖次数 var prizeChance = data.prizeChance; //是否抽中奖品 var prizeType = parseInt(data.prizeType); //判断抽奖机会 if (prizeChance > 0) { var lottery = new Lottery('scratch-area', '#092f57', 'color', 300, 102, drawPercent); lottery.init(prize, 'text'); if (prizeType == 0) { $(".look-prize").css("visibility","visible").on("click",function(){ window.location.href="/center/coupon?mappId="+mappId; }); } function drawPercent(percent) { $("#drawPercent").html(percent); var area = $("#drawPercent").html(); if (area > 9.5 && prizeType == 2) { //app.alert('恭喜您获得' + '"' + prize + '"!', '刮刮乐', function () { // //location.reload(); // console.log("in") //}); $(".look-prize").css("visibility","visible").html("点我刷新").on("click",function(){ location.reload(); }); } } } else { app.alert('您的剩余刮奖次数不足!', '刮刮乐',function(){ location.reload(); }); } }, error: function (error) { app.alert(error.responseText, '刮刮乐'); } }); $(this).data("flag", false); console.log("in") } }); }; });
好多代码,厉害了我的哥
讲下大致的思路,其中dom结构这么放
<section>
<img src=x />
<canvas></canvas>
</section>
然后position布局放canvas覆盖在img上面,然后canvas监听touch和mouseMove事件,根据event的layerX/layerY或者offsetX/offsetY得出当前运动的坐标点,然后清理掉canvas上面的图案,清理方法在下面。
可以做个回掉的监测,当清理的面积(根据半径和移动的xy坐标可算)大于整个canvas面积的70%(随便举例)就算刮奖完成。
别看讲的这么简单,写完这部分代码,加上各种边界检查等容错得弄几个小时吧。
以下是原答案:
建议做两层,然后重叠,canvas默认是png类型有透明通道的,直接刮开canvas下面就看到了奖品的那个图片。
canvas里面有cleanRect的方法,清理掉矩形区域很好用,但是圆形区域没有直接的接口,但是利用globalCompositeOperation可以hack一个清理圆形区域的方法出来。
补充一下关于clean arc 方面的一点东西:
http://stackoverflow.com/ques...
function cleanArc(context, x, y, radius){ context.globalCompositeOperation = 'destination-out' context.arc(x, y, radius, 0, Math.PI*2, true); context.fill(); }