From 5277563e95fa9bd6e83712a8d26b9d9e3fab85af Mon Sep 17 00:00:00 2001 From: Glen Cheney Date: Tue, 2 Jul 2013 00:06:52 -0700 Subject: [PATCH] Add animated favicon Currently lots of jank in Chrome at the moment. --- _includes/head.html | 2 +- img/favicon-sprite.png | Bin 0 -> 10628 bytes img/favicon-sprite@2x.png | Bin 0 -> 1318 bytes js/page.js | 191 +++++++++++++++++++++++++++++++++++++- 4 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 img/favicon-sprite.png create mode 100644 img/favicon-sprite@2x.png diff --git a/_includes/head.html b/_includes/head.html index 61d1a58..cf9536d 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -27,7 +27,7 @@ - + diff --git a/img/favicon-sprite.png b/img/favicon-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..8d66332223f09b46c151dac8a1b2af2405d9f0b3 GIT binary patch literal 10628 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 literal 0 HcmV?d00001 diff --git a/js/page.js b/js/page.js index 22962cc..675e119 100644 --- a/js/page.js +++ b/js/page.js @@ -40,6 +40,14 @@ Modules.Support = (function() { return dfd.promise(); }; + // Fill rAF + var rAF = window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + window.msRequestAnimationFrame; + + window.requestAnimationFrame = rAF; + return self; }()); @@ -188,6 +196,176 @@ Modules.Nav = (function( $ ) { }( jQuery )); +Modules.Favicon = (function( doc ) { + 'use strict'; + + var Favicon = function( src, numFrames, framesPerAnimation, animationDelay ) { + var self = this; + + // Variables based on params + self.src = src; + self.numFrames = numFrames; + self.framesPerAnimation = framesPerAnimation; + self.animationDelay = animationDelay; + + // Elements + self.canvas = doc.createElement('canvas'); + self.img = doc.createElement('img'); + self.html = doc.documentElement; + + // Calculations + self.size = window.devicePixelRatio > 1 ? 32 : 16; + + // If it's not a data url, pick apart the filename and add @2x for retina + if ( !self.src.match(/data:/) && window.devicePixelRatio > 1 ) { + var dot = self.src.lastIndexOf('.'); + self.src = self.src.substring( 0, dot ) + '@2x' + self.src.substring( dot ); + } + + self.currentFrame = 0; + self.thirtyFPS = 1000 / 30; + + self.init(); + }; + + Favicon.prototype.init = function() { + var self = this; + + // No #favicon element or browser doesn't support canvas or < IE9, stop + if ( !doc.getElementById('favicon') || !self.canvas.getContext || self.html.className.indexOf('lt-ie9') > -1 ) { + return; + } + + // Save context + self.ctx = self.canvas.getContext('2d'); + + // Set canvas dimensions based on device DPI + self.canvas.height = self.canvas.width = self.size; + + // Create a new sprite 32x32 size with 32x32 sprites + self.sprite = new Sprite( self.ctx, self.img, self.size ); + + // Bind the image load handler + self.img.onload = self.onSpriteLoaded.bind( self ); + + // Trigger image to load + self.img.src = self.src; + }; + + Favicon.prototype.getData = function() { + return this.canvas.toDataURL('image/png'); + }; + + // Clone the current #favicon and replace it with a new element + // which has the updated data URI href + Favicon.prototype.setFavicon = function() { + var self = this, + data = self.getData(), + originalFavicon = doc.getElementById('favicon'), + clone = originalFavicon.cloneNode( true ); + + clone.setAttribute( 'href', data ); + originalFavicon.parentNode.replaceChild( clone, originalFavicon ); + }; + + // Request Animation Frame Loop + Favicon.prototype.loop = function( timestamp ) { + var self = this, + lastCall = self.lastTimestamp; + + // If not enough time has elapse since the last call + // immediately call the next rAF + if ( timestamp - lastCall < self.timeToElapse ) { + return requestAnimationFrame( self.loop.bind( self ) ); + } + + // Increment current frame + self.currentFrame += 1; + if ( self.currentFrame === self.numFrames ) { + self.currentFrame = 0; + } + + // Completed an animation state + self.timeToElapse = self.currentFrame % self.framesPerAnimation === 0 ? + self.animationDelay : + self.thirtyFPS; + + // Draw current frame from sprite + self.sprite.drawFrame( self.currentFrame ); + + // Swap + self.setFavicon(); + + // Set a timeout to draw again + self.lastTimestamp = timestamp; + + // Continue loop + return requestAnimationFrame( self.loop.bind( self ) ); + }; + + // Sprite loaded + Favicon.prototype.onSpriteLoaded = function() { + var self = this; + + // Draw the first frame when the image loads + self.sprite.drawFrame( self.currentFrame ); + + // Swap + self.setFavicon(); + + // Start loop + requestAnimationFrame( self.loop.bind( self ) ); + }; + + + var Sprite = function( context, img, size ) { + var self = this; + self.ctx = context; + self.img = img; + self.width = size; + self.height = size; + self.frameWidth = size; + self.frameHeight = size; + }; + + // Assuming horizontal sprite + Sprite.prototype.getFrame = function( frame ) { + return { + x: frame * this.frameWidth, + y: 0 + }; + }; + + Sprite.prototype.clearCanvas = function() { + this.ctx.clearRect( 0, 0, this.width, this.height ); + }; + + Sprite.prototype.drawFrame = function( frameNumber ) { + var self = this; + + var frame = self.getFrame( frameNumber ); + + // Clear out the last frame + self.clearCanvas(); + + // Draw to the context. This method is really confusing... + self.ctx.drawImage( + self.img, + frame.x, + frame.y, + self.width, + self.height, + 0, + 0, + self.width, + self.height + ); + }; + + return Favicon; +}( document )); + + // Analytics var _gaq = [ ['_setAccount', 'UA-39355642-1'], ['_trackPageview'] ]; @@ -222,4 +400,15 @@ $(document).ready(function() { Modules.Nav.init(); Modules.Polyfill.init(); -}); \ No newline at end of file + + var src = '/img/favicon-sprite.png'; + new Modules.Favicon( src, 21, 7, 3000 * 1 ); +}); + + + + + + + +