您现在的位置是:网站首页> 编程资料编程资料
用HTML5 实现橡皮擦的涂抹效果的教程Html5+JS实现手机摇一摇功能HTML5 Canvas的事件处理介绍HTML5 audio标签使用js进行播放控制实例
2021-08-31
1096人已围观
简介 这篇文章主要介绍了用HTML5 实现橡皮擦的涂抹效果的教程,主要还是依赖于Canvas API来进行绘图,需要的朋友可以参考下
最近项目刚好用到这种效果,也就是有点像刮刮卡一样,在移动设备上,把某张图片刮掉显示出另一张图片。效果图如下:
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把两点之间连接起来再绘制,但是擦除效果中的剪辑区域要求要是闭合路径,如果是单纯的把两个点连起来就无法形成剪辑区域了。然后我就想到用计算的方法,算出两个擦除区域中的矩形四个端点坐标来实现,也就是下图中的红色矩形:
计算方法也很简单,因为可以知道两个剪辑区域连线两个端点的坐标,又知道我们要多宽的线条,矩形的四个端点坐标就变得容易求了,所以就有了下面的代码:
XML/HTML Code复制内容到剪贴板
- var aasin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)));
- var aacos = 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就是两个端点,从而求出了四个端点的坐标。这样一来,剪辑区域就是圈加矩形,代码组织起来就是:
XML/HTML Code复制内容到剪贴板
- 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 aasin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)));
- var aacos = 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;
- }
- })
如此一来,鼠标擦除的效果就实现了,不过还有一个要实现的点,就是大部分擦除的效果,当你擦了一定数量的像素后,就会自动把所有图片内容呈现出来,这个效果,我是用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个像素检查一次,修改后的代码如下:
复制代码
相关内容
- 用HTML5中的Canvas结合公式绘制粒子运动的教程详解使用HTML5 Canvas创建动态粒子网格动画Html5 canvas实现粒子时钟的示例代码
- 使用分层画布来优化HTML5渲染的教程html5 分层屏幕适配的方法Html分层的box-shadow效果的示例代码
- 简单介绍HTML5中的文件导入jQuery+HTML5实现的页面整屏滑动切换效果源码html5实现的网格布局动画加载并打开内容特效源码html5实现的可拖拽图片循环滚动切换特效源码
- HTML5实现获取地理位置信息并定位功能HTML5地理定位_动力节点Java学院整理HTML5地理定位实例简单html5代码获取地理位置h5实现获取用户地理定位的实例代码
- HTML5 canvas标签实现刮刮卡效果Html5新特性用canvas标签画多条直线附效果截图HTML5 Canvas标签使用收录详解HTML5 Canvas标签及基本使用
- HTML5 DeviceOrientation实现手机网站摇一摇功能代码实例Html5+JS实现手机摇一摇功能html5摇一摇代码优化包括DeviceMotionEvent等等html5 利用重力感应实现摇一摇换颜色可用来做抽奖等等用HTML5实现手机摇一摇的功能的教程基于html5 DeviceOrientation 实现微信摇一摇功能
- Html5+JS实现手机摇一摇功能HTML5 DeviceOrientation实现手机网站摇一摇功能代码实例html5摇一摇代码优化包括DeviceMotionEvent等等html5 利用重力感应实现摇一摇换颜色可用来做抽奖等等用HTML5实现手机摇一摇的功能的教程基于html5 DeviceOrientation 实现微信摇一摇功能
- HTML5 Canvas的事件处理介绍如何在Canvas上的图形/图像绑定事件监听的实现如何在Canvas中添加事件的方法示例html5中监听canvas内部元素点击事件的三种方法详解Canvas事件绑定一个不错的HTML5 Canvas多层点击事件监听实例HTML5 Canvas鼠标与键盘事件demo示例详解如何在Canvas中添加事件的方法
- HTML5全屏(Fullscreen)API详细介绍html5实现点击弹出图片功能html5 录制mp3音频支持采样率和比特率设置html5表单的required属性使用html5调用摄像头实例代码HTML5页面音频自动播放的实现方式Html5大屏数据可视化开发的实现html实现弹窗的实例HTML5来实现本地文件读取和写入的实现方法HTML 罗盘式时钟的实现HTML5简单实现添加背景音乐的几种方法
- 详解HTML5中ol标签的用法HTML与XHTML、以及HTML4与HTML5标签之间的区别简介简单介绍HTML5中audio标签的使用详解HTML5中的<template>标签HTML5 video标签(播放器)学习笔记(二):播放控制HTML5 Video标签的属性、方法和事件汇总介绍HTML5中新标签和常用标签详解HTML5语音识别标签写法附图html5 video标签屏蔽右键视频另存为的js代码HTML5标签使用方法详解
点击排行
本栏推荐
