javascript 计算从 A 到 B 的动画

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16994662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 06:42:40  来源:igfitidea点击:

Count animation from number A to B

javascript

提问by RienNeVaPlu?s

I am updating a numeric valueinside an elementby doing intervalled ajax requests.

我正在通过执行 intervalled 来更新numeric value内部。elementajax requests

To make the whole thing a bit more alive, I want to count from the currentvalue to the newone, by partially in- or decreasingthe valueover a time of n sec.

为了使整个事情有点更有活力,我想从计算current价值的new一个,通过部分输入或减少value过度的时间n sec

So basically something like this:

所以基本上是这样的:

<div id="value">100</div>
<script type="text/javascript">
    /** Decrease $value (over a time of 2 seconds) till it reaches 25 */
    $value.increaseAnimation(-75, {duration:2});
</script>

Is there a javascript library for doing so?

是否有这样做的 javascript 库?

回答by jfriend00

You can just code it yourself pretty simply:

您可以非常简单地自己编写代码:

function animateValue(id, start, end, duration) {
    var range = end - start;
    var current = start;
    var increment = end > start? 1 : -1;
    var stepTime = Math.abs(Math.floor(duration / range));
    var obj = document.getElementById(id);
    var timer = setInterval(function() {
        current += increment;
        obj.innerHTML = current;
        if (current == end) {
            clearInterval(timer);
        }
    }, stepTime);
}

animateValue("value", 100, 25, 5000);
#value {
    font-size: 50px;
}
<div id="value">100</div>



Here's is a more accurate version that self adjusts in case the timer intervals aren't perfectly accurate (which they sometimes aren't):

这是一个更准确的版本,可以在计时器间隔不完全准确(有时不是)的情况下进行自我调整:

function animateValue(id, start, end, duration) {
    // assumes integer values for start and end
    
    var obj = document.getElementById(id);
    var range = end - start;
    // no timer shorter than 50ms (not really visible any way)
    var minTimer = 50;
    // calc step time to show all interediate values
    var stepTime = Math.abs(Math.floor(duration / range));
    
    // never go below minTimer
    stepTime = Math.max(stepTime, minTimer);
    
    // get current time and calculate desired end time
    var startTime = new Date().getTime();
    var endTime = startTime + duration;
    var timer;
  
    function run() {
        var now = new Date().getTime();
        var remaining = Math.max((endTime - now) / duration, 0);
        var value = Math.round(end - (remaining * range));
        obj.innerHTML = value;
        if (value == end) {
            clearInterval(timer);
        }
    }
    
    timer = setInterval(run, stepTime);
    run();
}

animateValue("value", 100, 25, 5000);
#value {
    font-size: 50px;
}
<div id="value">100</div>

回答by Luca Murante

I had a slightly different approach to this kind of animation. Based on these assumptions:

我对这种动画的处理方式略有不同。基于这些假设:

  1. there is a starting text(as fallback for non-JS browser or google indexing)
  2. this text can contains non-numeric chars
  3. the function take an element directlyas first param (as opposed to an element Id)
  1. 有一个起始文本(作为非 JS 浏览器或谷歌索引的后备)
  2. 此文本可以包含非数字字符
  3. 该函数将一个元素直接作为第一个参数(而不是元素 Id)

So, if you want to animate a simple text like "+300% gross margin", only the numericpart will be animated.

因此,如果您想为“+300% 毛利率”之类的简单文本设置动画,则只会对数字部分进行动画处理。

Moreover, all params have now a default value for start, endand duration.

此外,所有参数现在都有默认值start,endduration

https://codepen.io/lucamurante/pen/gZVymW

https://codepen.io/lucamurante/pen/gZVymW

function animateValue(obj, start = 0, end = null, duration = 3000) {
    if (obj) {

        // save starting text for later (and as a fallback text if JS not running and/or google)
        var textStarting = obj.innerHTML;

        // remove non-numeric from starting text if not specified
        end = end || parseInt(textStarting.replace(/\D/g, ""));

        var range = end - start;

        // no timer shorter than 50ms (not really visible any way)
        var minTimer = 50;

        // calc step time to show all interediate values
        var stepTime = Math.abs(Math.floor(duration / range));

        // never go below minTimer
        stepTime = Math.max(stepTime, minTimer);

        // get current time and calculate desired end time
        var startTime = new Date().getTime();
        var endTime = startTime + duration;
        var timer;

        function run() {
            var now = new Date().getTime();
            var remaining = Math.max((endTime - now) / duration, 0);
            var value = Math.round(end - (remaining * range));
            // replace numeric digits only in the original string
            obj.innerHTML = textStarting.replace(/([0-9]+)/g, value);
            if (value == end) {
                clearInterval(timer);
            }
        }

        timer = setInterval(run, stepTime);
        run();
    }
}

animateValue(document.getElementById('value'));
#value {
    font-size: 50px;
}
<div id="value">+300% gross margin</div>

回答by User Rebo

Current solutions do update more often than needed. Here a frame based approach, which is accurate:

当前的解决方案确实比需要的更新频率更高。这是一种基于框架的方法,它是准确的:

function animateValue(obj, start, end, duration) {
  let startTimestamp = null;
  const step = (timestamp) => {
    if (!startTimestamp) startTimestamp = timestamp;
    const progress = Math.min((timestamp - startTimestamp) / duration, 1);
    obj.innerHTML = Math.floor(progress * (end - start) + start);
    if (progress < 1) {
      window.requestAnimationFrame(step);
    }
  };
  window.requestAnimationFrame(step);
}

const obj = document.getElementById('value');
animateValue(obj, 100, -25, 2000);
div {font-size: 50px;}
<div id="value">100</div>

回答by londonfed

This works well. However, I needed to use a comma within the number. Below is the updated code which checks for commas. Hope someone finds this useful if they stumble across this post.

这很好用。但是,我需要在数字中使用逗号。以下是检查逗号的更新代码。希望有人在偶然发现这篇文章时发现这很有用。

function animateValue(id, start, end, duration) {

    // check for commas
    var isComma = /[0-9]+,[0-9]+/.test(end); 
    end = end.replace(/,/g, '');

    // assumes integer values for start and end

    var obj = document.getElementById(id);
    var range = end - start;
    // no timer shorter than 50ms (not really visible any way)
    var minTimer = 50;
    // calc step time to show all interediate values
    var stepTime = Math.abs(Math.floor(duration / range));

    // never go below minTimer
    stepTime = Math.max(stepTime, minTimer);

    // get current time and calculate desired end time
    var startTime = new Date().getTime();
    var endTime = startTime + duration;
    var timer;

    function run() {
        var now = new Date().getTime();
        var remaining = Math.max((endTime - now) / duration, 0);
        var value = Math.round(end - (remaining * range));
        obj.innerHTML = value;
        if (value == end) {
            clearInterval(timer);
        }
        // Preserve commas if input had commas
        if (isComma) {
            while (/(\d+)(\d{3})/.test(value.toString())) {
                value = value.toString().replace(/(\d+)(\d{3})/, ''+','+'');
            }
        }
    }

    var timer = setInterval(run, stepTime);
    run();
}

animateValue("value", 100, 25, 2000); 

回答by Nevil Saul Blemuss

HTML

HTML

<!DOCTYPE html>
<html>
<head>
    <title>Count</title>
</head>
<body>
    <div id="value">1000</div>
</body>
</html>

JAVASCRIPT snippet

JAVASCRIPT 片段

Here is a simple js function decrementing values from a given start number to an end number (object prototype)..

这是一个简单的 js 函数,将值从给定的开始编号递减到结束编号​​(对象原型)。

function getCounter(startCount,endcount,time,html){
objects = {
    //you can alternateif you want yo add till you reach the endcount
    startCount:startCount,
    endCount:endcount,
    timer:time
}
this.function = function(){
    let startTm  = objects.startCount,
        timer = objects.timer,
        endCount = objects.endCount;
        //if you want it to add a number just replace the -1 with +1
        /*and dont forget to change the values in the object prototype given a variable of counter*/
    let increament = startTm  < endCount ? 1:-1;
        timmer  = setInterval(function(){
                startTm  += increament;
                html.innerHTML = startTm ;
                if(startTm  == endCount){
                    clearInterval(timmer);
                }
            },timer);
   }
}
// input your startCount,endCount  the timer.....
let doc = document.getElementById('value');

let counter = new getCounter(1000,1,10,doc);
//calling the function in the object
counter.function();

Check out this demo https://jsfiddle.net/NevilPaul2/LLk0bzvm/

看看这个演示https://jsfiddle.net/NevilPaul2/LLk0bzvm/

回答by qwertzzz

This is what i came up with:

这就是我想出的:

function animateVal(obj, start=0, end=100, steps=100, duration=500) {   
    start = parseFloat(start)
    end = parseFloat(end)

    let stepsize = (end - start) / steps
    let current = start
    var stepTime = Math.abs(Math.floor(duration / (end - start)));
    let stepspassed = 0
    let stepsneeded = (end - start) / stepsize

    let x = setInterval( () => {
            current += stepsize
            stepspassed++
            obj.innerHTML = Math.round(current * 1000) / 1000 
        if (stepspassed >= stepsneeded) {
            clearInterval(x)
        }
    }, stepTime)
}   

animateVal(document.getElementById("counter"), 0, 200, 300, 200)