canvas教程

HTML5 实现橡皮擦的擦除效果

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

html5-HTML5 实现橡皮擦的擦除效果

  声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!

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

  

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

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

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

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

  

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

  

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

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

var hastouch = "ontouchstart" in window?true:false,//判断是否为移动设备 tapstart = hastouch?"touchstart":"mousedown", tapmove = hastouch?"touchmove":"mousemove", tapend = hastouch?"touchend":"mouseup"; canvas.addEventListener(tapstart , function(e){ e.preventDefault(); x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft; y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;
  //鼠标第一次点下的时候擦除一个圆形区域,同时记录第一个坐标点 ctx.save() ctx.beginPath() ctx.arc(x1,y1,a,
0,2*Math.PI); ctx.clip() ctx.clearRect(0,0,canvas.width,canvas.height); ctx.restore(); canvas.addEventListener(tapmove , tapmoveHandler); canvas.addEventListener(tapend , function(){ canvas.removeEventListener(tapmove , tapmoveHandler); });
  //鼠标移动时触发该事件
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;
    //获取两个点之间的剪辑区域四个端点
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;
    //保证线条的连贯,所以在矩形一端画圆 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();
    //清除矩形剪辑区域里的像素 ctx.save() ctx.beginPath() ctx.moveTo(x3,y3); ctx.lineTo(x5,y5); ctx.lineTo(x6,y6); ctx.lineTo(x4,y4); ctx.closePath(); ctx.clip() ctx.clearRect(
0,0,canvas.width,canvas.height); ctx.restore();
    //记录最后坐标 x1
= x2; y1 = y2; } })

 

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

相关文章
网友点评