canvas实现的擦除效果

嗯,好久没有写博客了,因为较长一段时间发生了点点变故:楼主从传统IT项目(OA)跳到了移动端,主要搞微信上的web开发,也是学习了很长一段时间。

言归正传,微信上常见的手指滑动扣个圈圈,然后显示底层图片的应用相信大家也见过不少了。包括微信自身之前也出过付款看图片的应用,也是分分钟刷爆朋友圈。这里,楼主分两个模块从技术上讲解该功能,知道怎么做的可以直接跳过第一部分。

firstBlood,clip的应用。

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContent('2d');

ctx.save();                                  //先保存环境
ctx.beginPath();                             //开始路径
ctx.arc(320, winH/2, 80, 0, Math.PI * 2, true);     //根据一个坐标点,绘制一个半径为80的圆
ctx.closePath();                             //关闭路径
ctx.clip();                                  //创建一个裁切路径
ctx.clearRect(0, 0, 640, winH);              //清除整个画布,由于之前已经clip过了,实际上只清除了圆的范围
ctx.restore();                               //还原环境

通过这样一个操作,我们就可以在画布上口出一个半径为80的圆了。效果如下图:

然后结合到各种touch事件,就可以做出擦除效果了,十分简单。

secondBlood,PS画笔工具

那么在该需求上做一下 衍生,PS的画笔工具相信大家也都用过,和前面的最大区别就在于圆的边缘会有一些模糊的效果。如果,需求到这里的话大可以通过canvas的createRadialGradient方法做一个渐变效果实现。接下来大家都懂的,需求远远不会那么简单,既然是做擦除效果,那么当两个圆相交的时候单凭渐变是无法实现该功能的。这个时候,canvas的像素操作技术就该登场咯,let go!

以单次擦除范围为85像素的圆为准,思路如下:

1,先扣除一个半径为55像素的小圆,参照 firstBlood的方法

2,从55像素到85像素,做30次半径累加循环,每次循环都计算出 当前圆心和累加半径所构成的点,并依次增加点的透明度(这里每次循环透明度增加0.033)

具体代码如下:

function renderCanvas(){
   var empty = r - 30, curR, x = currentPos.x, y = currentPos.y, imgData, data, i, j, x1, y1, tempVal;
   ctx.save();
   ctx.beginPath();
   ctx.arc(x, y, empty, 0, Math.PI * 2, true);
   ctx.closePath();
   ctx.clip();
   ctx.clearRect(0, 0, 640, winH);
   ctx.restore();
   
   //清除了小圆后,获取整个canvas的像素点		
   imgData = ctxTwo.getImageData(0, 0, 640, winH);
   //存储像素点 颜色值的一维数组
   data = imgData.data;
   for(i = 0; i < 30; i++) {
     curR = empty + i;
     for(j = 0; j < 361; j++) {
        //x1, y1代表当前半径上圆的点坐标
	x1 = parseInt(x + curR * Math.cos(j * Math.PI / 180));
	y1 = parseInt(y + curR * Math.sin(j * Math.PI / 180));
	//出范围了就继续				
	if(x1 < 0 || y1 < 0 || x1 > 640 || y1 > winH) continue;
        //计算出一维数组中,当前点透明度的键值
	curPoint = (y1 - 1) * 640 * 4 + x1 * 4 + 3;
	//如果透明度已经是0了就不做处理				
	if(0 == data[curPoint]) continue;
        //根据循环的半径做透明度降低处理
	tempVal = 255 * (i * 0.033);
        //如果计算出的透明度 高于当前的透明度就不做处理。
	if(tempVal < data[curPoint]) data[curPoint]  = tempVal;
     }
   }
   //清楚整个画布
   ctx.clearRect(0, 0, 640, winH);
   //将处理过的像素值 在canvas上重绘
   ctx.putImageData(imgData, 0, 0);		
}

效果如下:

仔细看的话,会发现边缘会有模糊,当然这个范围可以增大 让其更明显。

今天早上发现 android手机上也还是比较流畅特别是 锤子1手机,还是比较满意 O(∩_∩)O~

关于像素点的计算,科普一下

imgData = ctxTwo.getImageData(0, 0, 640, winH);

imgData有一个名为data的一维数组 属性,以640 * 1008大小的canvas为例,

其数组的长度为 640 * 1008 * 4,我们知道rgba的值为4位,前三位表示其rgba的值,第四位为其透明度的值,取值范围是0--255,

我们反复强调data是一维数组,以第一个点为例,

data[0],表示rgba的第一位

data[1],表示rgba的第二位

data[2],表示rgba的第三位

data[3],表示其颜色的透明度

 

如果我们要知道 230 * 150 这个点的颜色值的话,其在data里面的开始键值为:

key = 229 * 640 * 4 + 150 * 4;

那么对应的颜色值表示依次为

data[key],表示rgba的第一位

data[key + 1],表示rgba的第二位

data[key + 2],表示rgba的第三位

data[3 + 3],表示其颜色的透明度

最后推荐一个canvas api手册网址:

https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API

相关术语以及专业的解释,案例都可以看到,谢谢!

转载于:https://my.oschina.net/firstblood/blog/675666

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现 Canvas 图像的擦除和修补功能,你可以使用以下方法: 图像擦: 1. 使用 `globalCompositeOperation` 属性:将 `globalCompositeOperation` 属性设置为 `"destination-out"`,这将使绘制的内容被擦除掉。 ```javascript context.globalCompositeOperation = "destination-out"; ``` 然后使用鼠标或触摸事件监听器来绘制,这将以擦除的方式删除画布上的内容。 图像修补: 1. 使用保存的原始图像进行修补:在擦除部分之后,将保存的原始图像重新绘制在擦除的位置上。 下面是一个简单的示例代码,演示了如何实现图像的擦除和修补: ```html <canvas id="myCanvas" width="400" height="400"></canvas> <button onclick="erase()">擦除</button> <button onclick="repair()">修补</button> <script> const canvas = document.getElementById("myCanvas"); const context = canvas.getContext("2d"); let isErasing = false; let backgroundImage = new Image(); let originalImage = null; // 加载背景图像 backgroundImage.src = "path_to_image.jpg"; // 替换为你的背景图像路径 backgroundImage.onload = function () { context.drawImage(backgroundImage, 0, 0); originalImage = context.getImageData(0, 0, canvas.width, canvas.height); }; canvas.addEventListener("mousedown", startDrawing); canvas.addEventListener("mousemove", draw); canvas.addEventListener("mouseup", stopDrawing); canvas.addEventListener("mouseout", stopDrawing); function startDrawing(e) { isErasing = true; context.beginPath(); context.moveTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); } function draw(e) { if (!isErasing) return; context.lineTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); context.stroke(); } function stopDrawing() { isErasing = false; } function erase() { context.globalCompositeOperation = "destination-out"; } function repair() { context.globalCompositeOperation = "source-over"; context.putImageData(originalImage, 0, 0); } </script> ``` 在上述示例中,当你按下鼠标按钮并移动鼠标时会出现擦除效果,松开鼠标按钮后,你可以继续使用画笔进行绘制。要擦除画布上的内容,可以点击 "擦除" 按钮来调用 `erase()` 函数,要修补图像,可以点击 "修补" 按钮来调用 `repair()` 函数。当点击修补按钮时,原始图像会重新绘制在画布上,覆盖掉之前擦除的内容。请注意,`path_to_image.jpg` 需要替换为你的背景图像路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值