Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Animate the Web with EmberJS

Animate the Web with EmberJS

Learn more about story-driven animations and how to bring them to the web.
Were you a fan of animated cartoons as a kid, and wondered if one day you could create your own? Here's the great news: you can! Using open web standards and Ember.js you're able to create frame-by-frame animations—and even to make them interactive! In this talk you will learn how open web standards empower creators to tell animated stories and deliver them through the web. Alongside animation demos you will see how you can leverage the power of two Web APIs - HTML5 Canvas and the Web Animations API - in Ember efficiently and how you can embed your animations in Ember components for full flexibility and reusability across your app.

Watch this talk at EmberConf 2017: https://www.youtube.com/watch?v=wFJPIjRTIVU

Jessy Jordan

March 28, 2017
Tweet

More Decks by Jessy Jordan

Other Decks in Programming

Transcript

  1. FRAME-BY-FRAME ANIMATIONS IN CARTOONS Alla Gadassik - "The Animated Line:

    Performing and Generating Movement in Early Animation"
  2. CANVAS CONTEXT OBJECT <!-- index.html --> <canvas id="comic-panel"></canvas> // drawing.js

    const canvas = document.getElementById('comic-panel'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); } else { throw `Everything's fresh, but there's no context object here, so time for some polyfilling: bower install --save canvas-5-polyfill`; }
  3. CREATING THE COMPONENT {{comic-panel width=width height=height}} // app/components/comic-panel.js import Ember

    from 'ember'; export default Ember.Component.extend({ tagName: 'canvas' })
  4. DRAWING TO THE CANVAS Canvas sx, sy: origin of source

    image sWidth, sHeight: width and height of source image dx, dy: origin of canvas destination dWidth, dHeight: width and height of canvas destination
  5. DRAWING TO THE CANVAS // app/components/comic-panel.js export default Ember.Component.extend({ Ember.on('init',

    function() { const image = new Image(); image.onload = () => { this.set('naturalHeight', image.height); this.set('naturalWidth', image.width); this.set('pseudoImg', image); }; image.src = this.get('imgSrc'); }) })
  6. DRAWING TO THE CANVAS // app/components/comic-panel.js export default Ember.Component.extend({ draw()

    { // ... ctx.clearRect(0, 0, canvasWidth, canvasHeight); ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, dWidth, canvasHeight); } }) /* app/components/comic-panel.js */ setup: Ember.observer('pseudoImg', function() { const ctx = this.get('element').getContext('2d'); this.set('ctx', ctx); this.draw(); })
  7. RUN AND CANCEL ANIMATIONS const loop = Ember.run.later(this, this.loop, 100);

    this.set('currentLoop', loop); if (!this.get('runAnimation')) { Ember.run.cancel(currentLoop); this.set('currentLoop', null); })
  8. CSS3 ANIMATIONS GO JAVASCRIPT CSS3 @keyframes rotating { 0% {

    transform: rotate(0) translate3D(-50%, -50%, 0); color: #000; }, 33% { color: #431236; offset: 0.333; }, 66% { transform: rotate(360deg) translate3D(-50%, -50%, 0); color: #000: } };
  9. KEYFRAME EFFECTS JS // KeyFrameEffect Objects: var rotating = [

    { transform: `rotate(0) translate3D(-50%, -50%, 0)`, color: '#000' }, { color: '#431236', offset: 0.333 }, { transform: 'rotate(360deg) translate3D(-50%, -50%, 0)', color: '#000' } ];
  10. CREATING KEYFRAMEEFFECTS // app/my-route/controller.js let characterObject = { ....., keyFrames:

    [ { backgroundPosition: '0 0' }, { backgroundPosition: `0 100%` } ], ..... };
  11. CREATING KEYFRAMEEFFECTS let characterObject = { ....., animationOptions: { duration:

    500, easing: `steps(5)`, iterations: 'Infinity' } ..... }; {{comic-panel comicLayer=characterObject}}
  12. CREATING AND STARTING THE ANIMATION /* app/components/comic-panel/component.js */ export default

    Ember.Component.extend({ ... startAnimation: Ember.on('didRender', function() { let keyFrames = this.get('keyFrames'); let animationOptions = this.get('animationOptions'); this.$()[0].animate(keyFrames, animationOptions); }), ...
  13. EMBEDDING COMIC LAYER SUB COMPONENTS /* app/components/comic-panel/template.hbs */ {{#each comicLayerList

    as |layer|}} {{comic-layer keyFrames=layer.keyFrames animationOptions=layer.animationOptions frameAction=(action "setKeyFrames")}} {{/each}} // app/components/comic-panel-layer.js createKeyFrames: Ember.on('didRender', function() { // ... const layer = this.get('element'); const keyFrame = new KeyframeEffect( layer, this.get('keyFrames'), this.get('animationOptions') ); this.sendAction('frameAction', keyFrame); }
  14. SYNCHRONIZE THE ANIMATION LAYERS /* app/components/comic-panel/component.js */ setupAnimation() { const

    timeline = this.get('timeline'); const keyFrameEffects = this.get('keyFrameEffects'); const group = new GroupEffect(keyFrameEffects); const animation = new Animation(group, timeline); animation.pause(); this.set('animation'); },
  15. SYNCHRONIZE THE ANIMATION LAYERS /* app/components/comic-panel/component.js */ export default Ember.Component.extend({

    // ... actions: { play() { this.get('animation').play(); } pause() { this.get('animation').pause(); } } // ... })
  16. RESOURCES Tomster and Zoey Illustration by "Inifinite Canvas" quote from

    Learn more about the Web Animations API with the Lindsey Wilson Rachel Nabor's Keynote @ OSCON 2014: "Storytelling On The Shoulders of Giants" excellent How To Guide at MDN Full source code for the animation demos