Problems during numerical calculation using an animation function written in native JavaScript
I tried to write a code when learning the MOOC online JavaScript animation effect. But I found several problems:
Non-uniform animation velocity
Animation duration was not able to be controlled
Other actions started before the animation reached the terminating condition (especially during transparency changes. The super-long decimal point calculation – as many as eight to nine decimal places – of JavaScript just left me speechless.)
Can somebody help me modify the code? Thanks so much.
If somebody can write a concise native JavaScript animation function that enables interaction of multiple attributes for reference, that would be even more awesome. (Please do make the animation duration controllable and animation termination strictly following the given conditions.)
Here is the code: - <!doctype html>
-
<html lang="en">
-
<head>
-
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
-
<script>
-
/*--Get the ID--*/
-
function $id(id){
-
return document.getElementById(id);
-
}
-
/*----Get the element style attributes--*/
-
function $gs(ele,attr){
-
if (ele.currentStyle)
-
{
-
return ele.currentStyle[attr];
-
}else if (ele.style[attr]!==''){
-
return ele.style[attr];
-
}else{
-
if (window.getComputedStyle(ele,null)[attr]!=='auto')
-
{
-
return window.getComputedStyle(ele,null)[attr];
-
}else{
-
return 0;
-
}
-
}
-
}
-
-
// Multi-attribute animation
-
function animate(ele,time,json,fn){
-
window.clearInterval(ele.timer);
-
var fps=60/1000;
-
ele.timer=window.setInterval(function(){
-
for (var a in json)
-
{
-
var curVal=(a.search('opacity')!==-1) ? parseFloat($gs(ele,a)) :parseInt($gs(ele,a)); // $gs 是自定义的获取元素某样式值德函数
-
var unit=(a.search('opacity')!==-1) ? '' : 'px';
-
var speed=(json[a]-curVal)/(fps*time);
-
if (speed>=0){
-
-
if (curVal>=json[a]){
-
window.clearInterval(ele.timer);
-
ele.style[a]=json[a]+unit;
-
if (fn){
-
fn();
-
}
-
}else{
-
ele.style[a]=curVal+speed+unit;
-
}
-
}else{
-
if (curVal<=json[a]+0.05){
-
window.clearInterval(ele.timer);
-
ele.style[a]=json[a]+unit;
-
if (fn){
-
fn();
-
}
-
}else{
-
ele.style[a]=curVal+speed+unit;
-
}
-
}
-
}
-
},1/fps);
-
}
-
-
</script>
-
</head>
-
<body>
-
<style>
-
#animate{width:200px;height:200px;background-color:blue;}
-
</style>
-
<div id='animate'></div>
-
-
<button id='pos'>Start the multi-attribute interaction animation </button>
-
<script>
-
$id('pos').onclick=function(){ // $id(id) is the custom function for quick retrieval of elements
-
animate($id('animate'),1000,{width:500,opacity:0},function(){
-
animate($id('animate'),1000,{width:200,opacity:1});
-
});
-
}
-
</script>
-
</body>
-
</html>
4 1932 gits 5,390
Recognized Expert Moderator Expert
well - i just reused the code that you posted to come up with a refactored version that would simply use the duration to determine and control the simultaneous animation of some properties - which i was thinking was what you were looking for. you can have a look at it and see if it fits to what you want it to behave. It has a linear animation speed and combines the properties all at once. I am sure i didn't code it for all cases that might happen - but its not intended - its just as an example how i would think that the duration would determine the animation. was hard enough to write it that 'function-like-way' anyway - since i usually would build classes for that. but that might have been confusing here - so i kept it same style as your posted code came. -
<!doctype html>
-
<html lang="en">
-
<head>
-
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
-
<script>
-
-
function $id(id){
-
return document.getElementById(id);
-
}
-
-
function getEleStyle(ele, prop) {
-
return window.getComputedStyle(ele, null).getPropertyValue(prop);
-
}
-
-
/**
-
* function animate
-
*
-
* @param ele dom-node
-
* @param duration duration in ms
-
* @param props js-obj with css props to set the values to
-
* @param cb optional callback that is called when the animation is over
-
*/
-
function animate(ele, duration, props, cb) {
-
-
// calculate how many frames we need to process for this animation
-
// note: i consider a frame as ONE interval cycle
-
var fps = 60;
-
var intervalStep = 1000/fps;
-
var framesToRenderAtAll = duration/1000 * fps;
-
var currFrame = 0;
-
-
// scale the passed props according to the frames we have to
-
// process
-
var propSteps = {};
-
-
for (var prop in props) {
-
propSteps[prop] = {};
-
-
var propStart = getEleStyle(ele, prop);
-
var pxTest = /px$/.test(propStart);
-
-
propSteps[prop].unit = pxTest ? 'px' : '';
-
propSteps[prop].curr = pxTest ? parseInt(propStart, 10) : parseFloat(propStart);
-
-
var step = (props[prop] - propSteps[prop].curr)/framesToRenderAtAll;
-
-
propSteps[prop].step = parseFloat(step.toFixed(2));
-
}
-
-
// function to set the props per animation-frame
-
var setProps = function() {
-
currFrame++;
-
-
for (var i in propSteps) {
-
propSteps[i].curr += propSteps[i].step;
-
ele.style[i] = propSteps[i].curr + propSteps[i].unit;
-
}
-
-
if (currFrame >= framesToRenderAtAll) {
-
window.clearInterval(t);
-
-
if (typeof cb != 'undefined') {
-
cb();
-
}
-
}
-
};
-
-
// instantly call first step
-
setProps();
-
-
// setting the interval to start the animation
-
var t = window.setInterval(setProps, intervalStep);
-
}
-
-
</script>
-
</head>
-
<body>
-
<style>
-
#animate{width:200px;height:200px;background-color:blue;}
-
</style>
-
<div id='animate'></div>
-
<button id='pos'>Start the multi-attribute interaction animation</button>
-
<script>
-
-
$id('pos').onclick = function() {
-
animate($id('animate'), 1000, {width:1000, opacity:0, height:100}, function() {
-
animate($id('animate'), 1000, {width:200, opacity:1, height:200});
-
});
-
}
-
-
</script>
-
</body>
-
</html>
PS: it is not as exact as it could be in determining exact steps and such - but you can improve it by more rounding floats and such where necessary.
You set the default FPS value to 60. Speed indicates the rate at which each frame will change.
However, the number of frames in a browser is not certain because of a variety of factors, and the time intervals between frames are also undefined.
The actual animation process should be calculated by the time difference between the start time and the current time.
When the animate function runs, it retrieves the start time from Date.now(). In the setInterval method, it retrieves the current time from Date.now() every time.
Calculate the proportion of the time gap “elapsed” between the two values to the animation time variable “time”, and you can get the variation proportion of the style.
I will post the code later today if I have the time.
Here is the code.
Multi-attribute animation - var interval = 1000 / 60;
-
var animate = function animate(ele, time, json, fn) {
-
if (ele.timer) return;
-
var startTime = Date.now(),
-
vals = [];
-
for (var key in json) {
-
var curVal = key.search('opacity') !== -1 ? parseFloat($gs(ele, key)) : parseInt($gs(ele, key)),
-
unit = key.search('opacity') !== -1 ? '' : 'px';
-
-
vals.push({ style: key, startVal: curVal, endVal: json[key], unit: unit });
-
}
-
-
ele.timer = setInterval(function () {
-
var elapsed = Date.now() - startTime;
-
if (elapsed >= time) {
-
clearInterval(ele.timer);
-
ele.timer = null;
-
for (var i = 0; i < vals.length; i++) {
-
ele.style[vals[i].style] = vals[i].endVal + vals[i].unit;
-
}
-
-
fn && fn();
-
} else {
-
for (var i = 0; i < vals.length; i++) {
-
ele.style[vals[i].style] = vals[i].startVal + (vals[i].endVal - vals[i].startVal) * (elapsed / time) + vals[i].unit;
-
}
-
}
-
}, interval);
-
};
-
gits 5,390
Recognized Expert Moderator Expert
well - seems viable solution as well - while i work with a constant number of frames TimoHa's solution assumes that the elapsed time isn't exactly the time of the interval - which is correct - so it can end up drawing a bit more or less calculated frames. Basically TimoHa's solution is better since it can smooth out some processing delays and such - it can be easily simulated by just placing a longer loop into the prop-setter-function - with my solution it will lead to a longer animation (constant number of frames) while the other solution determines the remaining time and adapts - so its a more constant duration.
gits 5,390
Recognized Expert Moderator Expert
here is something that can be very useful for such tasks since it explains in more detail what happens exactly and how things can be optimized especially with animations: THE EVENT LOOP
cheers,
gits
Sign in to post your reply or Sign up for a free account.
Similar topics |
by: BibhuAshish |
last post by:
Hello guys
i have one function which converts the ip/netmask into networkid/netmask and also it shows the message to user that his ip is changed to network id. but that function is working in...
|
by: Dan1701 |
last post by:
Is building a Hadoop cluster on Alibaba Cloud with CM + CDH supported?
|
by: IvanH |
last post by:
Does Alibaba Cloud ECS Automatic Backup Occupy Server Space?*
|
by: IvanH |
last post by:
Can Alibaba Cloud ECS defend against attacks?*
|
by: IvanH |
last post by:
What lines are used by Alibaba Cloud ECS?*
| |
by: IvanH |
last post by:
Does Alibaba Cloud have CDN service?
|
by: IvanH |
last post by:
Can OS be Switched or Automatically Added/Upgraded on Alibaba Cloud?
|
by: IvanH |
last post by:
https://www.decent.vip
My website uses Alibaba Cloud OSS and Alibaba Cloud CDN for Wordpress.It said I can visit this page but it returns a 403 error. And the icon is not there. What can I do?
|
by: IvanH |
last post by:
unable to access the instance remotely using rdp on Alibaba Cloud ECS, please help.
|
by: IvanH |
last post by:
How Can I Migrate from F(x) Data Cloud to Alibaba Cloud when I do web hosting?
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
| |
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
|
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...
| |