canvas刮刮卡
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title> - jsFiddle demo by artwl</title>
</head>
<body>
<!--
Author : Yaodongxin
Date : 2016-08-31
Tips : 如果蒙层是图片需要放到服务前环境测试
-->
<button id="freshBtn">刷新</button><label>已刮开 <span id="drawPercent">0%</span> 区域。</label>
<div style="position:relative" id = "card"></div>
<script type='text/javascript'>
var Card = function(options){
this.id = options.id;
this.width = options.width;//如果底层图层是图片,这个值会更新成图片尺寸
this.height = options.height;//如果底层图层是图片,这个值会更新成图片尺寸
this.wrap = null;//包裹canvas的对象
this.mask = null;//蒙层canvas对象
this.bacCtx = null; //context 对象
this.maskCtx = null; //context 对象
this.backType = options.backType || 'text'; // 'image' || 'text'
this.backImg = options.backImg; //刮开后的图层
this.texts = options.texts;//文字串码
this.fontSize = options.fontSize || 36;//文字串码字体大小
this.maskType = options.maskType || 'color';// 'color' || 'image'
this.maskImg = options.maskImg;
this.maskColor = options.maskColor || '#ccc';
this.callback = options.callback || false; //是否执行刮开百分比函数 boollean类型
this.percentDom = options.percentDom || document.getElementById('drawPercent');
}
Card.prototype = {
init : function(){
this.percentDom.innerHTML = '0%';
this.draw();
},
draw : function(){
this.wrap = document.getElementById(this.id);
this.drawMask();
},
// 画底层内容
drawCard : function(){
var _this = this;
_this.resizeCanvas(_this.card, _this.width, _this.height);
_this.bacCtx = _this.card.getContext('2d');
if(_this.backType == 'image'){
if(!_this.backImg){
console.error('A back image url is need.');
}else{
var image = new Image();
image.src = _this.backImg;
image.onload = function(){
_this.width = this.width;
_this.height = this.height;
_this.resizeCanvas(_this.card, this.width, this.height);
_this.bacCtx.drawImage(this, 0, 0); //绘背景图
}
image.error = function(){
console.error('image load failed. Check your url or network.');
}
}
}else{
_this.texts = _this.texts || getRandomStr(6);
_this.bacCtx.font = 'Bold ' + _this.fontSize + 'px "microsoft yahei"';
_this.bacCtx.fillStyle = '#ff6600';
_this.bacCtx.textAlign = 'center';
_this.bacCtx.textBaseline = 'middle';
_this.bacCtx.fillText(_this.texts, _this.width/2, _this.height/2);
}
},
// 绘制蒙层
drawMask : function(){
var _this = this;
// _this.wrap.innerHTML = ''
if(_this.wrap.innerHTML == ''){
_this.mask = document.createElement('canvas');
_this.wrap.appendChild(_this.mask);
_this.mask.setAttribute('style','position:absolute;left:0;top:0;');
_this.card = document.createElement('canvas');
_this.wrap.appendChild(_this.card);
this.bindEvents();
}
_this.resizeCanvas(_this.mask, _this.width, _this.height);
_this.maskCtx = _this.mask.getContext('2d');
if(_this.maskType == 'image'){
if(!_this.maskImg){
console.error('A mask image url is need.');
}else{
var image = new Image();
image.src = _this.maskImg;
image.onload = function(){
_this.maskCtx.drawImage(this, 0, 0); //绘蒙层
_this.drawCard();//绘制随机码
}
image.error = function(){
console.error('image load failed. Check your url or network.');
}
}
}else{
_this.maskCtx.fillStyle = this.maskColor;
_this.maskCtx.fillRect(0, 0, _this.width, _this.height);
_this.drawCard();//绘制随机码
}
_this.clientRect = _this.wrap ? _this.wrap.getBoundingClientRect() : null;
},
// 绘制擦除圆
drawPoint : function(x, y){
this.maskCtx.globalCompositeOperation = 'destination-out';
this.maskCtx.beginPath();
// var radgrad = this.maskCtx.createRadialGradient(x, y, 0, x, y, 30);
// radgrad.addColorStop(0, 'rgba(0, 0, 0, 1)');
// radgrad.addColorStop(1, 'rgba(0, 0, 0, 1)');
radgrad = '#fff';
this.maskCtx.fillStyle = radgrad;
this.maskCtx.arc(x, y, 30, 0, Math.PI * 2, true);
this.maskCtx.fill();
},
//绑定事件
bindEvents : function(){
var _this = this,
device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())),
clickEvtName = device ? 'touchstart' : 'mousedown',
moveEvtName = device? 'touchmove': 'mousemove',
isMouseDown = false,
start ={x:0, y:0},
end = {x:0, y:0};
if (!device) {//pc
isMouseDown = false;
document.addEventListener('mouseup', function(e) {
isMouseDown = false;
start ={x:0, y:0};
end = {x:0, y:0};
}, false);
document.addEventListener('mouseout', function(e) {
isMouseDown = false;
start ={x:0, y:0};
end = {x:0, y:0};
}, false);
}else{//mobile
document.addEventListener('touchmove', function(e) {
if (isMouseDown) {
e.preventDefault();
}
}, false);
document.addEventListener('touchend', function(e) {
isMouseDown = false;
start ={x:0, y:0};
end = {x:0, y:0};
}, false);
}
// 绑定擦除事件
var docEle = document.documentElement || document.body;
_this.mask.addEventListener(clickEvtName, function(e){
// console.log(device)
start ={x:0, y:0};
end = {x:0, y:0};
isMouseDown = true;
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 (!isMouseDown) {
return false;
}
isMouseDown = true;
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;
if(start.x!=0){
end.x = start.x;
end.y = start.y;
}
start.x = x;
start.y = y;
_this.drawPoint(x, y);
if(end.x!=0){
_this.addDraw(start, end);
}
if(_this.callback){
var percent = _this.drawPercent(_this.maskCtx);
_this.percentDom.innerHTML = percent + '%';
}
}, false);
},
/**
* 这个函数是用来补充move的时候中间的空白
* @param {object} start 形式{x:10,y:10}的对象,画线开始坐标
* @param {object} end 形式{x:20,y:20}的对象,画线结束坐标
*/
addDraw : function(start, end){
var _this = this;
_this.maskCtx.lineWidth = 60;
_this.maskCtx.lineStyle = '#f00';
_this.maskCtx.beginPath();
_this.maskCtx.moveTo(start.x, start.y);
_this.maskCtx.lineTo(end.x, end.y);
_this.maskCtx.stroke();
},
/**
* 重置canvas的宽高
* @param {object} canvas canvas对象
* @param {number} w canvas宽
* @param {number} h canvas高
*/
resizeCanvas : function(canvas, w, h){
canvas.width = w;
canvas.height = h;
},
/**
* 计算刮开的百分比
* @param {object} ctx context2d对象
* @return {number} 刮开图层所占百分比
*/
drawPercent : function(ctx){
var imgData = ctx.getImageData(0, 0, this.width, this.height),
pixles = imgData.data,
transPixs = [],
len = pixles.length;
for(var i = 0; i<len; i+=4){
if(pixles[i+3] == 0){
transPixs.push(pixles[i+3]);
}
}
return (transPixs.length/(len/4)*100).toFixed(2);
}
}
/**
* 生成随机串码
* @param {number} len 生成随机串码的长度
* @return {string} 生成的串码
*/
function getRandomStr(len) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for( var i=0; i < len; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
window.onload = function(){
var card = new Card({
id : 'card',
backType : 'text',
width : '325',
height : '174'
});
card.init();
// 刷新
document.getElementById('freshBtn').addEventListener('click', function(){
card.init();
}, false);
}
</script>
</body>
</html>
demo:预览地址

浙公网安备 33010602011771号