demo1手机端 demo2手机+PC
首先我看实在移动端还是在PC端
引入要被擦得图片进去Canvas
技术除以采样范围就可以得到百分比了,这样我们不要全部擦完就可以得到底图。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=640,user-scalable=no,target-densitydpi=device-dpi" />
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="format-detection" content="telephone=no"/>
<style>
*{
margin:0;
padding:0;
}
body{
max-width:640px;
width:100%;
margin:0 auto;
height:100%;
position:absolute;
}
.txt{
width:100%;
height:100%;
max-width:640px;
}
.txt img{
width:100%;
max-width:640px;
height:100%;
}
.can{
position: absolute;
top:0;
left:0;
width:100%;
}
#Mycanvas{
opacity: 1;
-webkit-transition: opacity .5s;
-ms-transition: opacity .5s;
-moz-transition: opacity .5s;
}
.Mycanvas{
opacity:0!important;
}
</style>
</head>
<body>
<section class="bg">
<div class="txt">
<img src="images/2.jpg" alt="" />
</div>
<div class="can">
<canvas id="Mycanvas"></canvas>
</div>
</section>
</body>
<script>
!(function(doc){
var MyCanvas=doc.querySelector("#Mycanvas"),
cont=MyCanvas.getContext("2d"),
dataArr=[],
a=false,
stop=startx=starty=movex=movey=timer=null,disyance=30,
hastouch = "ontouchstart" in window?true:false,
tapstart=hastouch?"touchstart":"mousedown",
tapmove=hastouch?"touchmove":"mousemove",
tapend=hastouch?"touchend":"mouseup";
MyCanvas.width=window.innerWidth;
MyCanvas.height=853;
/**
* *兼容动画函数
* @param {Function} callback [description]
* @return {[type]} [description]
*/
// window.requestAnimFrame = (function(callback) {
// return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
// function(callback) {
// window.setTimeout(callback, 1000 / 60);
// };
// })();
// var cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
/**
* *引入图片 转化成Canvas
* @return {[type]} [description]
*/
function cvsToImg(){
var img=new Image();
img.src="images/1.jpg";
// img.crossOrigin = "Anonymous";
img.οnlοad=function(){
cont.drawImage(img,0,0);
//文章的核心 设置源和目标的重叠区域为透明
cont.globalCompositeOperation="destination-out";
}
}
cvsToImg();
/**
* *触摸事件绑定
*/
MyCanvas.addEventListener(tapstart,start,false);
/**
* *开始挂
* @param {[type]} event [description]
* @return {[type]} [description]
*/
function start(event){
/**清楚像素值计算计时器**/
clearTimeout(timer);
var touch=hastouch?event.targetTouches[0]:null;
//获取初始坐标
startx=hastouch?touch.pageX-getPos(MyCanvas).x1:event.clientX-getPos(MyCanvas).x1;
starty=hastouch?touch.pageY-getPos(MyCanvas).y1:event.clientY-getPos(MyCanvas).y1;
/**事件绑定**/
MyCanvas.addEventListener(tapmove,move,false);
MyCanvas.addEventListener(tapend,end,false);
event.preventDefault();
}
function move(event){
//清楚计算透明度计时器
clearTimeout(timer);
var touch=hastouch?event.targetTouches[0]:null;
//移动的坐标
movex=hastouch?touch.pageX-getPos(MyCanvas).x1:event.clientX-getPos(MyCanvas).x1;
movey=hastouch?touch.pageY-getPos(MyCanvas).y1:event.clientY-getPos(MyCanvas).y1;
cont.beginPath();
cont.strokeStyle="rgba(255,255,255,1)";
cont.lineWidth=60;
cont.lineCap="round"; //设置线条两端为圆弧
cont.lineJoin="round";
cont.moveTo(startx,starty);
cont.lineTo(movex,movey);
cont.stroke();
cont.closePath();//设置线条转折为圆弧
startx=movex;
starty=movey;
event.preventDefault();
}
function end(event){
timer=setTimeout(function(){
var imgData=cont.getImageData(0,0,window.innerWidth,853);
dataSize=imgData.data.length,
count=0;
for (var x =0; x<imgData.width; x+=disyance) {
for (var y = 0; y < imgData.height; y+=disyance) {
var i=(y*imgData.width+x)*4;
if(imgData.data[i+3]==0)count++;
};
};
if(count/(imgData.width*imgData.height/(disyance*disyance))>0.6&&!a){
MyCanvas.className="Mycanvas";
a=true;
}
},100)
MyCanvas.removeEventListener(tapmove,move,false);
event.preventDefault();
}
/**
* *获取离文档的编剧
* @param {[type]} elm [description]
* @return {[type]} [description]
*/
function getPos(elm){
var tops=elm.getBoundingClientRect().top+(document.body.scrollTop||document.documentElement.scrollTop), //获取上边距和左边距
lefts=elm.getBoundingClientRect().left+(document.body.scrollLeft||document.documentElement.scrollLeft);
return {"x1":lefts,"y1":tops};
}
/**
* *随机生成中奖下标
* @param {[type]} num [description]
* @return {[type]} [description]
*/
// function randomInRange(num){
// var ranDom=Math.floor(Math.random()*num);
// console.log(ranDom);
// return txtArr[ranDom];
// }
/**
* 计算颜色个数
* @param {[type]} child [description]
* @param {[type]} parentArr [description]
* @return {[type]} [description]
*/
// function perCent(child,parentArr){
// var count=0;
// for (var i = 0; i < parentArr.length; i++) {
// if(parentArr[i]==child)count++;
// };
// return count;
// }
// function drwas(gloBal){
// cont.globalAlpha=gloBal/100;
// console.log(cont.globalAlpha);
// }
// function upData(){
// gloBa-=globalSpeed;
// if(gloBa<0){
// gloBa=0;
// cancelAnimationFrame(stop);
// console.log(gloBa);
// console.log(stop);
// }else{
// stop=requestAnimationFrame(upData);
// }
// // drwas(gloBa);
// MyCanvas.style.opacity=gloBa/100;
// }
})(document)
</script>
</html>
定义两个结构 一个底图,一个Canvas
本文章的核心是讲 cont.globalCompositeOperation="destination-out"; 这个属性,目标与源的重叠是透明的 这样我们就思路出来了,把要掩盖的图片引入进Canvas里面,就是要擦掉的图片,在手机或者电脑上手指移动 的时候我们再画布目标上不断画一个源出来,这样不就是目标和源重叠了吗,重叠的地方透明了,被掩盖的底图就出来了。
hastouch = "ontouchstart" in window?true:false,
tapstart=hastouch?"touchstart":"mousedown",
tapmove=hastouch?"touchmove":"mousemove",
tapend=hastouch?"touchend":"mouseup";
首先我看实在移动端还是在PC端
ontouchstart in window 来判断,后面三个start move end 就可以决定是用touch 还是mouse ;
cont.drawImage(img,0,0);
引入要被擦得图片进去Canvas
接着start事件包含move和end连个事件 开始进行绘制 end事件触发的时候记得解绑move以免重复绑定。
if(count/(imgData.width*imgData.height/(disyance*disyance))>0.6&&!a){
MyCanvas.className="Mycanvas";
a=true;
}
关于这个0.6是什么,就是当你绘制的图形大于整个画布部分的60%; 然后canvas就自动消失,显示底部,一般我们刮刮乐的时候,不会全部挂完就显示出来,就是这个效果。
timer=setTimeout(function(){
var imgData=cont.getImageData(0,0,window.innerWidth,853);
dataSize=imgData.data.length,
count=0;
for (var x =0; x<imgData.width; x+=disyance) {
for (var y = 0; y < imgData.height; y+=disyance) {
var i=(y*imgData.width+x)*4;
if(imgData.data[i+3]==0)count++;
};
};
if(count/(imgData.width*imgData.height/(disyance*disyance))>0.6&&!a){
MyCanvas.className="Mycanvas";
a=true;
}
},100
手指一离开的时候,利用getImageData()方法返回的data属性来获取整个画布的像素值rgba 四个点的值,但是一个画布很大,我们不可能每个点都去采集获取,那样性能就很低了,会很卡,利用采样的方法进行
disyance=30
这个30代表了我没30*30像素我取一个像素点来获取rgba中的a值,既然cont.globalCompositeOperation="destination-out"; 那透明每个像素点的a值都是0 取每30*30像素的第一个像素中的a,(小图的话 采样的宽和高可以小一点),如果的等于a==0 我的计数器count++;count必须定义在end方法里面。每次都要清空不能定义全局对象.
count/(imgData.width*imgData.height/(disyance*disyance))>0.6
技术除以采样范围就可以得到百分比了,这样我们不要全部擦完就可以得到底图。
最后说一下
setTimeout
我再end里面定义了一个定时器,意思就是离开之后不马上计算,隔一会儿,但是更重要的原因就是性能,离开之后又触发start事件 我就清楚这个计算进程,不占用浏览器的计算线程,这样就不会重复绘制计算像素比例了.