【问题标题】:How to interpolate progress based on discrete steps?如何根据离散步骤插入进度?
【发布时间】:2014-12-10 15:25:59
【问题描述】:

在 Web 应用程序中,某些任务需要多个连续的 ajax 调用步骤才能完成。每个需要 12-18 秒。

我想向用户展示一个进度指示器,它正在执行频繁的小步骤。

我的第一个赌注是假设一个线性 progress = k * time 函数,在每个新响应上自我调整 kFiddle emulated 随机值在 +- 4s 范围内的响应时间。

这种方法似乎是错误的:在一系列快速反应之后反应相对较长的情况下,进展会采取消极的步骤来赶上实际速度。

感觉一个函数应该以“波”的形式出现:开始时更快,在检查点延迟的情况下在接近结束时减速。

此类任务的最佳做法是什么?

【问题讨论】:

标签: javascript function math interpolation progress


【解决方案1】:

我将专注于您请求的数学部分:

函数应该以“波浪”形式出现:开始时更快,在检查点延迟的情况下在接近结束时减速

平移:具有正初始梯度和大 x 渐近行为的单调函数(即没有后退步骤)。

考虑 atan(theta):对于小 x,它的梯度为 1,对于大 x,它渐近接近 π/2。我们可以缩放它,以便在块处于可用长度的某个分数时发生预期的结束 - 也就是说,如果您预计它需要 4 秒,而它需要 4 秒,它可以跳过剩余部分。如果它需要更长的时间,这个剩余部分就是我们将渐近吃掉的部分。因此:

function chunkProgressFraction(expectedEndT, currentT, expectationFraction) {
    // validate
    if(!expectedEndT) { return 0; }

    // defaults        
    if(!expectationFraction) { expectationFraction = 0.85 }

    // y = k atan(mx)
    // to reach 1.0 at large x:
    // 1.0 = k . atan(+lots) = k . pi/2
    var k = 2.0 / Math.PI;
    // scale the function so that the expectationFraction result happens 
    // at expectedEndT, i.e. 
    // expectationFraction = k * atan(expectedEndT * m)
    // expectedEndT * m = tan(expectationFraction / k)
    var m = Math.tan(expectationFraction / k) / expectedEndT;

    return k * Math.atan(m * currentT);
}

所以如果我们想要达到 100 像素,并且我们希望它需要 4 秒,并且我们想要 20% 的 slack:

progressPixelsThisChunk = 100.0 * 
      chunkProgressValue(4000.0, thisChunkTimeInMilliseconds, 0.8);

一定要使用前一个块所用的时间来缩放 expectedEndT。

【讨论】:

  • 谢谢,@phil-h,我想我明白了。每次测量后,我都会设定下一个“目标”,作为之前步骤的平均值。并接近该目标,永远不会超过使用 atan 或 1/-x^2-like 之类的函数的值:!grapher chart
  • A+B*(x^-2)atan() 更可取,因为它在一开始就有缓入感!grapher tests
  • 好东西。我选择了 atan,因为它很简单,并且函数和它的逆都可以在 Math 中使用。无论什么真正适合您,关键是在数学上构建您的需求。祝你好运!
猜你喜欢
  • 1970-01-01
  • 2016-12-05
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
相关资源
最近更新 更多