清除canvas画布内容--点擦除+线擦除
清空canvas画布内容
1、重置宽或高
由于canvas每当高度或宽度被重设时,画布内容就会被清空,因此可以用以下方法清空:(此方法仅限需要清除全部内容的情况)
var c=document.getElementById("myCanvas");
c.width=c.width;
2、clearRect
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(0,0,300,150);
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 | 使用异或操作对源图像与目标图像进行组合。 |
<!DOCTYPE html>
<html>
<head>
<style>
canvas
{
border:1px solid #d3d3d3;
margin-right:10px;
margin-bottom:20px;
}
</style>
</head>
<body> <script> var gco=new Array();
gco.push("source-atop");
gco.push("source-in");
gco.push("source-out");
gco.push("source-over");
gco.push("destination-atop");
gco.push("destination-in");
gco.push("destination-out");
gco.push("destination-over");
gco.push("lighter");
gco.push("copy");
gco.push("xor");
for (n=0;n<gco.length;n++)
{
document.write("<div id='p_" + n + "' style='float:left;'>" + gco[n] + ":<br>");
var c=document.createElement("canvas");
c.width=120;
c.height=100;
document.getElementById("p_" + n).appendChild(c);
var ctx=c.getContext("2d");
ctx.fillStyle="blue";
ctx.fillRect(10,10,50,50);
ctx.globalCompositeOperation=gco[n];
ctx.beginPath();
ctx.fillStyle="red";
ctx.arc(50,50,30,0,2*Math.PI);
ctx.fill();
document.write("</div>");
} </script> </body>
</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对象。

下面的一段代码,实现了绘制该线条到画布。使用二次贝塞尔函数使得绘制出来的线条流畅平滑没有折痕,当只有一个点时可绘制出一个圆点。
var count = this.points.length();
var p: Core.Point = this.points.get(0);
if (isDrawHit) {
ctx.strokeStyle = this.colorKey;
}
else {
ctx.strokeStyle = this.lineColor;
}
ctx.lineCap = "round";
ctx.lineJoin = 'round';//转折的时候不出现尖角
if (ctx.canvas.id == "hitCanvas")
ctx.lineWidth = this.lineWidth + eraserRadius;//扩大hit上线条的范围,橡皮半径
else
ctx.lineWidth = this.lineWidth;
ctx.beginPath();
if (count >= 2) {
ctx.moveTo(p.x, p.y);
for (var i = 1; i < count - 2; i++) {
// p = this.points.get(i);
// ctx.lineTo(p.x, p.y);
if (this.points.get(i).x == this.points.get(i + 1).x && this.points.get(i).y == this.points.get(i + 1).y)
continue;
var c = (this.points.get(i).x + this.points.get(i + 1).x) / 2;
var d = (this.points.get(i).y + this.points.get(i + 1).y) / 2;
ctx.quadraticCurveTo(this.points.get(i).x, this.points.get(i).y, c, d); //二次贝塞曲线函数
}
// For the last 2 points
if (count >= 3) {
ctx.quadraticCurveTo(
this.points.get(i).x,
this.points.get(i).y,
this.points.get(i + 1).x,
this.points.get(i + 1).y
);
} else if (count >= 2) {
ctx.lineTo(this.points.get(1).x, this.points.get(1).y);
}
ctx.stroke();
} else {
if (isDrawHit) {
ctx.fillStyle = this.colorKey;
}
else {
ctx.fillStyle = this.lineColor;
}
if (ctx.canvas.id == "hitCanvas")
var radius = this.lineWidth + eraserRadius;//扩大hit上线条的范围,橡皮半径
else
var radius = this.lineWidth;
ctx.arc(this.points.get(0).x, this.points.get(0).y, radius, 0, 2 * Math.PI);
ctx.fill();
}
其中绘制到hitCanvas上的时候将lineWidth扩大加上了eraserRadius(圆形橡皮擦半径),下图即为绘制到hitCanvas上的colorKey颜色线条,每个线条颜色值是上图中的key值colorKey。另外线条粗细明显比上面的白色线条要粗很多,因为橡皮擦是个cur鼠标样式它的半径很大,但获取的鼠标点击位置还只是一个像素点坐标,所以为了扩大鼠标点到线条上的范围将其变粗。

2. 线擦除和点擦除
这样线擦除就很容易实现,只需要找到橡皮擦点到画布上的坐标点的色值,就其从hash集合中根据colorKey删除掉该项,即实现了删除整条线。
点擦除就需要考虑到从两端擦除或者从中间擦除的情况:
if (that.isErasePoint) {
line.points.foreach(function (i, p) {
//橡皮擦距离该线条上点的距离是否在橡皮擦半径范围内
if (Math.pow(p.x - point.x, 2) + Math.pow(p.y - point.y, 2) <= Math.pow(eraserRadius, 2)) {
isSeparate = true;//已经找到橡皮擦半径范围内的点,该点不存入两个集合中的任何一个
} else {
if (isSeparate)//找到后将之后的点存入另一个点集合points2中
points2.add(p);
else//找到之前将点存入点集合points1中
points1.add(p);
}
})
//遍历完线条points上的所有点后。根据points1和points2是否为空处理点擦除后的线条
if (points1.length() >= 1 && points2.length() >= 1) {//points1和points2都不为空,说明从中间擦除变为两条线
var preLine = editor.commonEditLogic.clonePenLine(line);
line.points = points1;
var linePen = editor.bdCanvas.elementFactory.createPenLine(point, line.lineWidth, line.lineColor);
linePen.points = points2; editor.bdCanvas.activeElement.setPenLine(linePen.colorKey, linePen);
} else if (points1.length() == 0 && points2.length() >= 1) {//从一端擦除
line.points = points2;
} else if (points1.length() >= 1 && points2.length() == 0) {//从一端擦除
line.points = points1;
} else if (points1.length() == 0 && points2.length() == 0) {//线条上的点全部被擦除,删除该线条
editor.bdCanvas.activeElement.delPenLine(line.colorKey); }
editor.courseware.currentBlackboard.draw(false, true); }
清除canvas画布内容--点擦除+线擦除的更多相关文章
- 将canvas画布内容转化为图片(toDataURL(),创建url)
将canvas画布内容转化为图片(toDataURL(),创建url) 总结 1.现在的浏览器都支持右键另存为图片的方法来将canvas画布内容转化为图片 2.在代码里面可以通过toDataURL() ...
- canvas toDataURL() 方法如何生成部分画布内容的图片
HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI .可以使用 type参数其类型,默认为 PNG 格式.图片的分辨率为96dpi. 如果画布的高 ...
- html 5 canvas画布整理
1. 创建canvas画布<canvas id="myCanvas" width="800" height="800" >< ...
- 【读书笔记《Android游戏编程之从零开始》】12.游戏开发基础(Canvas 画布)
1.Canvas 画布 画布类 Canvas 封装了图形和图片绘制等内容,此类常用的函数说明如下: drawColor(int color) 作用:绘制颜色覆盖画布,常用于刷屏 参数:颜色值,也可用十 ...
- 关于canvas画布使用fillRect()时高度出现双倍效果解决办法
当设置canvas的宽度和高度时,只有内嵌css有效,外部css会出现拉伸的情况,例如: <!DOCTYPE html> <html lang="en"> ...
- 小程序开发-Canvas画布组件
Canvas画布 基本使用方法: 在wxml中添加canvas组件 <canvas canvas-id='canvasDemo' class='demo'></canvas> ...
- 《每周一点canvas动画》——3D点线与水波动画
<每周一点canvas动画>--差分函数的妙用 每周一点canvas动画代码文件 好像上次更新还是十一前,这唰唰唰的就过去大半个月了,现在才更新实在不好意思.这次我们不涉及canvas 3 ...
- 【HTML5】canvas画布练习
第一步:获取画布元素 var canvas = document.getElementById("myCanvas"); var context = canvas.getConte ...
- 关于使用Css设置Canvas画布大小的问题
问题分析 我们在调整画布大小时,希望画布中的图形保持不变,只是改变画布本身的大小.但是如果使用Css设置画布大小,则会出现问题. 问题描述 如果使用Css设置Canvas画布的大小,则导致画布按比例缩 ...
随机推荐
- 简述ref与out区别
1.相同点:两者都是按地址(引用)传递的,使用后都将改变原来参数的数值. 2.区别:ref可以把参数的数值传递进函数,但是out是要把参数清空(声明时不必显示初始化),就是说你无法把一个数值从out传 ...
- 关于logging的那些坑
python的logging日志记录模块非常强大,使用也很简单,但是特别容易出各种意外状况,打印各种出乎意料的log.最近对logging的一些原理进行了学习,再此做个记录,以备忘. 首先全面的了解一 ...
- opencv学习笔记2
import cv2 as cvimport numpy as np"""#图像加法运算 即像素加法 (结果图=图1+图二) (两个图像必须是等大等类型的)image = ...
- Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力)
Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力) 题目描述 如果一个数组1.至少三个元素2.两两之间差值相同,那么这个数组就是算术序列 比如下面的数组都是算 ...
- 12C GI + 11g DB 环境中PSU安装
环境说明: 12.1.0.2的GI集群,11.2.0.4的RAC数据库,需要安装最新的补丁. 补丁下载: 12.1.0.2 GI的PSU:11.2.0.4 DB的PSU:OJVM For 11.2.0 ...
- UML类图和时序图符号
看懂UML类图和时序图 https://www.cnblogs.com/me115/p/4092632.html 内容目录: 从一个示例开始 类之间的关系 时序图 附录:<图说设计模式> ...
- REST模式中HTTP请求方法(GET,POST,PUT,DELETE)
一直在测试REST模式的WEB SERVICE接口,客户端的HTTP的请求方式一般分为四种:GET.POST.PUT.DELETE,这四种请求方式有什么不同呢.简单的说,GET就是获取资源,POST就 ...
- Android 查看联系人电话和姓名(ContentProvider)
1.介绍 2.使用方法 3.在AndroidManifest.xml文件中添加相关设置 <uses-permission android:name="android.permissio ...
- c# 委托访问listbox多线程操作
c# 委托访问listbox多线程操作 using System;using System.Collections.Generic;using System.ComponentModel;using ...
- Codeforces Round #549 (Div. 2) Solution
传送门 A.The Doors 看懂题目就会写的题 给一个 $01$ 序列,找到最早的位置使得 $0$ 或 $1$ 已经全部出现 #include<iostream> #include&l ...