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
Count animation from number A to B
提问by RienNeVaPlu?s
I am updating a numeric value
inside an element
by doing intervalled ajax requests
.
我正在通过执行 intervalled 来更新numeric value
内部。element
ajax requests
To make the whole thing a bit more alive, I want to count from the current
value to the new
one, by partially in- or decreasingthe value
over 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:
我对这种动画的处理方式略有不同。基于这些假设:
- there is a starting text(as fallback for non-JS browser or google indexing)
- this text can contains non-numeric chars
- the function take an element directlyas first param (as opposed to an element Id)
- 有一个起始文本(作为非 JS 浏览器或谷歌索引的后备)
- 此文本可以包含非数字字符
- 该函数将一个元素直接作为第一个参数(而不是元素 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
, end
and duration
.
此外,所有参数现在都有默认值start
,end
和duration
。
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/
回答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)