SlideShare a Scribd company logo
1 of 87
Download to read offline
Thomas Fuchs



   Roll your own
    JavaScript
Effects Framework
   (and introducing Émile)
Émile Cohl
“The father of the animated cartoon”




                                 http://en.wikipedia.org/wiki/File:Young_Emile_Cohl.jpg
http://www.youtube.com/watch?v=aEAObel8yIE
Animation & visual effects on
webpages are superfluous and
 don’t add anything useful.
Animation & visual effects on
 webpages are superfluous,
  don’t add anything useful
  and are totally awesome.
Animation & visual effects on
 webpages are superfluous,
  don’t add anything useful
  and are totally awesome.
       what’s important to the user?
emile.js


Simple (<50 lines of code)
     CSS animations
 Timing, chaining, easing
      Stand-alone



http://github.com/madrobby/emile
//  emile.js  (c)  2009  Thomas  Fuchs
//  Licensed  under  the  terms  of  the  MIT  license.

(function(emile,  object){
    var  parseEl  =  document.createElement('div'),
        props  =  ('backgroundColor  borderBottomColor  borderBottomWidth  borderLeftColor  borderLeftWidth  '+
        'borderRightColor  borderRightWidth  borderSpacing  borderTopColor  borderTopWidth  bottom  color  fontSize  '+
        'fontWeight  height  left  letterSpacing  lineHeight  marginBottom  marginLeft  marginRight  marginTop  maxHeight  '+
        'maxWidth  minHeight  minWidth  opacity  outlineColor  outlineOffset  outlineWidth  paddingBottom  paddingLeft  '+
        'paddingRight  paddingTop  right  textIndent  top  width  wordSpacing  zIndex').split('  ');

    function  parse(value){
        var  v  =  parseFloat(value),  u  =  value.replace(/^[d.]+/,'');
        return  {  value:  isNaN(v)  ?  u  :  v,  unit:  isNaN(v)  ?  'color'  :  u  };
    }

    function  normalize(style){
        var  css,  rules  =  {},  i  =  props.length,  v;
        parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
        css  =  parseEl.childNodes[0].style;
        while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  parse(v);
        return  rules;
    }
    
    function  color(source,target,pos){
        var  i  =  2,  j,  c,  v  =  [],  r  =  [];
        while(i-­‐-­‐)  
            if(arguments[i][0]=='r'){
                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));
            }  else  {
                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));
            }
        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }
        return  'rgb('+r.join(',')+')';
    }
    
    (object||window)[emile]  =  function(el,  style,  opts){
        el  =  typeof  el  ==  'string'  ?  document.getElementById(el)  :  el;
        opts  =  opts  ||  {};
        var  target  =  normalize(style),  comp  =  el.currentStyle  ?  el.currentStyle  :  document.defaultView.getComputedStyle(el,  null),
            prop,  current  =  {},  start  =  (new  Date).getTime(),  dur  =  opts.duration||200,  finish  =  start+dur,  interval;
        for(prop  in  target)  current[prop]  =  parse(comp[prop]);
        interval  =  setInterval(function(){
            var  time  =  (new  Date).getTime(),  delta  =  time>finish  ?  1  :  (time-­‐start)/dur;
            for(prop  in  target)
                el.style[prop]  =  target[prop].unit  ==  'color'  ?
                    color(current[prop].value,target[prop].value,delta)  :  
                    (current[prop].value+(target[prop].value-­‐current[prop].value)*delta).toFixed(3)  +  target[prop].unit;
            if(time>finish)  {  clearInterval(interval);  opts.after  &&  opts.after();  }
        },10);
    }
})('emile');
Wait, hold it!
Why write something
 new from scratch?
JavaScript frameworks



•   “Best thing since sliced bread”
•   Help you get stuff done more easily
•   “Make JavaScript enjoyable”
•   Fix cross-browser issues
JavaScript frameworks (BUT)



•   Cover too much or too little
•   Component and plugin hell
•   Lead to uniformity
•   Keep JavaScript away from you
JavaScript frameworks (BUT BUT)



 •   Learn from them for your own code
 •   Pick parts you need
 •   Extend them for good or evil
 •   Be a JavaScript god/ninja/cowboy etc.
Animation! (what you came for)



•   What to use for timing
•   How to conquer CSS
•   Performance?
•   And how to make it really nice
Move a block from left to right and back
Move a block from left to right and back
Using a for loop


for  (var  i  =  0;  i  <  1000;  i++)
    element.style.left  =  i  +  'px';

for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)
    element.style.left  =  j  +  'px';
Using a for loop

                        moves block to right
for  (var  i  =  0;  i  <  1000;  i++)
    element.style.left  =  i  +  'px';

for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)
    element.style.left  =  j  +  'px';



      moves block back to left
Using a for loop


for  (var  i  =  0;  i  <  1000;  i++)
    element.style.left  =  i  +  'px';

for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)
    element.style.left  =  j  +  'px';


       surprise, this does
         nothing at all!
JavaScript and the browser
rendering engine share a single
     thread of execution.

  While the code is running,
  no rendering will happen.
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);
setInterval
             1 = positive, -1 = negative
var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);

              call this function
                 every 10ms
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);

      increase or decrease the index
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);


   reverse direction once we reach 1000
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);


               set the style
setInterval

var  direction  =  1,  i  =  0,  
    interval  =  setInterval(function(){
        i  +=  direction;
        if(i  ==  1000)  direction  =  -­‐1;
        element.style.left  =  i  +  'px';
        if(i  <  0)  clearInterval(interval);  
    },10);


     stop doing the animation when
        the index drops below 0
Much better, as in, there’s
actually some animation going on.
But, there’s a problem:
it’s hardly exact timing to use the
           10ms interval.

 Not all users have the super-fast
       laptops you all have,
or maybe they’re looking at it on a
          mobile browser.
(new  Date).getTime()
 1257185326039


   milliseconds since epoch
(January 1, 1970 00:00:00 UTC)
Epoch FTW

<div  id="test"  style="position:absolute">test</div>

<script  type="text/javascript"  charset="utf-­‐8">
var  element  =  document.getElementById('test');

var  start  =  (new  Date).getTime(),  duration  =  1000,  
    finish  =  start+duration;
    
var  interval  =  setInterval(function(){
    var  time  =  (new  Date).getTime(),  
        pos  =  time>finish  ?  1  :  (time-­‐start)/duration;
    element.style.left  =  (1000*pos)  +  'px';        
    if(time>finish)  clearInterval(interval);
},10);
</script>
Epoch FTW

<div  id="test"  style="position:absolute">test</div>

<script  type="text/javascript"  charset="utf-­‐8">
var  element  =  document.getElementById('test');

var  start  =  (new  Date).getTime(),  duration  =  1000,  
    finish  =  start+duration;
    
var  interval  =  setInterval(function(){
    var  time  =  (new  Date).getTime(),  
        pos  =  time>finish  ?  1  :  (time-­‐start)/duration;
    element.style.left  =  (1000*pos)  +  'px';        
    if(time>finish)  clearInterval(interval);
},10);
</script>
           starts now, calculate finish time from
              duration (for now one second)
Epoch FTW

<div  id="test"  style="position:absolute">test</div>

<script  type="text/javascript"  charset="utf-­‐8">
var  element  =  document.getElementById('test');

var  start  =  (new  Date).getTime(),  duration  =  1000,  
    finish  =  start+duration;
    
var  interval  =  setInterval(function(){
    var  time  =  (new  Date).getTime(),  
        pos  =  time>finish  ?  1  :  (time-­‐start)/duration;
    element.style.left  =  (1000*pos)  +  'px';        
    if(time>finish)  clearInterval(interval);
},10);
</script>
            calculate a position between 0 and 1
            (0 = start of effect, 1 = end of effect)
“pos” is 0 at the animation’s start,
     1 at the animation’s end


  0                                               1
                        t


   var  time  =  (new  Date).getTime(),  
             pos  =  time>finish  ?  
                 1  :  (time-­‐start)/duration;
var  time  =  (new  Date).getTime(),  
          pos  =  time>finish  ?  
              1  :  (time-­‐start)/duration;
var  time  =  (new  Date).getTime(),  
          pos  =  time>finish  ?  
              1  :  (time-­‐start)/duration;
              start = 6039
      duration = 1000 (1 second)
    finish = start + duration = 7039
          current time = 6539
var  time  =  (new  Date).getTime(),  
          pos  =  time>finish  ?  
              1  :  (time-­‐start)/duration;
              start = 6039
      duration = 1000 (1 second)
    finish = start + duration = 7039
          current time = 6539

         what’s pos at 6539?
       6039               7039
                 t
var  time  =  (new  Date).getTime(),  
          pos  =  time>finish  ?  
              1  :  (time-­‐start)/duration;
              start = 6039
      duration = 1000 (1 second)
    finish = start + duration = 7039
          current time = 6539

         what’s pos at 6539?
       6039               7039
                 t

        (time-start)/duration =
         (6539-6039)/1000 =
              500/1000
                 = 0.5
Epoch FTW

<div  id="test"  style="position:absolute">test</div>

<script  type="text/javascript"  charset="utf-­‐8">
var  element  =  document.getElementById('test');

var  start  =  (new  Date).getTime(),  duration  =  1000,  
    finish  =  start+duration;
    
var  interval  =  setInterval(function(){
    var  time  =  (new  Date).getTime(),  
        pos  =  time>finish  ?  1  :  (time-­‐start)/duration;
    element.style.left  =  (1000*pos)  +  'px';        
    if(time>finish)  clearInterval(interval);
},10);
</script>
             use the position to
             calculate the style
The core loop is complete,
  but supporting only the
CSS “left” property is boring.

  So how do we query/set
   more CSS properties?
“It depends.”
Reading CSS properties


                               IE
computedStyle  =  
    element.currentStyle  ?  element.currentStyle  :  
        document.defaultView.getComputedStyle(element,  null);




                             DOM


      My thinking is, IE’s currentStyle
        property is more elegant.
However:


>  element.style.border  =  "2px  solid  green";
2px  solid  green

>  document.defaultView.getComputedStyle(element,null).border




           nothing returned?
However:

>  element.style.border  =  "2px  solid  green";
2px  solid  green

>  document.defaultView.getComputedStyle(element,null).border


>  document.defaultView.getComputedStyle(element,null).borderLeftWidth
2px

>  document.defaultView.getComputedStyle(element,null).borderLeftColor
rgb(0,  128,  0)


                                        shorthand properties
 colors are                                are expanded
normalized
This means, to transform from

  border:2px  solid  green;

             to

 border:17px  solid  #f056eb;

We need to expand/normalize
    the target properties.
Normalizing CSS properties
Normalizing CSS properties

var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
Normalizing CSS properties
   create a DIV, to give the browser the hard work
var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
Normalizing CSS properties
              define a list of possible properties
var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
Normalizing CSS properties

var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
              create a new element with
    the CSS properties we want to have normalized
Normalizing CSS properties

var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
            like getComputedStyle(), the style
              property of an element contains
                 normalized CSS properties
Normalizing CSS properties

var  parseEl  =  document.createElement('div'),
    props  =  ('backgroundColor  borderBottomColor  '+
      //  imagine  more  lines  with  more  CSS  properties  here
      'width  wordSpacing  zIndex').split('  ');

function  normalize(style){
    var  css,  rules  =  {},  i  =  props.length,  v;
    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';
    css  =  parseEl.childNodes[0].style;
    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;
    return  rules;
}
   slightly optimized way of “for all properties on
   our list, check if it’s defined, and if yes, add it to
                     the rules object”
Interpolating values
and colors from A to B
Interpolating between
         two CSS values

origin  +  difference  ×  position
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
        target  =  ‘20px’
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
        target  =  ‘20px’
        position  =  0.5
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
        target  =  ‘20px’
        position  =  0.5

        12  +  (20-­‐12)  ×  0.5  =
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
        target  =  ‘20px’
        position  =  0.5

        12  +  (20-­‐12)  ×  0.5  =
        12  +  8  ×  0.5  =
Interpolating between
         two CSS values

origin  +  difference  ×  position

        origin  =  ‘12px’
        target  =  ‘20px’
        position  =  0.5

        12  +  (20-­‐12)  ×  0.5  =
        12  +  8  ×  0.5  =
        12  +  4  =  16
Interpolating between two colors

    function  color(source,target,pos){
        var  i  =  2,  j,  c,  tmp,  v  =  [],  r  =  [];
        while(i-­‐-­‐)  
            if(arguments[i][0]=='r'){
                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));
            }  else  {
                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));
            }
        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }
        return  'rgb('+r.join(',')+')';
    }




             looks complicated, but it really only is
                  interpolating for each color
                 component (red, green, blue)
                          individually.
Also...

    function  color(source,target,pos){
        var  i  =  2,  j,  c,  tmp,  v  =  [],  r  =  [];
        while(i-­‐-­‐)  
            if(arguments[i][0]=='r'){
                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));
            }  else  {
                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));
            }
        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }
        return  'rgb('+r.join(',')+')';
    }




                     This JavaScript snippet is
                   optimized for code size, not for
                  readability. It could be expressed
                       much more elegantly.
JavaScript numbers

>  0.1
0.1
>  0.0001
0.0001
>  0.0000001
1e-­‐7
               string representation
JavaScript numbers

       font-­‐size:  1e-­‐7px
      doesn’t work in CSS


      number.toFixed(3)
toFixed(3) round the number to
     3 decimal places and
     and prevents an error
Optimizing rendering speed
Reduce the amount
of nodes (HTML elements
   and text nodes) and
     avoid using the
 “opacity” CSS property.
And finally... easing.
“pos” is 0 at the animation’s start,
     1 at the animation’s end



   var  time  =  (new  Date).getTime(),  
       pos  =  time>finish  ?  
           1  :  (time-­‐start)/duration;
No easing




pos
      t
No easing
                         sudden change
                           in velocity
                             at end




  sudden change
in velocity at start
Easing is nothing
      more than messing with “pos”


    emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {
        duration:  500,
        after:  function(){
            emile('test1',  'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {  
                duration:  4000,  easing:  bounce
            });
        }
    });
No easing looks unnatural.

Things move by accelerating
 and stop by decelerating.
(-Math.cos(pos*Math.PI)/2) + 0.5




    pos
          t
(-Math.cos(pos*Math.PI)/2) + 0.5




    pos
          t
(-Math.cos(pos*Math.PI)/2) + 0.5

                       deceleration
                          at end




   acceleration
     at start
A “bounce” easing




pos
      t
A “bounce” easing




pos
      t
A “bounce” easing

                hard velocity
                  changes




    quadratic
    “gravity”
A “bounce” easing


  function  bounce(pos)  {
        if  (pos  <  (1/2.75))  {
                return  (7.5625*pos*pos);
        }  else  if  (pos  <  (2/2.75))  {
                return  (7.5625*(pos-­‐=(1.5/2.75))*pos  +  .75);
        }  else  if  (pos  <  (2.5/2.75))  {
                return  (7.5625*(pos-­‐=(2.25/2.75))*pos  +  .9375);
        }  else  {
                return  (7.5625*(pos-­‐=(2.625/2.75))*pos  +  .984375);
        }
    }
   emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {
        duration:  500,
        after:  function(){
            emile('test1',  
                'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {  
                duration:  4000,  easing:  bounce
            });
        }
    });
   emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {
        duration:  500,
        after:  function(){
            emile('test1',  
                'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {  
                duration:  4000,  easing:  bounce
            });
        }
    });
Easing animated CSS
properties individually
propertyTransitions:  {  
       marginLeft:  'mirror',  
       marginTop:  'bouncePast',  
       left:  'swingFromTo',  
       zIndex:  zIndexTransition  
   }


scripty2 code – Not supported by Émile,
    too specialized. But easy to add.
scripty2 has tons of easings you
can lift and use in your own apps




                      Demo them at
                     http://tr.im/E0JS
Q&A
           And thanks!

http://github.com/madrobby/emile
        http://scripty2.com/

Slides: http://mir.aculo.us/ (soon)

More Related Content

Recently uploaded

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 

Recently uploaded (20)

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Émile - a JavaScript animation framework in 50 lines of code

  • 1. Thomas Fuchs Roll your own JavaScript Effects Framework (and introducing Émile)
  • 2. Émile Cohl “The father of the animated cartoon” http://en.wikipedia.org/wiki/File:Young_Emile_Cohl.jpg
  • 4. Animation & visual effects on webpages are superfluous and don’t add anything useful.
  • 5. Animation & visual effects on webpages are superfluous, don’t add anything useful and are totally awesome.
  • 6. Animation & visual effects on webpages are superfluous, don’t add anything useful and are totally awesome. what’s important to the user?
  • 7. emile.js Simple (<50 lines of code) CSS animations Timing, chaining, easing Stand-alone http://github.com/madrobby/emile
  • 8. //  emile.js  (c)  2009  Thomas  Fuchs //  Licensed  under  the  terms  of  the  MIT  license. (function(emile,  object){    var  parseEl  =  document.createElement('div'),        props  =  ('backgroundColor  borderBottomColor  borderBottomWidth  borderLeftColor  borderLeftWidth  '+        'borderRightColor  borderRightWidth  borderSpacing  borderTopColor  borderTopWidth  bottom  color  fontSize  '+        'fontWeight  height  left  letterSpacing  lineHeight  marginBottom  marginLeft  marginRight  marginTop  maxHeight  '+        'maxWidth  minHeight  minWidth  opacity  outlineColor  outlineOffset  outlineWidth  paddingBottom  paddingLeft  '+        'paddingRight  paddingTop  right  textIndent  top  width  wordSpacing  zIndex').split('  ');    function  parse(value){        var  v  =  parseFloat(value),  u  =  value.replace(/^[d.]+/,'');        return  {  value:  isNaN(v)  ?  u  :  v,  unit:  isNaN(v)  ?  'color'  :  u  };    }    function  normalize(style){        var  css,  rules  =  {},  i  =  props.length,  v;        parseEl.innerHTML  =  '<div  style="'+style+'"></div>';        css  =  parseEl.childNodes[0].style;        while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  parse(v);        return  rules;    }        function  color(source,target,pos){        var  i  =  2,  j,  c,  v  =  [],  r  =  [];        while(i-­‐-­‐)              if(arguments[i][0]=='r'){                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));            }  else  {                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));            }        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }        return  'rgb('+r.join(',')+')';    }        (object||window)[emile]  =  function(el,  style,  opts){        el  =  typeof  el  ==  'string'  ?  document.getElementById(el)  :  el;        opts  =  opts  ||  {};        var  target  =  normalize(style),  comp  =  el.currentStyle  ?  el.currentStyle  :  document.defaultView.getComputedStyle(el,  null),            prop,  current  =  {},  start  =  (new  Date).getTime(),  dur  =  opts.duration||200,  finish  =  start+dur,  interval;        for(prop  in  target)  current[prop]  =  parse(comp[prop]);        interval  =  setInterval(function(){            var  time  =  (new  Date).getTime(),  delta  =  time>finish  ?  1  :  (time-­‐start)/dur;            for(prop  in  target)                el.style[prop]  =  target[prop].unit  ==  'color'  ?                    color(current[prop].value,target[prop].value,delta)  :                      (current[prop].value+(target[prop].value-­‐current[prop].value)*delta).toFixed(3)  +  target[prop].unit;            if(time>finish)  {  clearInterval(interval);  opts.after  &&  opts.after();  }        },10);    } })('emile');
  • 9. Wait, hold it! Why write something new from scratch?
  • 10. JavaScript frameworks • “Best thing since sliced bread” • Help you get stuff done more easily • “Make JavaScript enjoyable” • Fix cross-browser issues
  • 11. JavaScript frameworks (BUT) • Cover too much or too little • Component and plugin hell • Lead to uniformity • Keep JavaScript away from you
  • 12. JavaScript frameworks (BUT BUT) • Learn from them for your own code • Pick parts you need • Extend them for good or evil • Be a JavaScript god/ninja/cowboy etc.
  • 13. Animation! (what you came for) • What to use for timing • How to conquer CSS • Performance? • And how to make it really nice
  • 14. Move a block from left to right and back
  • 15. Move a block from left to right and back
  • 16. Using a for loop for  (var  i  =  0;  i  <  1000;  i++)    element.style.left  =  i  +  'px'; for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)    element.style.left  =  j  +  'px';
  • 17. Using a for loop moves block to right for  (var  i  =  0;  i  <  1000;  i++)    element.style.left  =  i  +  'px'; for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)    element.style.left  =  j  +  'px'; moves block back to left
  • 18. Using a for loop for  (var  i  =  0;  i  <  1000;  i++)    element.style.left  =  i  +  'px'; for  (var  j  =  1000;  j  >  0;  j-­‐-­‐)    element.style.left  =  j  +  'px'; surprise, this does nothing at all!
  • 19. JavaScript and the browser rendering engine share a single thread of execution. While the code is running, no rendering will happen.
  • 20. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10);
  • 21. setInterval 1 = positive, -1 = negative var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10);
  • 22. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10); call this function every 10ms
  • 23. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10); increase or decrease the index
  • 24. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10); reverse direction once we reach 1000
  • 25. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10); set the style
  • 26. setInterval var  direction  =  1,  i  =  0,      interval  =  setInterval(function(){        i  +=  direction;        if(i  ==  1000)  direction  =  -­‐1;        element.style.left  =  i  +  'px';        if(i  <  0)  clearInterval(interval);      },10); stop doing the animation when the index drops below 0
  • 27. Much better, as in, there’s actually some animation going on.
  • 28. But, there’s a problem: it’s hardly exact timing to use the 10ms interval. Not all users have the super-fast laptops you all have, or maybe they’re looking at it on a mobile browser.
  • 29. (new  Date).getTime() 1257185326039 milliseconds since epoch (January 1, 1970 00:00:00 UTC)
  • 30. Epoch FTW <div  id="test"  style="position:absolute">test</div> <script  type="text/javascript"  charset="utf-­‐8"> var  element  =  document.getElementById('test'); var  start  =  (new  Date).getTime(),  duration  =  1000,      finish  =  start+duration;     var  interval  =  setInterval(function(){    var  time  =  (new  Date).getTime(),          pos  =  time>finish  ?  1  :  (time-­‐start)/duration;    element.style.left  =  (1000*pos)  +  'px';            if(time>finish)  clearInterval(interval); },10); </script>
  • 31. Epoch FTW <div  id="test"  style="position:absolute">test</div> <script  type="text/javascript"  charset="utf-­‐8"> var  element  =  document.getElementById('test'); var  start  =  (new  Date).getTime(),  duration  =  1000,      finish  =  start+duration;     var  interval  =  setInterval(function(){    var  time  =  (new  Date).getTime(),          pos  =  time>finish  ?  1  :  (time-­‐start)/duration;    element.style.left  =  (1000*pos)  +  'px';            if(time>finish)  clearInterval(interval); },10); </script> starts now, calculate finish time from duration (for now one second)
  • 32. Epoch FTW <div  id="test"  style="position:absolute">test</div> <script  type="text/javascript"  charset="utf-­‐8"> var  element  =  document.getElementById('test'); var  start  =  (new  Date).getTime(),  duration  =  1000,      finish  =  start+duration;     var  interval  =  setInterval(function(){    var  time  =  (new  Date).getTime(),          pos  =  time>finish  ?  1  :  (time-­‐start)/duration;    element.style.left  =  (1000*pos)  +  'px';            if(time>finish)  clearInterval(interval); },10); </script> calculate a position between 0 and 1 (0 = start of effect, 1 = end of effect)
  • 33. “pos” is 0 at the animation’s start, 1 at the animation’s end 0 1 t var  time  =  (new  Date).getTime(),            pos  =  time>finish  ?                1  :  (time-­‐start)/duration;
  • 34. var  time  =  (new  Date).getTime(),            pos  =  time>finish  ?                1  :  (time-­‐start)/duration;
  • 35. var  time  =  (new  Date).getTime(),            pos  =  time>finish  ?                1  :  (time-­‐start)/duration; start = 6039 duration = 1000 (1 second) finish = start + duration = 7039 current time = 6539
  • 36. var  time  =  (new  Date).getTime(),            pos  =  time>finish  ?                1  :  (time-­‐start)/duration; start = 6039 duration = 1000 (1 second) finish = start + duration = 7039 current time = 6539 what’s pos at 6539? 6039 7039 t
  • 37. var  time  =  (new  Date).getTime(),            pos  =  time>finish  ?                1  :  (time-­‐start)/duration; start = 6039 duration = 1000 (1 second) finish = start + duration = 7039 current time = 6539 what’s pos at 6539? 6039 7039 t (time-start)/duration = (6539-6039)/1000 = 500/1000 = 0.5
  • 38. Epoch FTW <div  id="test"  style="position:absolute">test</div> <script  type="text/javascript"  charset="utf-­‐8"> var  element  =  document.getElementById('test'); var  start  =  (new  Date).getTime(),  duration  =  1000,      finish  =  start+duration;     var  interval  =  setInterval(function(){    var  time  =  (new  Date).getTime(),          pos  =  time>finish  ?  1  :  (time-­‐start)/duration;    element.style.left  =  (1000*pos)  +  'px';            if(time>finish)  clearInterval(interval); },10); </script> use the position to calculate the style
  • 39. The core loop is complete, but supporting only the CSS “left” property is boring. So how do we query/set more CSS properties?
  • 41. Reading CSS properties IE computedStyle  =      element.currentStyle  ?  element.currentStyle  :          document.defaultView.getComputedStyle(element,  null); DOM My thinking is, IE’s currentStyle property is more elegant.
  • 42. However: >  element.style.border  =  "2px  solid  green"; 2px  solid  green >  document.defaultView.getComputedStyle(element,null).border nothing returned?
  • 43. However: >  element.style.border  =  "2px  solid  green"; 2px  solid  green >  document.defaultView.getComputedStyle(element,null).border >  document.defaultView.getComputedStyle(element,null).borderLeftWidth 2px >  document.defaultView.getComputedStyle(element,null).borderLeftColor rgb(0,  128,  0) shorthand properties colors are are expanded normalized
  • 44. This means, to transform from border:2px  solid  green; to border:17px  solid  #f056eb; We need to expand/normalize the target properties.
  • 46. Normalizing CSS properties var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; }
  • 47. Normalizing CSS properties create a DIV, to give the browser the hard work var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; }
  • 48. Normalizing CSS properties define a list of possible properties var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; }
  • 49. Normalizing CSS properties var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; } create a new element with the CSS properties we want to have normalized
  • 50. Normalizing CSS properties var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; } like getComputedStyle(), the style property of an element contains normalized CSS properties
  • 51. Normalizing CSS properties var  parseEl  =  document.createElement('div'),    props  =  ('backgroundColor  borderBottomColor  '+      //  imagine  more  lines  with  more  CSS  properties  here      'width  wordSpacing  zIndex').split('  '); function  normalize(style){    var  css,  rules  =  {},  i  =  props.length,  v;    parseEl.innerHTML  =  '<div  style="'+style+'"></div>';    css  =  parseEl.childNodes[0].style;    while(i-­‐-­‐)  if(v  =  css[props[i]])  rules[props[i]]  =  v;    return  rules; } slightly optimized way of “for all properties on our list, check if it’s defined, and if yes, add it to the rules object”
  • 53. Interpolating between two CSS values origin  +  difference  ×  position
  • 54. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’
  • 55. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’ target  =  ‘20px’
  • 56. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’ target  =  ‘20px’ position  =  0.5
  • 57. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’ target  =  ‘20px’ position  =  0.5 12  +  (20-­‐12)  ×  0.5  =
  • 58. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’ target  =  ‘20px’ position  =  0.5 12  +  (20-­‐12)  ×  0.5  = 12  +  8  ×  0.5  =
  • 59. Interpolating between two CSS values origin  +  difference  ×  position origin  =  ‘12px’ target  =  ‘20px’ position  =  0.5 12  +  (20-­‐12)  ×  0.5  = 12  +  8  ×  0.5  = 12  +  4  =  16
  • 60. Interpolating between two colors    function  color(source,target,pos){        var  i  =  2,  j,  c,  tmp,  v  =  [],  r  =  [];        while(i-­‐-­‐)              if(arguments[i][0]=='r'){                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));            }  else  {                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));            }        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }        return  'rgb('+r.join(',')+')';    } looks complicated, but it really only is interpolating for each color component (red, green, blue) individually.
  • 61. Also...    function  color(source,target,pos){        var  i  =  2,  j,  c,  tmp,  v  =  [],  r  =  [];        while(i-­‐-­‐)              if(arguments[i][0]=='r'){                c  =  arguments[i].match(/d+/g);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c[j]));            }  else  {                c  =  arguments[i].substr(1);  j=3;  while(j-­‐-­‐)  v.push(parseInt(c.substr(j*2,2),  16));            }        j=3;  while(j-­‐-­‐)  {  tmp  =  ~~(v[j+3]+(v[j]-­‐v[j+3])*pos);  r.push(tmp<0?0:tmp>255?255:tmp);  }        return  'rgb('+r.join(',')+')';    } This JavaScript snippet is optimized for code size, not for readability. It could be expressed much more elegantly.
  • 62. JavaScript numbers >  0.1 0.1 >  0.0001 0.0001 >  0.0000001 1e-­‐7 string representation
  • 63. JavaScript numbers font-­‐size:  1e-­‐7px doesn’t work in CSS number.toFixed(3) toFixed(3) round the number to 3 decimal places and and prevents an error
  • 65. Reduce the amount of nodes (HTML elements and text nodes) and avoid using the “opacity” CSS property.
  • 67.
  • 68. “pos” is 0 at the animation’s start, 1 at the animation’s end var  time  =  (new  Date).getTime(),      pos  =  time>finish  ?          1  :  (time-­‐start)/duration;
  • 70. No easing sudden change in velocity at end sudden change in velocity at start
  • 71. Easing is nothing more than messing with “pos”    emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {        duration:  500,        after:  function(){            emile('test1',  'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {                  duration:  4000,  easing:  bounce            });        }    });
  • 72. No easing looks unnatural. Things move by accelerating and stop by decelerating.
  • 75. (-Math.cos(pos*Math.PI)/2) + 0.5 deceleration at end acceleration at start
  • 78. A “bounce” easing hard velocity changes quadratic “gravity”
  • 79. A “bounce” easing  function  bounce(pos)  {        if  (pos  <  (1/2.75))  {                return  (7.5625*pos*pos);        }  else  if  (pos  <  (2/2.75))  {                return  (7.5625*(pos-­‐=(1.5/2.75))*pos  +  .75);        }  else  if  (pos  <  (2.5/2.75))  {                return  (7.5625*(pos-­‐=(2.25/2.75))*pos  +  .9375);        }  else  {                return  (7.5625*(pos-­‐=(2.625/2.75))*pos  +  .984375);        }    }
  • 80.    emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {        duration:  500,        after:  function(){            emile('test1',                  'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {                  duration:  4000,  easing:  bounce            });        }    });
  • 81.
  • 82.    emile('test2',  'left:300px;padding:10px;border:50px  solid  #ff0000',  {        duration:  500,        after:  function(){            emile('test1',                  'background:#0f0;left:100px;padding-­‐bottom:100px;opacity:1',  {                  duration:  4000,  easing:  bounce            });        }    });
  • 84.
  • 85. propertyTransitions:  {      marginLeft:  'mirror',      marginTop:  'bouncePast',      left:  'swingFromTo',      zIndex:  zIndexTransition   } scripty2 code – Not supported by Émile, too specialized. But easy to add.
  • 86. scripty2 has tons of easings you can lift and use in your own apps Demo them at  http://tr.im/E0JS
  • 87. Q&A And thanks! http://github.com/madrobby/emile http://scripty2.com/ Slides: http://mir.aculo.us/ (soon)