<!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:预览地址

canvas刮刮卡的更多相关文章

  1. canvas 绘制刮刮卡

    思路=> 用div来展示刮奖结果,用canvas绘制刮奖前展示的图片或者文字:将canvas叠在div上方,刮奖是只需要操作canvas配合touch事件即可简单完成. canvas刮奖可以用g ...

  2. canvas实现刮刮卡效果

    canvas实现刮刮卡效果 实现步骤: 设置页面背景图,即刮刮卡底部图片 绘制canvas 刮刮卡顶部图片drawImage 绑定事件 addEventListener  touchstart.tou ...

  3. qt qml 刮刮卡效果

    用canvas+mouseArea实现的刮刮卡效果. 表层是一层色彩,用手指划开,可看到下面的文字Lisence: MIT, 请保留本文档说明Author: surfsky.cnblogs.com 2 ...

  4. 网页闯关游戏(riddle webgame)--H5刮刮卡的原理和实践

    前言: 之前编写了一个网页闯关游戏(类似Riddle Game), 除了希望大家能够体验一下我的游戏外. 也愿意分享编写这个网页游戏过程中, 学到的一些知识. 对于刮刮卡, 想必大家都很熟悉, 也很喜 ...

  5. Html5实现移动端、PC端 刮刮卡效果

    刚从南方回来就分了一个刮刮卡效果的页面,特么的我在烦恼怎么用H5去实现这个效果呢,好不容易写出来了,产品居然说:“既然你可以写出来这个效果那当然好了,开始我只是打算让你实现点击就出现呢!”… … 尼玛 ...

  6. 用c#开发微信 (16) 微活动 2 刮刮卡

    微信营销是一种新型的营销模式,由于微信更重视用户之间的互动,故而这种营销推广不不能盲目地套用微博营销的单纯大量广告推送方式.这种方式在微信营销中的效果非常差,会令用户反感,继而取消去企业或商家的微信公 ...

  7. Atitit .html5刮刮卡的gui实现总结

    Atitit .html5刮刮卡的gui实现总结 #----两个案例canvas或者wScratchPad-1.4.4 1 #----1.添加panel  ,这个十mask div.....posti ...

  8. 使用HTML5实现刮刮卡效果

    你玩过刮刮卡么?一不小心可以中奖的那种.今天我给大家分享一个基于HTML5技术实现的刮刮卡效果,在PC上只需按住鼠标,在手机上你只需按住指头,轻轻刮去图层就可以模拟真实的刮奖效果. 我们利用HTML5 ...

  9. Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View

    一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...

  10. Android刮刮卡自定义控件

    网上的都是自己绘制的或者图片,我的需求是可以随意的自定义底部和顶部的布局.所以自己重写一个,原理就是直接继承 View 来实现一个刮层,让这个刮层和图片以及文字不产生任何依赖,再结合 FrameLay ...

随机推荐

  1. hdu 5444 Elven Postman(长春网路赛——平衡二叉树遍历)

    题目链接:pid=5444http://">http://acm.hdu.edu.cn/showproblem.php?pid=5444 Elven Postman Time Limi ...

  2. mysql启动參数(/etc/my.cnf)具体解释汇总

    在linux以下的/etc/my.cnf的參数具体解释汇总 MYSQL–my.cnf配置中文具体解释 basedir = path   使用给定文件夹作为根文件夹(安装文件夹). character- ...

  3. Iptables实现公网IP DNAT/SNAT

    Iptables实现NAT是最基本的功能,大部分家用路由都是基于其SNAT方式上网,使用Iptables实现外网DNAT也很简单,不过经常会出现不能正常NAT的现象.以下命令将客户端访问1.1.1.1 ...

  4. Oracle SQL性能优化 - 根据大表关联更新小表

    需求: 小表数据量20w条左右,大表数据量在4kw条左右,需要根据大表筛选出150w条左右的数据并关联更新小表中5k左右的数据. 性能问题: 对筛选条件中涉及的字段加index后,如下常规的updat ...

  5. 【设计模式】C++单例模式的几种写法——Java自动加载内部类对象,C++怎么破?

    单例模式是最简单的设计模式,就让我像玩简单的游戏一样写下去吧. v1: 简单模式 和这个版本有过一面之缘,但不敢苟同. class Singleton { private: Singleton() { ...

  6. Maven一大坑——缓存

    在Spring进行配置的时候,通常是分模块的,也就是一个配置文件会被另外一个配置文件所import. 但是今天的项目中我明明就都已经配置好了,文件也引入了,但是尼玛这个接口就是没有注入...... 后 ...

  7. 你要的最后一个字符就在下面这个字符串里,这个字符是下面整个字符串中第一个只出现一次的字符。(比如,串是abaccdeff,那么正确字符就是b了)

    include "stdafx.h" #include<iostream> #include<string> using namespace std; in ...

  8. Android错误之Location of the Android SDK has not been setup in the preferences

    解决的方法:打开Help-Install new software,更新文件就可以,这时国内的朋友就须要FQ了,详细有代理,能够网上自行搜索.

  9. H2 database 应用

    以前对内存表的引用一直采用sqllite,由于sqllite对字段的局限性无法满足需要.后来对h2 有了一定青睐做了下应用.下面对h2进行介绍. 1. H2数据库引擎 H2数据库由Java编写的,它可 ...

  10. WEB服务器、应用程序服务器、HTTP服务器区别【转】

    WEB服务器.应用程序服务器.HTTP服务器有何区别?IIS.Apache.Tomcat.Weblogic.WebSphere都各属于哪种服务器,这些问题困惑了很久,今天终于梳理清楚了: Web服务器 ...