简言
canvas实现了快速绘制矩形的方法。
clearRect
CanvasRenderingContext2D.clearRect() 是 Canvas 2D API 的方法,这个方法通过把像素设置为透明以达到擦除一个矩形区域的目的。
请确保在调用 clearRect()之后绘制新内容前调用beginPath() 。
语法:
void ctx.clearRect(x, y, width, height);
参数:
- x — 矩形起点的 x 轴坐标。
- y — 矩形起点的 y 轴坐标。
- width — 矩形的宽度。
- height — 矩形的高度。
clearRect() 方法在一个矩形区域内设置所有像素都是透明的 (rgba(0,0,0,0))。这个矩形范围的左上角在 (x, y),宽度和高度分别由 width 和height确定。
示例 清除画布
这段代码清除整个画布。这段代码通常在动画的每一帧开始被执行。清除的范围涵覆盖了整个 <canvas> 元素。
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
fillRect
CanvasRenderingContext2D.fillRect() 是 Canvas 2D API 绘制填充矩形的方法。当前渲染上下文中的fillStyle 属性决定了对这个矩形对的填充样式。
这个方法是直接在画布上绘制填充,并不修改当前路径,所以在这个方法后面调用 fill() 或者stroke()方法并不会对这个方法有什么影响。
语法:
void ctx.fillRect(x, y, width, height);
fillRect()方法绘制一个填充了内容的矩形,这个矩形的开始点(左上点)在(x, y) ,它的宽度和高度分别由width 和 height 确定,填充样式由当前的fillStyle 决定。
参数:
- x — 矩形起始点的 x 轴坐标。
- y — 矩形起始点的 y 轴坐标。
- width — 矩形的宽度。
- height — 矩形的高度。
示例
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(20, 10, 150, 100);
strokeRect
CanvasRenderingContext2D.strokeRect() 是 Canvas 2D API 在 canvas 中,使用当前的绘画样式,描绘一个起点在 (x, y)、宽度为 w、高度为 h 的矩形的方法。
此方法直接绘制到画布而不修改当前路径,因此任何后续fill() 或stroke()调用对它没有影响。
语法:
void ctx.strokeRect(x, y, width, height);
strokeRect()方法绘制一个描边矩形,其起点为(x, y) ,其大小由宽度和高度指定。
参数:
-
x — 矩形起点的 x 轴坐标。
-
y — 矩形起点的 y 轴坐标。
-
width — 矩形的宽度。正值在右侧,负值在左侧。
-
height — 矩形的高度。正值在下,负值在上。
示例
矩形的左上角是(20,10)。它的宽度为 160,高度为 100。
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "green";
ctx.strokeRect(20, 10, 160, 100);
示例:快速绘制矩形
在vue中使用快速绘制矩形方法,思路是在确定绘制后将绘制信息保存下来,绘制移动时更新辅助绘制线段矩形和恢复以前绘制的图形:
type DrawType =
| 'line'
| 'triangle'
| 'rect'
| 'polygon'
| 'rectFill'
| 'rectStroke'
| 'rectClear';
interface HistoryRecord {
name: string;
type: DrawType;
path: number[][];
}
const historyRecord: HistoryRecord[] = reactive([]);
const fastRenderValue = ref('');
const fastRenderValueChange = () => {};
let startX = 0,
startY = 0,
endX = 0,
endY = 0;
let isDraw = false; // 是否是在绘制
onMounted(() => {
canvasDom.value?.addEventListener('mousedown', mouseDown);
canvasDom.value?.addEventListener('mousemove', canvasMove);
canvasDom.value?.addEventListener('mouseup', mouseUp);
});
onUnmounted(() => {
canvasDom.value?.removeEventListener('mousedown', mouseDown);
canvasDom.value?.removeEventListener('mousemove', canvasMove);
canvasDom.value?.removeEventListener('mouseup', mouseUp);
});
// 按下
const mouseDown = (e: MouseEvent) => {
const ctx = canvasDom.value?.getContext('2d');
if (!ctx || fastRenderValue.value === '') return;
startX = e.offsetX;
startY = e.offsetY;
isDraw = true;
};
// 移动
const canvasMove = (e: MouseEvent) => {
const ctx = canvasDom.value?.getContext('2d');
if (!ctx || fastRenderValue.value === '' || !isDraw) return;
if (ctx.isPointInStroke(e.offsetX, e.offsetY)) {
}
// 更新画布
updateCanvas();
// 绘制提示区域
ctx.save();
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.setLineDash([2, 4]);
ctx.strokeRect(startX, startY, e.offsetX - startX, e.offsetY - startY);
ctx.restore();
// 恢复以前的内容
};
// 抬起
const mouseUp = (e: MouseEvent) => {
const ctx = canvasDom.value?.getContext('2d');
if (!ctx || fastRenderValue.value === '' || !isDraw) return;
endX = e.offsetX;
endY = e.offsetY;
fastDrawRect(
ctx,
[
[startX, startY],
[endX, endY],
],
fastRenderValue.value,
);
isDraw = false;
};
// 快速绘制
function fastDrawRect(
ctx: CanvasRenderingContext2D,
path: number[][] = [
[startX, startY],
[endX, endY],
],
type: string,
record = true,
) {
let name = '';
let str: DrawType = 'rectFill';
switch (type) {
case 'rectFill':
ctx.fillRect(path[0][0], path[0][1], path[1][0] - path[0][0], path[1][1] - path[0][1]);
name = '快速绘制填充矩形';
str = 'rectFill';
break;
case 'rectStroke':
ctx.strokeRect(path[0][0], path[0][1], path[1][0] - path[0][0], path[1][1] - path[0][1]);
name = '快速绘制描边矩形';
str = 'rectStroke';
break;
case 'rectClear':
ctx.clearRect(path[0][0], path[0][1], path[1][0] - path[0][0], path[1][1] - path[0][1]);
name = '快速清除矩形区域';
str = 'rectClear';
break;
default:
ctx.strokeRect(path[0][0], path[0][1], path[1][0] - path[0][0], path[1][1] - path[0][1]);
break;
}
if (record) {
historyRecord.push({
name: name,
type: str,
path: [
[startX, startY],
[endX, endY],
],
});
}
}
// 更新画布
function updateCanvas() {
const ctx = canvasDom.value?.getContext('2d');
if (!ctx || !canvasDom.value) return;
ctx.clearRect(0, 0, canvasDom.value.width, canvasDom.value.height);
for (let i = 0; i < historyRecord.length; i++) {
const { name, type, path } = historyRecord[i];
switch (type) {
case 'line':
case 'rect':
case 'polygon':
case 'triangle':
drawPath(ctx, path, ['rect', 'triangle', 'polygon'].includes(type));
break;
case 'rectFill':
case 'rectStroke':
case 'rectClear':
fastDrawRect(ctx, path, type, false);
default:
break;
}
}
}
结语
结束了。