清除canvas画布内容--点擦除+线擦除

清空canvas画布内容

1、重置宽或高

由于canvas每当高度或宽度被重设时,画布内容就会被清空,因此可以用以下方法清空:(此方法仅限需要清除全部内容的情况)

var c=document.getElementById("myCanvas");  
c.width=c.width;

 

2、clearRect

1 var c=document.getElementById("myCanvas");
2 var ctx=c.getContext("2d");
3 ctx.fillStyle="red";
4 ctx.fillRect(0,0,300,150);
5 ctx.clearRect(20,20,100,50);

3、globalCompositeOperation

引用globalCompositeOperation()函数,这个函数是用来在画布上组合颜色,我们可以利用这个原理,叠加(数学上的"或"原理)来制作橡皮。

首先看看 globalCompositeOperation属性可以设置的值有哪些,分别是什么效果:

描述
source-over默认。在目标图像上显示源图像。
source-atop在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-in在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
source-out在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
destination-over在源图像上方显示目标图像。
destination-atop在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
destination-out在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
lighter显示源图像 + 目标图像。
copy显示源图像。忽略目标图像。
xor使用异或操作对源图像与目标图像进行组合。
 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4 <style>
 5 canvas
 6 {
 7 border:1px solid #d3d3d3;
 8 margin-right:10px;
 9 margin-bottom:20px;    
10 }
11 </style>
12 </head>
13 <body>
14 
15 <script>
16 
17 var gco=new Array();
18 gco.push("source-atop");
19 gco.push("source-in");
20 gco.push("source-out");
21 gco.push("source-over");
22 gco.push("destination-atop");
23 gco.push("destination-in");
24 gco.push("destination-out");
25 gco.push("destination-over");
26 gco.push("lighter");
27 gco.push("copy");
28 gco.push("xor");
29 for (n=0;n<gco.length;n++)
30     {
31     document.write("<div id='p_" + n + "' style='float:left;'>" + gco[n] + ":<br>");
32     var c=document.createElement("canvas");
33     c.width=120;
34     c.height=100;
35     document.getElementById("p_" + n).appendChild(c);
36     var ctx=c.getContext("2d");    
37     ctx.fillStyle="blue";
38     ctx.fillRect(10,10,50,50);
39     ctx.globalCompositeOperation=gco[n];
40     ctx.beginPath();
41     ctx.fillStyle="red";
42     ctx.arc(50,50,30,0,2*Math.PI);
43     ctx.fill();
44     document.write("</div>");    
45     }
46 
47 </script>
48 
49 </body>
50 </html>

可以看出如果设置成destination-out,就可以清除canvas现有的像素点的图像。


 

清除绘制到画布上的线条(点擦除,线擦除)

  在我最近实现的项目中有画笔功能, 同时画笔画出的线条可以被橡皮擦擦除,有点擦除和线擦除两种方式。

  使用以上两种方法也可以,但是如果这些线条不止绘制一次的话呢,中间有其他操作(例如绘制的内容变换一次后)那上面的方法就不容易做到了,因为要反复绘制存储每次擦除后的数据,简单的为了能达到该目的,可以将整个canvas画布转化成base64编码的image,后面再次绘制的时候把这个image数据再绘制到canvas上,可以继续在这个canvas上进行绘制和擦除内容。但是怎么样也不好做到线擦除的功能了!

  下面介绍另外一种存储绘制路径点坐标的方法去实现绘制线条后的点擦除和线擦除的功能。

  首先介绍下存储线条的数据结构,之前写的一篇《js实现存储对象的数据结构hashTable和list》大家可以先大致看看hash结构的实现,但是key和value快速查找的优势需要清楚。另外在canvas画的各种形状和线条,我们是如何知道点击到哪个元素哪条线?《软件项目技术点(4)——实现点击画布上元素》这篇博客里有说明实现原理。

1. 线条存储及绘制

项目中我存储的线条hash结构的对象如下:

展开第一个线条key值为“#8c471a”的具体信息如下,value值其中有colorKey,lineColor,lineWidth,以及最重要的List结构的points对象,是一个存储了该线条所有点坐标集合的List对象。

下面的一段代码,实现了绘制该线条到画布。使用二次贝塞尔函数使得绘制出来的线条流畅平滑没有折痕,当只有一个点时可绘制出一个圆点。

 1                 var count = this.points.length();
 2                 var p: Core.Point = this.points.get(0);
 3                 if (isDrawHit) {
 4                     ctx.strokeStyle = this.colorKey;
 5                 }
 6                 else {
 7                     ctx.strokeStyle = this.lineColor;
 8                 }
 9                 ctx.lineCap = "round";
10                 ctx.lineJoin = 'round';//转折的时候不出现尖角
11                 if (ctx.canvas.id == "hitCanvas")
12                     ctx.lineWidth = this.lineWidth + eraserRadius;//扩大hit上线条的范围,橡皮半径
13                 else
14                     ctx.lineWidth = this.lineWidth;
15                 ctx.beginPath();
16                 if (count >= 2) {
17                     ctx.moveTo(p.x, p.y);
18                     for (var i = 1; i < count - 2; i++) {
19                         // p = this.points.get(i);
20                         // ctx.lineTo(p.x, p.y);
21                         if (this.points.get(i).x == this.points.get(i + 1).x && this.points.get(i).y == this.points.get(i + 1).y)
22                             continue;
23                         var c = (this.points.get(i).x + this.points.get(i + 1).x) / 2;
24                         var d = (this.points.get(i).y + this.points.get(i + 1).y) / 2;
25                         ctx.quadraticCurveTo(this.points.get(i).x, this.points.get(i).y, c, d); //二次贝塞曲线函数   
26                     }
27                     // For the last 2 points
28                     if (count >= 3) {
29                         ctx.quadraticCurveTo(
30                             this.points.get(i).x,
31                             this.points.get(i).y,
32                             this.points.get(i + 1).x,
33                             this.points.get(i + 1).y
34                         );
35                     } else if (count >= 2) {
36                         ctx.lineTo(this.points.get(1).x, this.points.get(1).y);
37                     }
38                     ctx.stroke();
39                 } else {
40                     if (isDrawHit) {
41                         ctx.fillStyle = this.colorKey;
42                     }
43                     else {
44                         ctx.fillStyle = this.lineColor;
45                     }
46                     if (ctx.canvas.id == "hitCanvas")
47                         var radius = this.lineWidth + eraserRadius;//扩大hit上线条的范围,橡皮半径
48                     else
49                         var radius = this.lineWidth;
50                     ctx.arc(this.points.get(0).x, this.points.get(0).y, radius, 0, 2 * Math.PI);
51                     ctx.fill();
52                 }
53              
View Code

 

其中绘制到hitCanvas上的时候将lineWidth扩大加上了eraserRadius(圆形橡皮擦半径),下图即为绘制到hitCanvas上的colorKey颜色线条,每个线条颜色值是上图中的key值colorKey。另外线条粗细明显比上面的白色线条要粗很多,因为橡皮擦是个cur鼠标样式它的半径很大,但获取的鼠标点击位置还只是一个像素点坐标,所以为了扩大鼠标点到线条上的范围将其变粗。

 

2. 线擦除和点擦除

这样线擦除就很容易实现,只需要找到橡皮擦点到画布上的坐标点的色值,就其从hash集合中根据colorKey删除掉该项,即实现了删除整条线。

点擦除就需要考虑到从两端擦除或者从中间擦除的情况:

 1         if (that.isErasePoint) {
 2                     line.points.foreach(function (i, p) {
 3                         //橡皮擦距离该线条上点的距离是否在橡皮擦半径范围内
 4                         if (Math.pow(p.x - point.x, 2) + Math.pow(p.y - point.y, 2) <= Math.pow(eraserRadius, 2)) {
 5                             isSeparate = true;//已经找到橡皮擦半径范围内的点,该点不存入两个集合中的任何一个
 6                         } else {
 7                             if (isSeparate)//找到后将之后的点存入另一个点集合points2中
 8                                 points2.add(p);
 9                             else//找到之前将点存入点集合points1中
10                                 points1.add(p);
11                         }
12                     })
13                     //遍历完线条points上的所有点后。根据points1和points2是否为空处理点擦除后的线条
14                     if (points1.length() >= 1 && points2.length() >= 1) {//points1和points2都不为空,说明从中间擦除变为两条线
15                         var preLine = editor.commonEditLogic.clonePenLine(line);
16                         line.points = points1;
17                         var linePen = editor.bdCanvas.elementFactory.createPenLine(point, line.lineWidth, line.lineColor);
18                         linePen.points = points2;                                   editor.bdCanvas.activeElement.setPenLine(linePen.colorKey, linePen);
19                     } else if (points1.length() == 0 && points2.length() >= 1) {//从一端擦除
20                         line.points = points2;
21                     } else if (points1.length() >= 1 && points2.length() == 0) {//从一端擦除
22                         line.points = points1;
23                     } else if (points1.length() == 0 && points2.length() == 0) {//线条上的点全部被擦除,删除该线条
24                             editor.bdCanvas.activeElement.delPenLine(line.colorKey);26                     }
27                     editor.courseware.currentBlackboard.draw(false, true);30                 } 

 

要实现 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` 需要替换为你的背景图像路径。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值