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

HTML Canvas合成:鼠标移动擦除上层画布显露下层图片

实现方案

你只需要修改现有JS代码补充擦除逻辑、修正坐标计算即可,完整可运行的修改代码如下:

1. 核心实现逻辑说明

  • 用canvas的globalCompositeOperation = 'destination-out'合成模式,实现画新内容时擦除上层画布已有白色遮罩的效果
  • 新增全局配置项,可直接调整擦除的形状和尺寸
  • 修正鼠标坐标计算:原clientX/Y是相对于浏览器视口的坐标,需要减去canvas元素的视口偏移,才能得到画布内的正确坐标
  • 将上层画布上下文等公共变量挂载到window对象,方便跨函数调用

2. 修改后的完整JavaScript代码

// 擦除配置项,可自定义修改
const eraseConfig = {
  shape: 'circle', // 可选值 circle 圆形 / square 方形
  size: 20 // 擦除的尺寸,单位像素
}

window.onload = function() {
    //Create Bottom canvas & context
    var canvas = document.getElementById('canvas');
    var ctxB = canvas.getContext('2d');
    
    //Create Top canvas & context
    var canvas2 = document.getElementById('canvas2');
    // 挂载到window,方便外部函数调用
    window.ctxT = canvas2.getContext('2d');
    window.canvas2 = canvas2;

    //Set waterfall image variable
    var waterfall = document.getElementById('waterfall');

    //Set canvas w&h properties
    canvas.width = canvas2.width = waterfall.width;
    canvas.height = canvas2.height = waterfall.height;

    //Populate Bottom canvas with image
    ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);

    //Populate Top canvas with white rectangle
    ctxT.fillStyle = "white";
    ctxT.fillRect(0, 0, canvas2.width, canvas2.height);
}
        
//Show Coordinates of mouse on Top canvas
function HandleMouseMove(event) {
    // 计算canvas在视口的偏移,得到画布内的正确坐标
    const rect = window.canvas2.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    // 显示坐标
    var coords = x.toFixed(0) + ", " + y.toFixed(0);
    document.getElementById("demo").innerHTML = coords;  

    // 擦除逻辑
    const ctx = window.ctxT;
    ctx.save();
    // 设置合成模式为擦除已有内容
    ctx.globalCompositeOperation = 'destination-out';

    if(eraseConfig.shape === 'circle') {
      // 画圆形擦除区域
      ctx.beginPath();
      ctx.arc(x, y, eraseConfig.size/2, 0, Math.PI * 2);
      ctx.fill();
    } else if(eraseConfig.shape === 'square') {
      // 画方形擦除区域
      ctx.fillRect(x - eraseConfig.size/2, y - eraseConfig.size/2, eraseConfig.size, eraseConfig.size);
    }

    ctx.restore();
}

3. 可选优化(按需开启)

如果需要实现「按住鼠标左键拖动才擦除,悬停不擦除」的交互,只需加个状态控制即可:

// 新增全局变量
let isDragging = false;

// window.onload里补充绑定事件
window.onload = function() {
  // ...原有逻辑不变
  canvas2.addEventListener('mousedown', () => isDragging = true);
  canvas2.addEventListener('mouseup', () => isDragging = false);
  canvas2.addEventListener('mouseleave', () => isDragging = false);
}

// HandleMouseMove里的擦除逻辑加判断
function HandleMouseMove(event) {
  // ...原有坐标计算逻辑不变
  if(!isDragging) return; // 没按住鼠标就不执行擦除
  // ...原有擦除逻辑不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:36:04