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

Canvas笔刷场景下实现光标经过区域文本切换的方法

笔刷擦除换字实现方案

不用纠结mix-blend-mode,用Canvas遮罩方案最可控,能1:1匹配笔刷形状,实现刷过的位置露出下层文字的效果,核心逻辑很简单:

  • 两层文字完全重叠摆放,下层放黄色的「w marketingu」,上层放白色的「w brandingu i digital」
  • 单独用一个透明Canvas铺在最上层接鼠标事件,专门记录笔刷移动轨迹
  • 给上层白色文字绑定Canvas作为透明度遮罩:遮罩不透明的位置白字正常显示,遮罩被笔刷“擦除”变透明的位置,白字隐藏露出下层黄字

第一步:调整CSS层叠与遮罩配置

把原来错乱的伪元素层级、画布层级理顺,给上层白字加遮罩属性:

.hero__animation_container {
  position: relative;
}
/* 画布透明铺在最上层,不阻挡鼠标交互 */
.hero__canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 3;
  pointer-events: none;
}
.hero__headings {
  position: relative;
  z-index: 2;
}
.brush {
  position: relative;
  font-size: 80px;
  margin: 0;
}
/* 下层黄色文本,层级最低 */
.brush::before {
  position: absolute;
  content: 'w marketingu';
  color: #ffdd00;
  top: 0;
  left: 0;
  z-index: 1;
}
/* 上层白色文本,绑定canvas遮罩 */
.brush::after {
  position: absolute;
  content: 'w brandingu i digital';
  color: #ffffff;
  top: 0;
  left: 0;
  z-index: 2;
  -webkit-mask-image: -webkit-canvas(brushMask);
  mask-image: -webkit-canvas(brushMask);
  mask-repeat: no-repeat;
}

第二步:修改JS绘制逻辑

替换原来容易错位的滚动偏移计算,改用元素相对坐标,同时在遮罩层用擦除模式绘制笔刷:

function drawAnimation() {
  var yellowBrush = new Image();
  // 等笔刷素材加载完成再绑定交互,避免首次绘制空白
  yellowBrush.onload = initBrush;
  yellowBrush.src = 'wp-content/themes/starter/assets/images/brush-yellow.png';

  function initBrush() {
    var hoverArea = document.getElementById('hero__headings');
    var textContainer = document.querySelector('.brush');
    var viewCanvas = document.getElementById('hero__canvas');
    // 初始化遮罩画布,尺寸和文本容器一致
    var maskCtx = document.getCSSCanvasContext('2d', 'brushMask', textContainer.offsetWidth, textContainer.offsetHeight);
    viewCanvas.width = textContainer.offsetWidth;
    viewCanvas.height = textContainer.offsetHeight;
    var viewCtx = viewCanvas.getContext('2d');

    // 遮罩初始全黑填充,对应上层白字默认全部显示
    maskCtx.fillStyle = '#000';
    maskCtx.fillRect(0, 0, viewCanvas.width, viewCanvas.height);
    maskCtx.lineJoin = maskCtx.lineCap = 'round';
    viewCtx.lineJoin = viewCtx.lineCap = 'round';

    var lastPoint = { x: 0, y: 0 };
    // 笔刷偏移值,根据你自己的笔刷素材尺寸调整,保证笔刷中心对齐鼠标
    var brushOffsetX = 25;
    var brushOffsetY = 25;

    function getPos(e) {
      var rect = textContainer.getBoundingClientRect();
      return {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      }
    }

    function distanceBetween(p1, p2) {
      return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
    }

    function angleBetween(p1, p2) {
      return Math.atan2(p2.x - p1.x, p2.y - p1.y);
    }

    hoverArea.onmouseenter = function(e) {
      lastPoint = getPos(e);
    }

    hoverArea.onmousemove = function(e) {
      var currentPoint = getPos(e);
      var dist = distanceBetween(lastPoint, currentPoint);
      var angle = angleBetween(lastPoint, currentPoint);

      for (var i = 0; i < dist; i++) {
        var x = lastPoint.x + Math.sin(angle) * i - brushOffsetX;
        var y = lastPoint.y + Math.cos(angle) * i - brushOffsetY;
        // 可见画布正常画笔刷材质,不需要显示黄色笔刷痕迹可以删掉下面这行
        viewCtx.drawImage(yellowBrush, x, y);
        // 遮罩层切换为擦除模式,画过的位置变透明,露出下层黄字
        maskCtx.globalCompositeOperation = 'destination-out';
        maskCtx.drawImage(yellowBrush, x, y);
      }

      lastPoint = currentPoint;
    }
  }
}

jQuery(document).ready(function($) {
  drawAnimation();
  // 窗口尺寸变化时重绘画布,避免遮罩错位
  let resizeTimer;
  $(window).on('resize', function() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(drawAnimation, 300);
  })
})

调整注意事项

  • 如果需要兼容火狐浏览器,不用-webkit-canvas的原生引用方式,每次笔刷绘制完成后把画布转成base64地址,赋值给.brush::after的mask-image属性即可,核心逻辑不变
  • brushOffsetX、brushOffsetY两个值根据你实际用的笔刷png尺寸调整,保证鼠标位置刚好在笔刷的落笔点
  • 如果需要重置笔刷效果(比如鼠标移出区域后恢复初始白字状态),直接在mouseleave事件里重新给遮罩层填充全黑、清空可见画布就行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:06:19