You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

纯Vanilla JS实现Canvas单图形删除:保留指定图形并移除目标图形的技术问询

嘿,我明白你遇到的Canvas难题了——既要让红色光标流畅跟随鼠标,又要保留绘制的蓝色图形,还要能单独删除它们对吧?咱们不用第三方库,纯Vanilla JS就能搞定,核心思路是用数组管理所有绘制的图形,每帧清空画布后重新渲染所有元素,这样就能解决你说的两个问题,同时实现单个图形删除功能。

问题根源分析

你之前的两个问题本质上是同一个原因:没有对已绘制的图形进行持久化管理:

  • 清画布时没重新绘制已有的蓝色图形,导致它们被清除
  • 不清画布时,红色光标每次移动都重新绘制,留下拖影

完整解决方案代码

先给你看修复后的完整代码,我会一步步解释关键改动:

<canvas id="canvas-pl-c-canvas"></canvas>
*{
 margin: 0;
 padding: 0;
 box-sizing: border-box;
}
#canvas-pl-c-canvas:hover{
 cursor: none;
}
const canvas = document.getElementById('canvas-pl-c-canvas');
const c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 定义图形类,保持你的原有逻辑
class Shape {
 constructor(x, y, radius, color) {
 this.x = x;
 this.y = y;
 this.radius = radius;
 this.color = color;
 }
 draw() {
 c.beginPath();
 c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
 c.fillStyle = this.color;
 c.fill();
 }
 update(nx, ny) {
 this.x = nx;
 this.y = ny;
 }
}

// 初始化红色光标
const x = canvas.width / 2;
const y = canvas.height / 2;
const cursor = new Shape(x, y, 10,'red');

// 用数组存储所有绘制的蓝色图形
let shapes = [];
let isDrawing = false;

// 统一渲染函数:清空画布 → 绘制所有蓝色图形 → 绘制红色光标
function render() {
 c.clearRect(0, 0, canvas.width, canvas.height);
 // 遍历数组绘制所有蓝色图形
 shapes.forEach(shape => shape.draw());
 // 绘制红色光标
 cursor.draw();
}

// 鼠标移动事件:更新光标位置,绘制时添加新图形
addEventListener('mousemove', (e) => {
 cursor.update(e.clientX, e.clientY);
 if(isDrawing){
 // 按住左键时,创建新蓝色图形并加入数组
 const newShape = new Shape(e.clientX, e.clientY, 10, 'blue');
 shapes.push(newShape);
 }
 // 每次移动都重新渲染
 render();
})

// 鼠标按键事件:控制绘制状态
canvas.addEventListener('mouseup', () => {
 isDrawing = false;
})
canvas.addEventListener('mousedown', () => {
 isDrawing = true;
})

// 右键删除单个图形:判断点击位置与图形的距离
canvas.addEventListener('contextmenu', (e) => {
 e.preventDefault(); // 阻止默认右键菜单
 const clickX = e.clientX;
 const clickY = e.clientY;
 // 过滤数组:移除距离点击位置小于半径的图形
 shapes = shapes.filter(shape => {
 const distance = Math.sqrt(Math.pow(clickX - shape.x, 2) + Math.pow(clickY - shape.y, 2));
 return distance > shape.radius;
 });
 // 删除后重新渲染
 render();
})

关键改动解释

  1. 图形数组管理:

    • 新增shapes数组来存储所有绘制的蓝色图形,这样每帧渲染时可以重新绘制它们,解决清画布丢失图形的问题
    • 把原来的Player类改名为Shape,更贴合它的用途
  2. 统一渲染函数:

    • 写了render函数,负责清空画布、绘制所有蓝色图形、绘制红色光标,这样所有需要刷新画布的场景都可以调用它,避免重复代码
  3. 修复光标拖影:

    • 每次鼠标移动都调用render函数,先清空画布再重新绘制所有元素,红色光标就不会留下拖影了
  4. 单个图形删除功能:

    • 监听右键点击事件,阻止默认菜单弹出
    • 计算点击位置和每个蓝色图形的距离(用勾股定理),如果距离大于图形半径,就保留这个图形,否则移除
    • 过滤后的数组重新赋值给shapes,然后调用render刷新画布,实现单个图形删除

额外优化建议

  • 可以调整蓝色图形的半径(我改成了10,和红色光标一致,你可以改回300)
  • 如果需要删除特定图形,还可以给每个Shape实例加唯一ID,通过ID精准删除
  • 可以添加鼠标按下时的初始绘制,避免移动才开始画

这样你的需求就都满足了:红色光标流畅跟随,按住左键绘制蓝色图形,右键点击单个蓝色图形就能删除,而且不会影响其他图形~

内容的提问来源于stack exchange,提问作者user16018534

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 03:12:47