DEMO请戳右: DEMO
这种在网上还是挺常见的,本来就想直接网上找个demo套用下他的方法就行了,套用了才发现,在android上卡出翔了,因为客户要求,在android不要求特别流畅,至少要能玩,但是网上找的那个demo实在太卡,根本就是没法玩的情况。于是就想自己写一个算了,本文也就权当记录一下研究过程。
这种刮图的效果,首先想到就是用HTML5的canvas来实现,而canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。用法很简单:
ctx.save() ctx.beginPath() ctx.arc(x2,y2,a,0,2*Math.PI); ctx.clip() ctx.clearRect(0,0,canvas.width,canvas.height); ctx.restore();
var asin = a*Math.sin(Math.atan((y2-y1)/(x2-x1))); var acos = a*Math.cos(Math.atan((y2-y1)/(x2-x1))) var x3 = x1+asin;var y3 = y1-acos; var x4 = x1-asin; var y4 = y1+acos; var x5 = x2+asin;var y5 = y2-acos; var x6 = x2-asin;var y6 = y2+acos;
x1、y1和x2、y2就是两个端点,从而求出了四个端点的坐标。这样一来,剪辑区域就是圈加矩形,代码组织起来就是:
hastouch = "ontouchstart" window?:= hastouch?"touchstart":"mousedown"= hastouch?"touchmove":"mousemove"= hastouch?"touchend":"mouseup"= hastouch?e.targetTouches[0].pageX:e.clientX-= hastouch?e.targetTouches[0].pageY:e.clientY-0,2*0,0= hastouch?e.targetTouches[0].pageX:e.clientX-= hastouch?e.targetTouches[0].pageY:e.clientY- asin = a*Math.sin(Math.atan((y2-y1)/(x2-x1))); acos = a*Math.cos(Math.atan((y2-y1)/(x2-x1))) x3 = x1+ y3 = y1- x4 = x1- y4 = y1+ x5 = x2+ y5 = y2- x6 = x2- y6 = y2+0,2*0,00,0==
如此一来,鼠标擦除的效果就实现了,不过还有一个要实现的点,就是大部分擦除的效果,当你擦了一定数量的像素后,就会自动把所有图片内容呈现出来,这个效果,我是用imgData来实现的。代码如下:
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x<imgData.width;x+=1){
for(var y=0;y<imgData.height;y+=1){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] > 0){
dd++
}
}
}if(dd/(imgData.width*imgData.height)<0.4){
canvas.className = "noOp";
} 获取到imgData,对imgData里的像素进行遍历,然后再对imgData的data数组里的rgba中的alpha进行分析,也就是分析透明度,如果像素被擦除了,那透明度就是0了,也就是把当前画布中透明度不为0的像素的数量跟画布总像素数进行比较,如果透明度不为0 的像素数比例低于40%,那说明当前画布上就以后有百分六十以上的区域被擦除了,就可以自动呈现图片了。
此处注意,我是把检查像素这段代码方法mouseup事件里面的,因为这个计算量相对来说还是不小,如果用户狂点鼠标,就会狂触发mouseup事件,也就是会疯狂的触发那个循环计算像素,计算量大到阻塞进程,导致界面卡住的情况,缓解办法如下:加个timeout,延迟执行像素计算,而在每一次点击的时候再清除timeout,也就是如果用户点击很快,这个计算也就触发不了了,还有一个提升的办法就是抽样检查,我上面的写法是逐个像素检查,逐个像素检查的话像素量太大,肯定会卡的,所以可以采用抽样检查,比如每隔30个像素检查一次,修改后的代码如下:
timeout = setTimeout(function(){
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x<imgData.width;x+=30){
for(var y=0;y<imgData.height;y+=30){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] >0){
dd++
}
}
} if(dd/(imgData.width*imgData.height/900)<0.4){
canvas.className = "noOp";
}
},100) hastouch = "ontouchstart" window?:= hastouch?"touchstart":"mousedown"= hastouch?"touchmove":"mousemove"= hastouch?"touchend":"mouseup"=
hastouch?e.targetTouches[0].pageX:e.clientX-= hastouch?e.targetTouches[0].pageY:e.clientY-= "round"= "round"= a*2= "destination-out"1,0,2*
imgData = ctx.getImageData(0,0 dd = 0( x=0;x<imgData.width;x+=30(
y=0;y<imgData.height;y+=30 i = (y*imgData.width + x)*4(imgData.data[i+3] > 0++(dd/(imgData.width*imgData.height/900)<0.4){
canvas.className = "noOp"= hastouch?e.targetTouches[0].pageX:e.clientX-= hastouch?e.targetTouches[0].pageY:e.clientY-== 擦除那部分代码就这么一点,也就相当于画图功能,直接设置line属性后通过lineTo进行绘制线条,只要事前把globalCompositeOperation设成destination-out,你所进行的一切绘制,都变成了擦除效果。鼠标滑动触发的事件里面代码也少了很多,绘图对象的调用次数减少了,计算也减少了,性能提升大大滴。
改好代码后就立即用自己的android机子测试了一下,果然如此,跟上一个相比,流畅了很多,至少达到了客户要求的能玩的地步了。
以上就是详解HTML5实现橡皮擦的擦除效果的示例代码(图)的详细内容,更多请关注Gxl网其它相关文章!
查看更多关于详解HTML5实现橡皮擦的擦除效果的示例代码(图)的详细内容...