By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,364 Members | 1,343 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,364 IT Pros & Developers. It's quick & easy.

Using an animation function written in native JavaScript on Alibaba Cloud

P: 51
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:
Expand|Select|Wrap|Line Numbers
  1. <!doctype html>
  2.     <html lang="en">
  3.      <head>
  4.    <meta http-equiv='content-type' content='text/html;charset=utf-8' />
  5.       <script>
  6.     /*--Get the ID--*/
  7.     function $id(id){
  8.       return document.getElementById(id);
  9.     }
  10.     /*----Get the element style attributes--*/
  11.     function $gs(ele,attr){
  12.        if (ele.currentStyle)
  13.          {
  14.            return ele.currentStyle[attr];
  15.          }else if (ele.style[attr]!==''){
  16.               return ele.style[attr];
  17.          }else{
  18.           if (window.getComputedStyle(ele,null)[attr]!=='auto')
  19.            {
  20.              return window.getComputedStyle(ele,null)[attr];
  21.            }else{
  22.              return 0;
  23.            }
  24.          }
  25.     } 
  26.  
  27.         // Multi-attribute animation
  28.         function animate(ele,time,json,fn){
  29.            window.clearInterval(ele.timer);
  30.            var fps=60/1000;
  31.            ele.timer=window.setInterval(function(){
  32.               for (var a in json)
  33.                {
  34.                  var curVal=(a.search('opacity')!==-1) ? parseFloat($gs(ele,a)) :parseInt($gs(ele,a)); // $gs 是自定义的获取元素某样式值德函数
  35.                  var unit=(a.search('opacity')!==-1) ? '' : 'px';
  36.                  var speed=(json[a]-curVal)/(fps*time);
  37.                  if (speed>=0){
  38.  
  39.                    if (curVal>=json[a]){
  40.                      window.clearInterval(ele.timer);
  41.                      ele.style[a]=json[a]+unit;
  42.                      if (fn){
  43.                        fn();
  44.                      }
  45.                    }else{
  46.                      ele.style[a]=curVal+speed+unit;
  47.                    }
  48.                  }else{
  49.                    if (curVal<=json[a]+0.05){
  50.                      window.clearInterval(ele.timer);
  51.                      ele.style[a]=json[a]+unit;
  52.                      if (fn){
  53.                        fn();
  54.                      }
  55.                    }else{
  56.                      ele.style[a]=curVal+speed+unit;
  57.                    }
  58.                  }
  59.                }
  60.            },1/fps);
  61.         }
  62.  
  63.      </script>
  64.      </head>
  65.      <body>
  66.        <style>
  67.          #animate{width:200px;height:200px;background-color:blue;}
  68.        </style>
  69.        <div id='animate'></div>
  70.  
  71.        <button id='pos'>Start the multi-attribute interaction animation </button>
  72.        <script>
  73.          $id('pos').onclick=function(){  // $id(id) is the custom function for quick retrieval of elements
  74.            animate($id('animate'),1000,{width:500,opacity:0},function(){
  75.              animate($id('animate'),1000,{width:200,opacity:1});
  76.            });
  77.          }
  78.        </script>
  79.      </body>
  80.     </html>
Apr 20 '18 #1
Share this Question
Share on Google+
4 Replies


gits
Expert Mod 5K+
P: 5,389
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.

Expand|Select|Wrap|Line Numbers
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4.     <meta http-equiv='content-type' content='text/html;charset=utf-8' />
  5.     <script>
  6.  
  7.     function $id(id){
  8.         return document.getElementById(id);
  9.     }
  10.  
  11.     function getEleStyle(ele, prop) {
  12.         return window.getComputedStyle(ele, null).getPropertyValue(prop);
  13.     }
  14.  
  15.     /**
  16.      * function animate
  17.      *
  18.      * @param ele dom-node
  19.      * @param duration duration in ms
  20.      * @param props js-obj with css props to set the values to
  21.      * @param cb optional callback that is called when the animation is over
  22.      */
  23.     function animate(ele, duration, props, cb) {
  24.  
  25.         // calculate how many frames we need to process for this animation
  26.         // note: i consider a frame as ONE interval cycle
  27.         var fps = 60;
  28.         var intervalStep = 1000/fps;
  29.         var framesToRenderAtAll = duration/1000 * fps;
  30.         var currFrame = 0;
  31.  
  32.         // scale the passed props according to the frames we have to 
  33.         // process
  34.         var propSteps = {};
  35.  
  36.         for (var prop in props) {
  37.             propSteps[prop] = {};
  38.  
  39.             var propStart = getEleStyle(ele, prop);
  40.             var pxTest = /px$/.test(propStart);
  41.  
  42.             propSteps[prop].unit = pxTest ? 'px' : '';
  43.             propSteps[prop].curr = pxTest ? parseInt(propStart, 10) : parseFloat(propStart);
  44.  
  45.             var step = (props[prop] - propSteps[prop].curr)/framesToRenderAtAll;
  46.  
  47.             propSteps[prop].step = parseFloat(step.toFixed(2));
  48.         }
  49.  
  50.         // function to set the props per animation-frame    
  51.         var setProps = function() {
  52.             currFrame++;
  53.  
  54.             for (var i in propSteps) {
  55.                 propSteps[i].curr += propSteps[i].step;
  56.                 ele.style[i] = propSteps[i].curr + propSteps[i].unit;
  57.             }
  58.  
  59.             if (currFrame >= framesToRenderAtAll) {
  60.                 window.clearInterval(t);
  61.  
  62.                 if (typeof cb != 'undefined') {
  63.                     cb();
  64.                 }
  65.             }
  66.         };
  67.  
  68.         // instantly call first step
  69.         setProps();
  70.  
  71.         // setting the interval to start the animation
  72.         var t = window.setInterval(setProps, intervalStep);
  73.     }
  74.  
  75.     </script>
  76. </head>
  77. <body>
  78.     <style>
  79.         #animate{width:200px;height:200px;background-color:blue;}
  80.     </style>
  81.     <div id='animate'></div>
  82.     <button id='pos'>Start the multi-attribute interaction animation</button>
  83.     <script>
  84.  
  85.     $id('pos').onclick = function() {
  86.         animate($id('animate'), 1000, {width:1000, opacity:0, height:100}, function() {
  87.             animate($id('animate'), 1000, {width:200, opacity:1, height:200});
  88.         });
  89.     }
  90.  
  91.     </script>
  92. </body>
  93. </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.
Apr 20 '18 #2

P: 22
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
Expand|Select|Wrap|Line Numbers
  1. var interval = 1000 / 60;
  2. var animate = function animate(ele, time, json, fn) {
  3.     if (ele.timer) return;
  4.     var startTime = Date.now(),
  5.         vals = [];
  6.     for (var key in json) {
  7.         var curVal = key.search('opacity') !== -1 ? parseFloat($gs(ele, key)) : parseInt($gs(ele, key)),
  8.             unit = key.search('opacity') !== -1 ? '' : 'px';
  9.  
  10.         vals.push({ style: key, startVal: curVal, endVal: json[key], unit: unit });
  11.     }
  12.  
  13.     ele.timer = setInterval(function () {
  14.         var elapsed = Date.now() - startTime;
  15.         if (elapsed >= time) {
  16.             clearInterval(ele.timer);
  17.             ele.timer = null;
  18.             for (var i = 0; i < vals.length; i++) {
  19.                 ele.style[vals[i].style] = vals[i].endVal + vals[i].unit;
  20.             }
  21.  
  22.             fn && fn();
  23.         } else {
  24.             for (var i = 0; i < vals.length; i++) {
  25.                 ele.style[vals[i].style] = vals[i].startVal + (vals[i].endVal - vals[i].startVal) * (elapsed / time) + vals[i].unit;
  26.             }
  27.         }
  28.     }, interval);
  29. };
  30.  
Apr 23 '18 #3

gits
Expert Mod 5K+
P: 5,389
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.
Apr 23 '18 #4

gits
Expert Mod 5K+
P: 5,389
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
May 22 '18 #5

Post your reply

Sign in to post your reply or Sign up for a free account.