canvas教程

HTML5 实现橡皮擦的擦除效果(2)

字号+ 作者:H5之家 来源:H5之家 2016-11-12 12:00 我要评论( )

如此一来,鼠标擦除的效果就实现了,不过还有一个要实现的点,就是大部分擦除的效果,当你擦了一定数量的像素后,就会自动把所有图片内容呈现出来,这个效果,我是用imgData来实现的。代码如下: var imgData = ctx

  如此一来,鼠标擦除的效果就实现了,不过还有一个要实现的点,就是大部分擦除的效果,当你擦了一定数量的像素后,就会自动把所有图片内容呈现出来,这个效果,我是用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)

  这样就可以较大限度的防止用户狂点击了,如果有其他更好的检查方法欢迎给出意见,谢谢。

  到了这一步就都写完了,然后就是测试的时候了,结果并不乐观,在android上还是卡啊卡啊,所以又得另想办法,最终发现了绘图环境中的globalCompositeOperation这个属性,这个属性的默认值是source-over,也就是,当你在已有像素上进行绘图时会叠加,但是还有一个属性是destination-out,官方解释就是:在源图像外显示目标图像。只有源图像外的目标图像部分才会被显示,源图像是透明的。好像不太好理解,但是其实自己测试一下就会发现很简单,也就是在已有像素的基础上进行绘图时,你绘制的区域里的已有像素都会被置为透明,直接看张图更容易理解:

  

  globalCompositeOperation属性效果图解。

  有了这个属性后,就意味着不需要用到clip,也就不需要用sin、cos什么的计算剪辑区域,直接用条粗线就行了,这样一来就能够很大限度的降低了计算量,同时减少了绘图环境API的调用,性能提升了,在android上运行应该也会流畅很多,下面是修改后的代码:

tapClip(){ var hastouch = "ontouchstart" in window?true:false, tapstart = hastouch?"touchstart":"mousedown", tapmove = hastouch?"touchmove":"mousemove", tapend = hastouch?"touchend":"mouseup"; canvas.addEventListener(tapstart , function(e){
     clearTimeout(timeout) e.preventDefault(); x1
= hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft; y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop; ctx.lineCap = "round";  //设置线条两端为圆弧 ctx.lineJoin = "round";  //设置线条转折为圆弧 ctx.lineWidth = a*2;   ctx.globalCompositeOperation = "destination-out"; ctx.save(); ctx.beginPath() ctx.arc(x1,y1,1,0,2*Math.PI); ctx.fill(); ctx.restore(); canvas.addEventListener(tapmove , tapmoveHandler); canvas.addEventListener(tapend , function(){ canvas.removeEventListener(tapmove , tapmoveHandler);
       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) });
function tapmoveHandler(e){ e.preventDefault() x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft; y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop; ctx.save(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); ctx.restore() x1 = x2; y1 = y2; } }) }

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
网友点评
0