详解HTML5实现橡皮擦的擦除效果的示例代码(图)


本文摘自PHP中文网,作者黄舟,侵删。

最近项目刚好用到这种效果,也就是有点像刮刮卡一样,在移动设备上,把某张图片刮掉显示出另一张图片。效果图如下:

   DEMO请戳右:DEMO

 这种在网上还是挺常见的,本来就想直接网上找个demo套用下他的方法就行了,套用了才发现,在android上卡出翔了,因为客户要求,在android不要求特别流畅,至少要能玩,但是网上找的那个demo实在太卡,根本就是没法玩的情况。于是就想自己写一个算了,本文也就权当记录一下研究过程。

  这种刮图的效果,首先想到就是用HTML5的canvas来实现,而canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。用法很简单: 

1

2

3

4

5

6

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();

  上面那段代码就实现了圆形区域的擦除,也就是先实现一个圆形路径,然后把这个路径作为剪辑区域,再清除像素就行了。有个注意点就是需要先保存绘图环境,清除完像素后要重置绘图环境,如果不重置的话以后的绘图都是会被限制在那个剪辑区域中。

  擦除效果有了,现在就是写鼠标移动擦除的效果了,下面我均用鼠标来描述,因为移动端也差不多,就是把mousedown换成touchstart,mousemove换成touchmove,mouseup换成touchend、以及获取坐标点由e.clientX换成e.targetTouches[0].pageX而已。

  实现鼠标移动擦除,刚开始就是想到鼠标移动时在触发的mousemove事件中对鼠标所在位置进行圆形区域擦除,写出来后发现,当鼠标移动速度很快的时候,擦除的区域就不连贯了,就会出现下面这种效果,这显然不是我们想要的橡皮擦擦除效果。

  

  既然所有点不连贯,那接下来要做的事就是把这些点连贯起来,如果是实现画图功能的话,就可以直接通过lineTo把两点之间连接起来再绘制,但是擦除效果中的剪辑区域要求要是闭合路径,如果是单纯的把两个点连起来就无法形成剪辑区域了。然后我就想到用计算的方法,算出两个擦除区域中的矩形四个端点坐标来实现,也就是下图中的红色矩形:

  

  计算方法也很简单,因为可以知道两个剪辑区域连线两个端点的坐标,又知道我们要多宽的线条,矩形的四个端点坐标就变得容易求了,所以就有了下面的代码:


1

2

3

4

5

6

7

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就是两个端点,从而求出了四个端点的坐标。这样一来,剪辑区域就是圈加矩形,代码组织起来就是:

1

2

3

4

5

6

7

8

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来实现的。代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

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%,那说明当前画布上就以后有百分六十以上的区域被擦除了,就可以自动呈现图片了。

阅读剩余部分

相关阅读 >>

HTML5的头部head的详解

使用HTML5 canvas封装一个echarts实现不了的饼图

HTML5删除的标签有哪些

h5 canvas中fill 与stroke文字效果实现实例

使用h5做出添加禁止缩放

HTML5中的常见错误用法

HTML5中返回audiotracklist对象的属性audiotracks

HTML5 details标签的作用是什么?<details>标签的使用方法介绍(附使用实例)

HTML5中关于history模式的详解

浅谈HTML5新增及移除的元素

更多相关阅读请进入《HTML5》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...