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

Konva.JS图层相减实现:如何用鼠标擦除/显示指定图层

解决方案:实现图层擦除/恢复功能

要实现左键擦除normalLayer显示底层、右键恢复normalLayer的效果,核心是利用图层合成模式和遮罩层的思路,调整图层结构与绘制逻辑:

关键修改思路

  1. 新增一个全屏白色的遮罩层drawingLayer,作为normalLayer的显示控制层
  2. 设置normalLayer的合成模式为source-in,使其仅显示与drawingLayer重叠的区域
  3. 在drawingLayer上绘制:
    • 左键用destination-out模式擦除白色区域,让normalLayer对应位置消失,露出底层的redFilterLayer
    • 右键用source-over模式绘制白色区域,恢复normalLayer的显示

修改后的完整代码

function initializeKonva() {
  let container = document.querySelector('#MagicContainerCanvas');
  if (!container) {
    console.error('Container #MagicContainerCanvas not found');
    return;
  }

  let containerWidth = container.offsetWidth;
  let containerHeight = container.offsetHeight;

  let stage = new Konva.Stage({
    container: container,
    width: containerWidth,
    height: containerHeight
  });

  // 底层:红色滤镜图层
  let redFilterLayer = new Konva.Layer();
  stage.add(redFilterLayer);

  // 中间层:遮罩控制层,默认全屏白色,让normalLayer完全显示
  let drawingLayer = new Konva.Layer();
  stage.add(drawingLayer);
  // 添加全屏白色矩形作为初始遮罩
  let maskRect = new Konva.Rect({
    x: 0,
    y: 0,
    width: containerWidth,
    height: containerHeight,
    fill: 'white'
  });
  drawingLayer.add(maskRect);

  // 顶层:正常显示图层,设置合成模式仅显示与drawingLayer重叠的区域
  let normalLayer = new Konva.Layer();
  normalLayer.globalCompositeOperation('source-in');
  stage.add(normalLayer);

  // 加载图片到对应图层
  loadImage(getLightSkin, redFilterLayer, true);
  loadImage(getLightMask, normalLayer, false);

  // 画笔显示层
  let brushLayer = new Konva.Layer();
  stage.add(brushLayer);

  let isDrawing = false;
  let brushSize = 20;
  let currentLine;

  // 画笔光标
  let brush = new Konva.Circle({
    x: -50,
    y: -50,
    radius: brushSize / 2,
    stroke: 'black',
    strokeWidth: 1,
    fill: 'rgba(0,0,0,0.2)'
  });
  brushLayer.add(brush);

  stage.on('mousedown', function(e) {
    isDrawing = true;
    let pos = stage.getPointerPosition();

    currentLine = new Konva.Line({
      stroke: 'white',
      strokeWidth: brushSize,
      // 左键擦除遮罩,右键恢复遮罩
      globalCompositeOperation: e.evt.button === 0 ? 'destination-out' : 'source-over',
      points: [pos.x, pos.y],
      tension: 0.5,
      lineCap: 'round',
      lineJoin: 'round'
    });

    drawingLayer.add(currentLine);
  });

  stage.on('mousemove', function(e) {
    let pos = stage.getPointerPosition();
    brush.position({ x: pos.x, y: pos.y });
    brushLayer.batchDraw();

    if (isDrawing && currentLine) {
      let newPoints = currentLine.points().concat([pos.x, pos.y]);
      currentLine.points(newPoints);
      drawingLayer.batchDraw();
    }
  });

  stage.on('mouseup', function() {
    isDrawing = false;
  });

  stage.on('contextmenu', function(e) {
    e.evt.preventDefault();
  });
}

核心逻辑解释

  • source-in合成模式:normalLayer仅会在drawingLayer有像素的区域显示,完美实现遮罩效果
  • destination-out模式:在drawingLayer上绘制时,会擦除目标区域的像素(即白色遮罩),让normalLayer对应位置消失
  • source-over模式:在drawingLayer上绘制白色,恢复遮罩区域,让normalLayer重新显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:33:12