(function () { 'use strict'; function SpriteSheet(img) { // array of sprites this.sprites = []; // number of sprites in image this.nbSprites = 0; // default width and height sprite this.width = 0; this.height = 0; // width and height of the original image this.imageWidth = 0; this.imageHeight = 0; // load image parameters this.load(img); } SpriteSheet.prototype = { load: function (img) { // set sprite dimension this.height = img.getAttribute('height'); this.width = img.getAttribute('width'); // load sprites if defined if (img.getAttribute('data-sprites') !== null) { var dataSprites = JSON.parse(img.getAttribute('data-sprites')), i = 0, len = 0; // sprites defined using an array if (Array.isArray(dataSprites)) { for (i = 0, len = dataSprites.length; i < len; i += 1) { if (dataSprites[i].length > 2) { this.sprites[i] = { x: dataSprites[i][0], y: dataSprites[i][1], width: dataSprites[i][2], height: dataSprites[i][3] }; } else { this.sprites[i] = { x: dataSprites[i][0], y: dataSprites[i][1] }; } } // sprites defined using names } else { for (i in dataSprites) { if (dataSprites.hasOwnProperty(i)) { if (dataSprites[i].length > 2) { this.sprites[i] = { x: dataSprites[i][0], y: dataSprites[i][1], width: dataSprites[i][2], height: dataSprites[i][3] }; } else { this.sprites[i] = { x: dataSprites[i][0], y: dataSprites[i][1] }; } } } } } // load number of sprites if (img.getAttribute('data-nb-sprites') !== null) { this.nbSprites = img.getAttribute('data-nb-sprites'); } }, getNbSprites: function () { return this.nbSprites; }, setNbSprites: function () { if (this.nbSprites === 0 && this.width !== 0 && this.height !== 0) { this.nbSprites = parseInt(this.imageWidth / this.width, 10) * parseInt(this.imageHeight / this.height, 10); } }, setSprites: function () { var nbCol = parseInt(this.imageWidth / this.width, 10), i = 0; for (i = 0; i < this.nbSprites; i += 1) { this.sprites[i] = { x: this.width * (i % nbCol), y: this.height * parseInt(i / nbCol, 10) }; } }, getOffset: function (spriteId) { if (this.sprites.length === 0) { this.setSprites(); } var sprite = this.sprites[spriteId], res = {}; if (sprite) { if (sprite.width) { res = { x: sprite.x, y: sprite.y, width: sprite.width, height: sprite.height }; } else { res = { x: sprite.x, y: sprite.y, width: this.width, height: this.height }; } return res; } } }; function Animation(img, sprites, canvas) { // array of frames this.frames = []; // default time transition this.time = 0.1; // default frame index this.frameIndex = 0; // current frame duraction this.frameDuration = 0; // set sprites and canvas this.sprites = sprites; this.canvas = canvas; // load image parameters this.load(img); } Animation.prototype = { load: function (img) { // load default time transition if (img.getAttribute('data-time')) { this.time = img.getAttribute('data-time'); } // load frames if (img.getAttribute('data-frames')) { var dataFrames = JSON.parse(img.getAttribute('data-frames')), i = 0; if (dataFrames.length !== 0) { for (i = 0; i < dataFrames.length; i += 1) { switch (typeof (dataFrames[i])) { case "number": this.frames[i] = {sprite: dataFrames[i], time: this.time}; break; case "object": this.frames[i] = {sprite: dataFrames[i][0], time: dataFrames[i][1]}; break; case "string": this.frames[i] = {sprite: dataFrames[i], time: this.time}; break; default: break; } } } } }, setImageDimension: function (imageWidth, imageHeight) { this.sprites.imageWidth = imageWidth; this.sprites.imageHeight = imageHeight; }, setFrames: function () { var i = 0, len = 0; this.sprites.setNbSprites(); for (i = 0, len = this.sprites.getNbSprites(); i < len; i += 1) { this.frames[i] = {time: this.time}; } }, // get current sprite to animate getSprite: function () { var spriteId = this.frameIndex, sprite = {}; if (this.frames.length === 0) { this.setFrames(); } if (this.frames[this.frameIndex].sprite !== undefined) { spriteId = this.frames[this.frameIndex].sprite; } sprite = this.sprites.getOffset(spriteId); this.frameDuration = this.frames[this.frameIndex].time; this.frameIndex += 1; // infinite loop animation if (this.frameIndex === this.frames.length) { this.frameIndex = 0; } return sprite; }, getFrameDuration: function () { // convert in millisecond return this.frameDuration * 1000; }, drawSprite: function (img) { var ctx = this.canvas.getContext('2d'), sprite = this.getSprite(), t = this; ctx.clearRect(0, 0, 300, 300); ctx.drawImage(img, sprite.x, sprite.y, sprite.width, sprite.height, 0, 0, this.canvas.width, this.canvas.height); window.setTimeout(function () {t.drawSprite(img); }, this.getFrameDuration()); } }; function initAnimCanvas() { var imgs = document.getElementsByTagName("img"), i = 0, len = 0, canvas = {}, sprites = {}, anim = {}, img = {}; // animate images where parent is canvas for (i = 0, len = imgs.length; i < len; i += 1) { canvas = imgs[i].parentNode; if (canvas.nodeName.toLowerCase() === "canvas") { sprites = new SpriteSheet(imgs[i]); anim = new Animation(imgs[i], sprites, canvas); img = document.createElement('img'); img.anim = anim; img.onload = function () { this.anim.setImageDimension(this.width, this.height); this.anim.drawSprite(this); } img.src = imgs[i].src; } } } //http://scottandrew.com/weblog/articles/cbs-events function addEvent(obj, evType, fn, useCapture) { if (obj.addEventListener) { obj.addEventListener(evType, fn, useCapture); } else { if (obj.attachEvent) { obj.attachEvent("on" + evType, fn); } else { window.alert("Handler could not be attached"); } } } // when document is loaded animated images if (document.getElementById && document.createTextNode) { addEvent(window, 'load', initAnimCanvas); } })();