GIFs

vs

Web Components

by

@GlenMaddern

Me?

Me & GIFs

Me & GIFs

Chapter One

The Idea

VastImg

ETOOMUCHPORN

GifCity

+

Tumblr

=

benschwarz.github.io/gifcity/?t=tumblrs,go,here

mrdiv

simpsonsgifs

skt-na-veia-sempre

benschwarz.github.io/gifcity/?t=tumblrs,go,here

DJGif

github.com/geelen/djgif

djgif.com (one day)

Two challenges:

<img src="probably_cats.gif">
var img = new Image;
img.src = "definitely_cats.gif";

Now what?

What is

an animation

but a

series of frames

?

What's in a GIF?

http://www.matthewflickinger.com/lab/ whatsinagif/bits_and_bytes.asp

header

frame frame frame

footer

header frame footer

header frame footer

header frame footer

exploder.js

Put the frames in the DOM

<div data-frame="0">
  <img src="frame0.gif">
  <img src="frame1.gif">
  <img src="frame2.gif">
</div>

Show one at a time with CSS

[data-frame] img {
  opacity: 0;
  position: absolute;
}
[data-frame="0"] img:nth-child(1),
[data-frame="1"] img:nth-child(2),
[data-frame="2"] img:nth-child(3) {
  opacity: 1;
}

Cycle through with JS

var animate = function() {
  var currentFrame = calculateFrame();
  framesElement.dataset.frame = currentFrame;
  requestAnimationFrame(animate);
}
animate();

Chapter Two

The Component

Dreamcode

<img src='lulz.gif'>
<x-gif src='lulz.gif'>

<x-gif>

geelen.github.io/x-gif

geelen.github.io/x-gif

<x-gif
  src=''
  // Playback Modes
  [speed='' || sync || bpm='']
  // Playback options
  stopped
  fill
  n-times=''
  ping-pong
  snap
>

Chapter Three

The Launch

Polymer
platform.js - 50kb
polymer.html - 1kb
polymer.js - 23kb
layout.html - 2kb

<x-gif>
x-gif.html - 1kb
x-gif.js - 11kb
x-gif.css - 3kb

7 requests, 91kb total

https://github.com/Polymer/vulcanize

https://github.com/Polymer/vulcanize

vulcanize -o dist/x-gif.vulcan.html --inline dist/x-gif.html
platform.js - 50kb
x-gif.vulcan.html - 34kb

2 requests, 84kb total

Polymer

What about Angular/Ember/React?

An idea!

Superficially, it should work

import XGifCore from './x-gif.core.js'
myModule.directive('xGif', XGifCore.Angular);
Ember.Component.extend(XGifCore.Ember);
React.createClass(XGifCore.React);
Polymer('x-gif', XGifCore.Polymer);

Problems

An example - Playback

setFrame(fraction, repeatCount) {
  var frameNr = (this.pingPong && repeatCount % 2 >= 1) ?
    this.gif.frameAt(1 - fraction) :
    this.gif.frameAt(fraction);
  this.element.dataset['frame'] = frameNr;
}

React changes

setFrame(fraction, repeatCount) {
  var frameNr = // SAME MATHS;
  this.domUpdater.setFrame(frameNr);
}
class ShadowDomUpdater { /* ... */ }
class ReactStateUpdater {/* ... */ }

Shadow DOM

is

badass

:(

Chapter Four

The Solution

Chrome 36

Polymer

is not equal to

Web Components

Polymer
class XGif {
 ready() { /* ... */ }
}
Polymer('x-gif', new XGif());
Web Components
class XGif extends HTMLElement {
  createdCallback() { /* ... */ }
}
document.registerElement('x-gif', XGif);
Polymer
srcChanged() {
  this.playback = new Playback(/* ... */)
}
speedChanged(oldVal, newVal) {
  this.playback.speed = newVal;
}
Web Components
attributeChangedCallback(attribute, oldVal, newVal) {
  if (attribute == 'src') {
    this.controller.srcChanged(newVal);
  } else if (attribute == 'speed') {
    this.controller.speedChanged(parseFloat(newVal));
  // ...
x-gif.html (Polymer)
<link rel='import' href='polymer.html'>

<polymer-element name='x-gif' attributes='src speed ... stopped'>
  <template>
    <link rel='stylesheet' href='x-gif.css' />
    <div class='frames-wrapper'>
      <div id='frames'></div>
    </div>
  </template>
</polymer-element>

<script src='x-gif.js'></script>
<!-- calls Polymer('x-gif', new XGif()) -->
x-gif.html (Web Component)
<template id='template'>
  <link rel='stylesheet' href='x-gif.css' />
  <div class='frames-wrapper'>
    <div id='frames'></div>
  </div>
</template>

<script src='x-gif.js'></script>
x-gif.js (Web Component)
class XGif extends HTMLElement {
  createdCallback() {
    this.shadow = this.xgif.createShadowRoot();
    var owner = document.currentScript.ownerDocument;
    var template = owner.querySelector('#template');
    this.shadow.appendChild(template.content.cloneNode(true));
  }
}

document.registerElement('x-gif', XGif);

Chrome 36+

<link rel='import' href='x-gif.html'>
<x-gif src='mrt_works_it.gif'></x-gif>
<x-gif>
x-gif.local.html - 1kb
x-gif.js - 11kb
x-gif.css - 3kb

Vulcanized
x-gif.html - 14kb

platform.js

... it's not just for Polymer

All browsers (IE9+)
<script>
  if ('registerElement' in document
    && 'createShadowRoot' in HTMLElement.prototype
    && 'import' in document.createElement('link')
    && 'content' in document.createElement('template')) {
    // We're using a browser with native WC support!
  } else {
    document.write("<script src='platform.js'></script>")
  }
</script>
<link rel='import' href='x-gif.html'>
<x-gif src='mrt_works_it.gif'></x-gif>
platform.js - 50kb
x-gif.html - 14kb

What's so different?

Extend the

browser

not the

framework


Everything talks

HTML

Closing thoughts

The Web

is

awesome

Thanks!

@GlenMaddern

geelen.github.io/gifs-vs-web-components
~46Mb ¯\_(ツ)_/¯
geelen.github.io/x-gif