HTML Canvas元素接触检测:实现正弦波形覆盖文本时自动切换字体颜色
实现方案
这里提供两种可行的实现路径,你可以根据自己的需求选择:
方案一:CSS混合模式实现(零JS修改,成本最低)
这个方案利用CSS的混合模式自动实现文字和背景的反色效果,完全不需要改动现有JS逻辑,仅需修改3行CSS:
/* 新增body背景,避免透明透出异常颜色 */ body { margin: 0; padding: 0; background: #fff; /* 新增这行 */ } /* 修改h1样式 */ h1 { text-align: center; color: #000; /* 把原有white改成black */ mix-blend-mode: difference; /* 新增这行 */ }
实现原理:
- 波浪未覆盖的区域canvas为透明,透出底层body的白色背景,黑色文字和白色背景做差值混合后显示为白色
- 波浪覆盖的区域canvas为黑色,黑色文字和黑色背景做差值混合后显示为黑色,刚好匹配你要的效果
方案二:JS检测覆盖状态实现(灵活度更高)
如果后续需要自定义触发逻辑(比如覆盖比例超过50%才变色、变色时加过渡动画等),可以用JS实时检测波浪和文字的重叠状态:
修改步骤:
- 先在JS代码中提前获取h1元素:
const title = document.querySelector('h1');
- 在
drawWave函数末尾新增重叠检测逻辑:
const drawWave = () => { // 原有代码保持不变 // ... 原有drawWave代码 ... // 新增以下检测逻辑 const titleRect = title.getBoundingClientRect(); // 计算标题水平范围内的波浪最高、最低位置 let waveMinY = Infinity; let waveMaxY = -Infinity; // 只遍历标题水平覆盖的x范围,不用遍历全宽,性能更好 for (let x = titleRect.left; x < titleRect.right; x++) { const y = wave.y + Math.sin(x * wave.length + increment) * wave.amplitude; waveMinY = Math.min(waveMinY, y); waveMaxY = Math.max(waveMaxY, y); } // 判断波浪和标题垂直范围是否有重叠 const isOverlap = !(waveMaxY < titleRect.top || waveMinY > titleRect.bottom); title.style.color = isOverlap ? '#000' : '#fff'; };
额外优化建议
- 现有波浪绘制的for循环步长为1,宽屏设备下性能损耗较高,可以把步长改成23,视觉上几乎没有差异,绘制效率能提升23倍:
for (let i = 0; i < canvas.width; i+=2) { // 把i++改成i+=2 ctx.lineTo(i, wave.y + Math.sin(i * wave.length + increment) * wave.amplitude); } - 窗口resize事件加防抖,避免频繁重设canvas尺寸导致卡顿
- 你已经引入了dat.gui,可以把wave的振幅、频率、位置等参数绑定到控制面板,调试参数更方便
内容的提问来源于stack exchange,提问作者Un Jin Jang
相关产品推荐
相关产品推荐

