当循环缩放动画时,线性计时不会感觉是线性的,而是在开始时很慢,在结束时很快。
您将如何计算正确的曲线? 如果您需要更多信息,请在评论中询问。
在这支笔中,我使用手绘曲线来尝试解决这个问题,因为我显然太愚蠢了,无法弄清楚其中的逻辑。
http://codepen.io/pixelass/pen/qZjBQy
// mathematically correct curve ?
@function linear-zoom() {
// add your code here
$sx: 0;
$sy: 0;
$ex: 1;
$ey: 1;
$curve: ($sx, $sy, $ex, $ey);
@return $curve;
}
最佳答案
您使用的缩放参数是 2 的倍数,因此当您使用线性动画速度时,缩放比例会线性增加,但距离会以对数方式增加。
让我们看一些数字。首先,我们将一个圆从 0.5
缩放到 2
,因此需要两个 log2 步骤:
t=0 => scale(0.5)
t=0.25 => scale((0.75 * 0.5 + 0.25 * 2)) = scale(0.875)
t=0.5 => scale((0.5 * 0.5 + 0.5 * 2)) = scale(1.25)
t=0.75 => scale((0.25 * 0.5 + 0.75 * 2)) = scale(1.625)
t=1 => scale(2)
所以看起来很棒,开始和结束之间的线性过渡。我们可能认为这意味着我们可以添加更多的圆圈来做同样的事情,但如果我们这样做,我们最终会得到对数行为。让我们看看原因:假设我们添加一个将 0.25
缩放到 1
的值。
t=0 => scale(0.25)
t=0.25 => scale((0.75 * 0.25 + 0.25)) = scale(0.4375)
t=0.5 => scale((0.5 * 0.25 + 0.5)) = scale(0.625)
t=0.75 => scale((0.25 * 0.25 + 0.75)) = scale(0.8125)
t=1 => scale(1)
这似乎不错:在每个时间间隔,大圆的半径是小圆的两倍...但这不是您想要的,因为这也意味着当大圆上的点移动两倍距离(1.5 个单位)时,小圆上的点仅移动 0.75 个单位。我们看到,圆圈的起始位置越大,它在屏幕上移动的速度就越快,遵循一个简单的 2^t
公式。
为了抵消这个问题,您需要补偿特定的对数增长,由于参数不同,每个动画都独立。让一条贝塞尔曲线对所有曲线执行此操作在数学上是不可能的,但由于人类不是完美的数学机器,因此您可以在像代码笔这样的一小块屏幕上完成它 - 在任何开始都“正确”地执行它/结束参数 a
和 b
集,您需要设置一条贝塞尔曲线,该曲线近似于函数 1/(2^t)
间隔t=[a,b]
,这没什么乐趣:我们需要近似 series for 1/2^x up to order 2使用贝塞尔曲线的特定间隔,然后使用为我们提供的坐标作为三次缓动参数。
有两种方法可以做到这一点 - 要么找到一条最适合从全局最小值到最大值的函数的贝塞尔曲线,然后使用曲线分割来找到每个子区间的参数,或者找到适合每个单独的贝塞尔曲线间隔。第一个(稍微)更容易,但由于 1/2^x
的低类(Class)数近似而容易出错,第二个更好,但工作量很大,所以如果你想找出答案如何做到这一点math.stackexchange.com这里是了解真正数学基础的更好地方。
大多数程序员能够使用的“Stackoverflow 答案”是为自己构建一个“某些间隔的某些曲线”的查找表,然后使用这些曲线之间的插值来处理落在您所设置的间隔之间的间隔。用于构建 LUT:使用您所使用的任何语言绘制间隔,然后使用类似 cubic-bezier.com 的内容将该图重叠起来,然后通过观察控制点来简单地为每个图找到“合适的”。比如说,按照您使用的十个间隔执行此操作,就可以开始了。
这肯定不是数学问题,而且您无法将该解决方案“编程”为通用解决方案,但它是高效的:从用户感知的 Angular 来看,这个解决方案应该已经足够好,感觉很流畅。
关于css - 计算线性缩放的贝塞尔曲线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36217435/