【问题标题】:Does d3.js have reverse ease functions?d3.js 有反向缓动功能吗?
【发布时间】:2017-01-10 12:58:16
【问题描述】:

使用 d3.js,我们可以在标准化时间 t 中实现缓和时间,通常在 [0,1] 范围内

例如:

d3.easeCubic(0.25) = 0.0625

我们如何反转它,我们如何在已知 y 的情况下找到 x?

d3.easeCubic(X) = 0.0625,
X ???

这里的答案是三次根,但仍然是。

问题在于可重用性,缓动函数可以更改为d3.easeExpIn,或`d3.easeCircleOut,或任何其他,你需要自己发明反向函数,还是隐藏在任何地方?

【问题讨论】:

  • 只是出于好奇,你会用它来做什么?
  • @altocumulus 我有一个带有值点的折线图,它通过窗帘方法进行动画处理 (bl.ocks.org/markmarkoh/8700606) 当窗帘“通过”一个值时,一个点通过从 0 到 4 的半径过渡出现. 传递值的时刻是let timeout = x(value) / width * duration。幕布随着缓动而移动,所以我必须像let timeout = Math.cbrt(x(value) / width) * duration 一样修改它为d3.easeCubicIn
  • 我认为,这最好使用自定义补间函数来完成,您可以完全控制缓动的当前值。然而,这本身就值得提出一个问题。这个问题已经得到了一个我完全同意的不错的答案。

标签: d3.js


【解决方案1】:

首先,你的数学是错误的。 d3.easeCubic(0.25)会给你0.0625

var easy = d3.easeCubic(0.25);
console.log(easy);
<script src="https://d3js.org/d3.v4.min.js"></script>

现在,回到你的问题:

我们如何反转它,我们如何在已知 y 的情况下找到 x?

没有本地解决方案,但我们可以创建自己的函数来在已知 Y 的情况下找到 X。当然,问题是我们必须为每个特定的缓动反转数学......但是,既然你问了关于d3.easeCubic,与d3.easeCubicInOut 相同,让我们尝试为特定的缓动创建一个倒置 函数。

第一步,我们看一下源码:

export function cubicInOut(t) {
    return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}

你可以很容易地看到这是正确的函数,给我们的值与第一个 sn-p 相同:

function cubicInOut(t) {
    return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}

console.log(cubicInOut(0.25))

现在,让我们尝试反转它。

这里的数学有点复杂,但是对于小于 1 的值,这里是函数:

function inverseEaseCubic(t){
    return Math.cbrt(t * 2) / 2;
}

这里是演示。我们将0.0625 传递给函数,它返回0.25

function inverseEaseCubic(t){
    return Math.cbrt(t * 2) / 2;
}

console.log(inverseEaseCubic(0.0625))

如果你想处理大于 1 的数字,这就是完整的功能:

function InverseEaseCubic(t){
    return t <= 1 ? Math.cbrt(t * 2) / 2 : (Math.cbrt(2 * t - 2) + 2) / 2;
}

PS:his comment 中,@altocumulus 只是提醒我们,有时甚至不可能找到值。这是一个非常简单的例子。假设这个函数:

function exponentiation(a){
    return a*a;
}

现在想象一下,当使用未知参数调用该函数时,该函数返回4。论据是什么?我们能找出来吗?无法确定,因为像这样的二阶方程有 2 个根:

console.log(exponentiation(2))//returns 4
console.log(exponentiation(-2))//also returns 4 

【讨论】:

  • 这进一步增加了问题的复杂性,即反转 elasticXXXbackXXXbounceXXX 缓动函数也会产生非唯一的解决方案。
  • 感谢详细解答,可惜没有像d3.easeCubic.inverse(0.25)那样实现,因为有很多简单的函数,其中一些比cubic更复杂。
  • @GerardoFurtado 如果有 2 个值 [2, -2],为什么不将它们作为数组返回?
  • @GerardoFurtado 除了我们主要在 [0,1] 范围内寻找归一化值
  • @user3468806 问题不是返回一个数组,这很简单,而是找到所有可能的解决方案,这有时会非常复杂。
【解决方案2】:

我使用了@Gerardo Furtado 的答案,但反函数效果不佳,所以我又写了一个

function cubicInOut(t) {
  return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}
function inverseEaseCubic(x) {
  return x < .5 ? Math.cbrt(x / 4) : (2 - Math.cbrt(2 - 2 * x)) / 2;
}
  
console.log(inverseEaseCubic(cubicInOut(1)) === 1);
console.log(inverseEaseCubic(cubicInOut(0.6)) === 0.6);
console.log(inverseEaseCubic(cubicInOut(0.4)) === 0.4);
console.log(inverseEaseCubic(cubicInOut(0.1)) === 0.1);
console.log(inverseEaseCubic(cubicInOut(0)) === 0);

【讨论】:

    猜你喜欢
    • 2017-07-30
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多