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
相关产品推荐
相关产品推荐

