如何用cubic-bezier实现Canvas视觉匀速缩放动画?
问题描述
我有一个16384px×16384px的Canvas,初始通过scale3d(0.03125, 0.03125, 0.03125)缩放到512px大小,点击按钮后通过CSS transition将其缩放至原始尺寸。即使设置了linear时序函数,视觉上仍呈现先加速后减速的效果,而非匀速。已知该问题与元素尺寸过大、过渡时长相关,希望通过cubic-bezier()时序函数修正,求适配场景的参数公式,或确认是否为无法避免的视觉错觉。允许将过渡时长调整至≤10s。
相关代码示例
HTML
<canvas width="16384px" height="16384px"></canvas> <button class="hidden"> scale </button>
CSS
canvas { position: absolute; transform: translate(-50%, -50%) scale3d(0.03125, 0.03125, 0.03125); transition: transform 5s linear; top: 50%; left: 50%; } canvas.scale { transform: translate(-50%, -50%) scale3d(1, 1, 1); } button { position: absolute; top: 0; left: 0; } .hidden { display: none; }
JavaScript
let canvas = document.querySelector('canvas') let button = document.querySelector('button') let ctx = canvas.getContext('2d') button.onclick = function() { if (canvas.classList.contains('scale')) { canvas.classList.remove('scale') } else { canvas.classList.add('scale') } } let img = new Image() img.height = '256px' img.width = '256px' img.onload = function() { let y = 0 while (y < 16384) { let x = 0 while (x < 16384) { ctx.drawImage(img, x, y) x+=256 } y+=256 } button.classList.remove('hidden') } img.src = 'https://i.etsystatic.com/16276846/r/il/ab3661/1503703028/il_570xN.1503703028_frl8.jpg'
解决方案
1. 视觉错觉的本质
这确实是视觉感知错觉:CSS的linear时序函数是让缩放比例随时间匀速变化,但人眼对缩放的感知是基于画面中像素的移动速度。比如从0.03125倍到1倍的过程中,初始阶段缩放比例每增加0.01,对应实际像素移动距离仅为16384×0.01=163.84px;而后期缩放比例从0.9增加到0.91,像素移动距离同样是163.84px,但此时画面已经接近原始尺寸,相同的像素移动在视觉上会显得更快,整体就呈现出先加速后减速的效果。
2. 适配的cubic-bezier参数推导
要实现视觉上的匀速,需要让像素移动速度恒定,也就是缩放比例的变化率和当前缩放比例成反比,对应的时间t与缩放比例s的关系是s(t) = s₀ × (s₁/s₀)^t(t∈[0,1])。由于CSS的cubic-bezier只能用三次贝塞尔曲线近似模拟这种对数曲线,针对你的场景(从0.03125倍放大到1倍,即32倍缩放),可以使用以下近似参数:
- 放大动画:
cubic-bezier(0.16, 0, 0.84, 1) - 缩小动画:
cubic-bezier(0.16, 1, 0.84, 0)
如果需要更精准的拟合,可以通过关键点计算调整:比如当t=0.25时,s应该达到0.03125^(0.75)=0.125;t=0.5时s=0.03125^0.5≈0.1768;t=0.75时s=0.03125^0.25≈0.3536。基于这些点微调贝塞尔控制点,比如cubic-bezier(0.15, 0, 0.85, 1),再根据实际视觉效果调整。
3. 过渡时长的调整建议
将过渡时长调整到3-5s范围内,人眼对快速变化的感知敏感度会降低,视觉错觉的影响会减弱。结合上述cubic-bezier参数,能更接近理想的匀速缩放效果。
内容的提问来源于stack exchange,提问作者user2272048

