如何在Canvas 2D中实现平滑滚动的无跳变重复线性渐变
Canvas 2D 无缝循环滚动渐变实现方案
跳变原因
Canvas 2D 标准的createLinearGradient API 原生不支持渐变重复平铺,没有等价于CSS repeating-linear-gradient的能力。原有代码直接将移动到pos>1位置的色标重置到pos=0,会打断色标间的颜色插值连续性,必然产生视觉跳变。
核心实现逻辑
通过双段色带拼接+全局偏移控制实现无跳变循环,不需要离屏绘制:
- 固定所有色标的原始位置,单独维护全局滚动偏移量,从根源避免单个色标位置跳变
- 将渐变线长度扩展为单组色带的2倍,在渐变区间内放置两组完全相同的色带,首尾色值保持一致保证衔接平滑
- 每帧累加偏移量,当偏移量走完1个完整色带周期时直接将偏移量减1,此时第二组色带刚好完全对齐原第一组色带的显示位置,视觉上完全重合,无任何跳变
- 添加色标时,单个色标的实际位置为
原始位置 + 组序号 - 全局偏移,保证所有色标落在0~2的有效渐变区间内
修正后完整代码
JavaScript
const colors = [ { color: "#FF0000", pos: 0 }, { color: "#FFFF00", pos: 1 / 5 }, { color: "#00FF00", pos: 2 / 5 }, { color: "#0000FF", pos: 3 / 5 }, { color: "#FF00FF", pos: 4 / 5 }, { color: "#FF0000", pos: 1 }, ]; const angleStep = 0.2; const linearStep = 0.001; function init() { const canvas = document.querySelector("canvas"); const context = canvas.getContext("2d"); const mw = canvas.width; const mh = canvas.height; let angle = 0; // 全局偏移量,替代直接修改色标pos的逻辑 let offset = 0; function drawScreen() { angle = (angle + angleStep) % 360; // 偏移走满一个周期直接重置,无视觉跳变 offset += linearStep; if (offset >= 1) offset -= 1; const [x1, y1, x2, y2] = angleToPoints(angle, mw, mh); // 渐变线延长为原来2倍,容纳两组重复色带 const gradient = context.createLinearGradient( x1 - (x2 - x1), y1 - (y2 - y1), x2, y2 ); // 填充两组完全一致的色带 for (let i = 0; i < 2; i++) { for (const colorStop of colors) { const realPos = colorStop.pos + i - offset; gradient.addColorStop(realPos, colorStop.color); } } context.fillStyle = gradient; context.fillRect(0, 0, canvas.width, canvas.height); } function loop() { drawScreen() window.requestAnimationFrame(loop); } loop(); } function angleToPoints(angle, width, height){ const rad = ((180 - angle) / 180) * Math.PI; const length = Math.abs(width * Math.sin(rad)) + Math.abs(height * Math.cos(rad)); const halfx = (Math.sin(rad) * length) / 2.0 const halfy = (Math.cos(rad) * length) / 2.0 const cx = width / 2.0 const cy = height / 2.0 const x1 = cx - halfx const y1 = cy - halfy const x2 = cx + halfx const y2 = cy + halfy return [x1, y1, x2, y2]; } init();
CSS
html,body, canvas { width: 100%; height: 100%; margin: 0; padding: 0; }
HTML
<canvas width="128" height="72"></canvas>
效果说明
该实现和CSS repeating-linear-gradient实现的滚动渐变效果完全一致,任意角度下都不会出现边缘色值突变、帧跳变的问题,不需要额外创建离屏Canvas做二次绘制,性能和原有实现基本持平。
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

