{"id":782,"date":"2016-06-01T15:00:05","date_gmt":"2016-06-01T20:00:05","guid":{"rendered":"http:\/\/rpchurchill.com\/?p=782"},"modified":"2017-02-03T15:06:00","modified_gmt":"2017-02-03T20:06:00","slug":"reproducing-a-clever-animation-product-part-2","status":"publish","type":"post","link":"https:\/\/rpchurchill.com\/wordpress\/posts\/2016\/06\/01\/reproducing-a-clever-animation-product-part-2\/","title":{"rendered":"Reproducing A Clever Animation Product, Part 2"},"content":{"rendered":"<p>Today I did some experiments to try to figure out why the animations I&#8217;ve created seem to hitch and hiccup slightly from time to time.  Again, this work is based on recreating the basic functionality of the Greensock animation product described <a href=\"http:\/\/greensock.com\/\">here<\/a> and especially <a href=\"http:\/\/greensock.com\/sequence-video\">here<\/a>.<\/p>\n<p>The first thing I thought of was that the drawing operations themselves might be taking long enough that they don&#8217;t complete during every animation step (about 16 ms at 60 frames per second).  I therefore set the update loop to only draw the items every other scan.  This approach didn&#8217;t relieve the hitching and updating at 30 fps left the animation looking slightly choppy.<\/p>\n<p><iframe loading=\"lazy\" width=\"325px\" height=\"290px\" src=\"https:\/\/www.rpchurchill.com\/demo\/animation\/animation_demo_20160601a.html\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>The next thing I tried was recording the elapsed time for every drawing loop and displaying the value if it was greater than 16 ms.  However, the value was never displayed, so it appears that the speed of the drawing isn&#8217;t an issue.<\/p>\n<p><iframe loading=\"lazy\" width=\"325px\" height=\"320px\" src=\"https:\/\/www.rpchurchill.com\/demo\/animation\/animation_demo_20160601b.html\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>Next it occurred to me that if an element has to travel far enough and in fine enough increments that the difference between traveling three or four pixels in an update, particularly when advancing by the smaller number doesn&#8217;t happen often, might be enough to look like a hitch.  I therefore set the durations of the transitions to be shorter so each increment is larger, and I also incorporated a fade-in by ramping up the opacity.  The combination of these two changes made things look pretty smooth.<\/p>\n<p><iframe loading=\"lazy\" width=\"325px\" height=\"320px\" src=\"https:\/\/www.rpchurchill.com\/demo\/animation\/animation_demo_20160601c.html\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>I also observe that the example animation in the second Greensock link, above, involves transitions that are relatively short, so there isn&#8217;t time for anything to hitch.  That may be the key to the whole enterprise.  That said, there&#8217;s an animation in the first link that shows a fountain of green balls.  I will try to reproduce something like that and see how it looks.  Most of the effects can be replicated (though perhaps not as well as the originals), and I&#8217;ll be working through duplicating some of them over the next few posts.<\/p>\n<p>In the meantime, I found it necessary to add an initialization capability so rerunning the animation starts from a good place.  Here&#8217;s the basic code in its entirety.<\/p>\n<pre class=\"toolbar-overlay:false wrap:false height-set:true lang:default decode:true \">\r\n<!DOCTYPE html>\r\n<html>\r\n  <head>\r\n  \t<title>Fast Animation Script Demo<\/title>\r\n    <link type=\"text\/css\" rel=\"stylesheet\" href=\"..\/stylesheet.css\"\/>\r\n\r\n    <script type=\"text\/javascript\" src=\"jquery.min.js\">\r\n    <\/script>\r\n\r\n    <style>\r\n      .demo {\r\n        height: 200px;\r\n        width: 300px;\r\n        margin-left: auto;\r\n        margin-right: auto;\r\n        background-color: #222222;\r\n        display: block;\r\n        overflow: hidden;\r\n        position: relative;\r\n      }\r\n      .demoPanel {\r\n        position: absolute;\r\n        background-color: rgba(0,0,0,0);\r\n        color: #EEEEEE;\r\n        font-size: 1.2em;\r\n      }\r\n      #rerun_button {\r\n        margin-left: auto;\r\n        margin-right: auto;\r\n        display: block;        \r\n      }\r\n    <\/style>\r\n  <\/head>\r\n  <body>\r\n    <div class=\"demo\">\r\n      <div id=\"handle001\" class=\"demoPanel\"><\/div>\r\n      <div id=\"handle002\" class=\"demoPanel\"><\/div>\r\n    <\/div>\r\n    <br \/>\r\n    <button id=\"rerun_button\" onclick=\"rerunClick()\" style=\"height: 50px; width: 300px\">Rerun the Animation<\/button>\r\n    <br \/>\r\n    <p id=\"elapsedElement\"><\/p>\r\n    <script>\r\n      \/\/specify element\r\n      \/\/specify initial properties\r\n      \/\/specify final properties\r\n      \/\/specify duration\r\n      \/\/specify start time\r\n      \/\/build list of commands that run for every animation call\r\n      \r\n      var bcActivitiesList = new Array;\r\n      for (var i=0; i<1800; i++) {  \/\/>\r\n        bcActivitiesList[i] = new Array;\r\n        bcActivitiesList[i][0] = 0;  \/\/number of commands each animation step\r\n      }  \/\/30 seconds of activities\r\n      var bcFinalActivity = -1;  \/\/index of last animation activity\r\n      \r\n      var bcInitializations = new Array;\r\n      bcInitializations[0] = 0;\r\n\r\n      function bcInitElement(pElement,pLeft,pTop,pColor,pBackgroundColor,pWidth,pOpacity,pDisplay,innerHTML) {\r\n        pElement.style.left = pLeft;\r\n        pElement.style.top = pTop;\r\n        pElement.style.color = pColor;\r\n        pElement.style.backgroundColor = pBackgroundColor;\r\n        pElement.style.width = pWidth;\r\n        pElement.style.opacity = pOpacity;\r\n        pElement.style.display = pDisplay;\r\n        pElement.innerHTML = innerHTML;\r\n      }\r\n      function bcDefineLeftTween(sElement,pStart,pEnd,tBegin,tDuration,mMethod) {\r\n        var s = sElement+\".style.left='\"+pStart+\"px';\"\r\n        bcInitializations[0] = bcInitializations.push(s);\r\n        var alpha = tBegin * 60.0;\r\n        var steps = tDuration * 60;\r\n        var omega = alpha + steps;\r\n        var increment = (pEnd - pStart) \/ steps;\r\n        var left = pStart;\r\n        for (var i=alpha; i<=omega; i++) { \/\/>\r\n          s = sElement+\".style.left='\"+Math.round(left)+\"px';\"\r\n          bcActivitiesList[i][0] = bcActivitiesList[i].push(s);\r\n          if (mMethod == \"linear\") {\r\n            left += increment;\r\n          }\r\n        }  \r\n        if (omega > bcFinalActivity) {\r\n          bcFinalActivity = omega;\r\n        }\r\n      }\r\n      function bcDefineTopTween(sElement,pStart,pEnd,tBegin,tDuration,mMethod) {\r\n        var s = sElement+\".style.top='\"+pStart+\"px';\"\r\n        bcInitializations[0] = bcInitializations.push(s);\r\n        var alpha = tBegin * 60.0;\r\n        var steps = tDuration * 60;\r\n        var omega = alpha + steps;\r\n        var increment = (pEnd - pStart) \/ steps;\r\n        var top = pStart;\r\n        for (var i=alpha; i<=omega; i++) { \/\/>\r\n          s = sElement+\".style.top='\"+Math.round(top)+\"px';\"\r\n          bcActivitiesList[i][0] = bcActivitiesList[i].push(s);\r\n          if (mMethod == \"linear\") {\r\n            top += increment;\r\n          }\r\n        }  \r\n        if (omega > bcFinalActivity) {\r\n          bcFinalActivity = omega;\r\n        }\r\n      }\r\n      function bcDefineOpacityTween(sElement,pStart,pEnd,tBegin,tDuration,mMethod) {\r\n        var s = sElement+\".style.opacity='\"+pStart+\"';\"\r\n        bcInitializations[0] = bcInitializations.push(s);\r\n        var alpha = tBegin * 60.0;\r\n        var steps = tDuration * 60;\r\n        var omega = alpha + steps;\r\n        var increment = (pEnd - pStart) \/ steps;\r\n        var opacity = pStart;\r\n        for (var i=alpha; i<=omega; i++) { \/\/>\r\n          s = sElement+\".style.opacity='\"+opacity+\"';\"\r\n          bcActivitiesList[i][0] = bcActivitiesList[i].push(s);\r\n          if (mMethod == \"linear\") {\r\n            opacity += increment;\r\n          }\r\n        }  \r\n        if (omega > bcFinalActivity) {\r\n          bcFinalActivity = omega;\r\n        }\r\n      }\r\n      \r\n      function bcInitializeElements() {\r\n        var i = 1;\r\n        while (i <= bcInitializations[0]) {  \/\/>\r\n          eval(bcInitializations[i]);\r\n          i++;\r\n        }\r\n      }\r\n      \r\n      var elapsedHandle = document.getElementById(\"elapsedElement\");\r\n      function doSomeStuff(step) {\r\n        var startTime = Date.now();\r\n        var i = 1;\r\n        while (i <= bcActivitiesList[step][0]) {  \/\/>\r\n          eval(bcActivitiesList[step][i]);\r\n          i++;\r\n        }\r\n        var endTime = Date.now();\r\n        var elapsed = endTime - startTime;\r\n        if (elapsed > 16) {\r\n          elapsedHandle.innerHTML = elapsed;\r\n        } else {\r\n          elapsedHandle.innerHTML = \"\";\r\n        }\r\n      } \r\n      \r\n      var handle001 = document.getElementById(\"handle001\");\r\n      bcInitElement(handle001,\"201px\",\"50px\",\"red\",\"rgba(0,0,0,0)\",\"260px\",1,\"block\",\"This line slides in from the side\");\r\n      bcDefineLeftTween(\"handle001\",301,25,0.0,0.75,\"linear\");\r\n      bcDefineOpacityTween(\"handle001\",0.0,1.0,0.0,0.75,\"linear\")\r\n      \r\n      var handle002 = document.getElementById(\"handle002\");\r\n      bcInitElement(handle002,\"13px\",\"-25px\",\"blue\",\"rgba(0,0,0,0)\",\"280px\",1,\"block\",\"This line drops down from the top\");\r\n      bcDefineTopTween(\"handle002\",-25,125,0.5,0.75,\"linear\");\r\n      bcDefineOpacityTween(\"handle002\",0.0,1.0,0.5,0.75,\"linear\")\r\n      \r\n      var maxAnimationSteps = bcFinalActivity;\r\n\r\n      bcInitializeElements();\r\n      var animationStep = 0;\r\n      var requestId;\r\n      function animateSomeStuff() {\r\n        doSomeStuff(animationStep);\r\n        if (animationStep >= maxAnimationSteps) {\r\n          cancelAnimationFrame(requestID);\r\n        } else {\r\n          animationStep++;\r\n        } \r\n        requestId = window.requestAnimationFrame(animateSomeStuff);      \r\n      }\r\n      animateSomeStuff();\r\n      \r\n      function rerunClick() {  \/\/called on button click\r\n        animationStep = 0;\r\n        bcInitializeElements();\r\n        animateSomeStuff();\r\n      }\r\n      \r\n\r\n    <\/script>\r\n  <\/body>\r\n<\/html>\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Today I did some experiments to try to figure out why the animations I&#8217;ve created seem to hitch and hiccup slightly from time to time. Again, this work is based on recreating the basic functionality of the Greensock animation product &hellip; <a href=\"https:\/\/rpchurchill.com\/wordpress\/posts\/2016\/06\/01\/reproducing-a-clever-animation-product-part-2\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[87,101,49],"_links":{"self":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/782"}],"collection":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/comments?post=782"}],"version-history":[{"count":4,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/782\/revisions"}],"predecessor-version":[{"id":1467,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/posts\/782\/revisions\/1467"}],"wp:attachment":[{"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/media?parent=782"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/categories?post=782"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rpchurchill.com\/wordpress\/wp-json\/wp\/v2\/tags?post=782"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}