diff --git a/HISTORY.md b/HISTORY.md new file mode 100755 index 0000000..9e2679d --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,18 @@ +# Release history + +## v0.2.2 + +- Safer image loading: images with a wrong or missing source get a placeholder image (when used + in a DOM context a missing image is not a big deal, but when trying to draw it on a canvas it crashes javascript) + +## v0.2.1 + +- Switch to wizcorp/util + +## v0.2.0 + +- Lowercase name + +## v0.1.0 + +- First version \ No newline at end of file diff --git a/README.md b/README.md index d22aefe..256c63f 100755 --- a/README.md +++ b/README.md @@ -1,47 +1,79 @@ image-preloader ============== -Preload your images with the ImagePreloader +image-preloader is an image preloader particularly designed to work with canvas. -### Usage example +# Overview + +Basically, you provide an object with a list of urls and you get back another object where the urls have been replaced with the corresponding images, ready to be drawn somewhere. + +Simple example: ```javascript var imagePreloader = new ImagePreloader(); -var urlList = { - whatever1: 'http://domain/path/to/image1.png', - whatever2: 'http://domain/path/to/image2.png', - whatever3: 'http://domain/path/to/image3.png', - whatever4: 'http://domain/path/to/image4.png', - whatever5: 'http://domain/path/to/image5.png', - whatever6: 'http://domain/path/to/image6.png' +var assets = { + sprite: 'http://domain.whatever.com/assets/sprite1.png', + background: 'http://domain.whatever.com/assets/bg.png', + button: 'http://domain.whatever.com/assets/btn.png' }; -imagePreloader.add(urlList); +imagePreloader.add(assets); +imagePreloader.on('finished', function (data) { + // the images are in data.images, matching the + // provided object structure, so you can simply do: + assets = data.images; + // and now you have image objects instead of strings, you can do for example: + whateverContext.drawImage(assets.sprite, 0, 0); +}); +imagePreloader.start(); +``` -var stepCb = function (data) { - var loaded = data.loaded; - var error = data.error; - var total = data.total; - console.log('loadInProgress: ' + (loaded + error) + '/' + total); -}; +# In depth -var finalCb = function (data) { - var loaded = data.loaded; - var error = data.error; - var total = data.total; - var images = data.images; - console.log('All (' + total + ') pictures have been processed. ' + loaded + ' have been loaded and ' + error + ' have not.'); - if (images.whatever1) { - document.body.appendChild(images.whatever1); - } -}; +## .start() parameters -imagePreloader.on('error', stepCb); -imagePreloader.on('loaded', stepCb); -imagePreloader.on('finished', finalCb); +You can provide completely optional parameters to the start method: -var notMandatory = { - ttl: 5000, - maxParallel: 3 -} -imagePreloader.start(notMandatory); +- `ttl`: the maximum time you want to wait on one image before having the onerror triggered (ms). Default value is 3000ms. +- `maxParallel`: the maximum number of images you want to allow to be loaded in parallel (if you want to avoid something else to be blocked). Default value is 5. +- `placeholderImgData`: what data image you want for failed images. Default is an empty 1x1 transparent png. + +Example: +```javascript +imagePreloader.start({ + ttl: 10000, + maxParallel: 2, + placeholderImgData: 'data:image/png;base64,iVBORw0KGgo....' +}); ``` + +## events + +You can listen for: + +### finished + +Sent back object contains: + +- `loaded`: number of images successfully loaded +- `error`: number of images where loading failed +- `errKeys`: array containing the list of keys who failed +- `images`: object, matching the original urls object structure, where strings have been replaced by images objects + +### loaded + +Called every-time a picture is successfully loaded, you can use it for progress bars. Sent back object contains: + +- `currentKey`: which key have been loaded +- `loaded`: number of images successfully loaded so far +- `error`: number of failed images so far +- `total`: total number of images we are processing + +### error + +Called every-time a picture fails to load, you can use it for progress bars. Sent back object contains: + +- `currentKey`: which key failed +- `loaded`: number of images successfully loaded so far +- `error`: number of failed images so far +- `total`: total number of images we are processing +- `errorMsg`: string error message \ No newline at end of file diff --git a/component.json b/component.json index 242ee3e..e692fac 100755 --- a/component.json +++ b/component.json @@ -1,6 +1,6 @@ { "name": "image-preloader", - "version": "0.2.1", + "version": "0.2.2", "description": "An image pre-loader component", "dependencies": { "Wizcorp/eventemitter": "*", diff --git a/index.js b/index.js index c64b064..d661d67 100755 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ var EventEmitter = require('EventEmitter'); var defaultTtl = 3000; var defaultMaxParallel = 5; +var emptyImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII='; function ImagePreloader() { this.urlList = {}; @@ -12,9 +13,11 @@ function ImagePreloader() { this.loading = 0; this.loaded = 0; this.error = 0; + this.errKeys = []; this.ttl = defaultTtl; this.maxParallel = defaultMaxParallel; + this.placeholderImgData = emptyImg; } inherit(ImagePreloader, EventEmitter); @@ -70,18 +73,19 @@ function loadNext() { var toLoad = that._keyMap.length; if (!processed) { if (err) { - that.imgList[key] = null; + that.imgList[key].src = that.placeholderImgData; that.error++; - that.emit('error', {loaded: that.loaded, error: that.error, total: toLoad, errorMsg: err}); + that.errKeys.push(key); + that.emit('error', {loaded: that.loaded, error: that.error, total: toLoad, errorMsg: err, currentKey: key}); } else { that.loaded++; - that.emit('loaded', {loaded: that.loaded, error: that.error, total: toLoad}); + that.emit('loaded', {loaded: that.loaded, error: that.error, total: toLoad, currentKey: key}); } that.loading--; processed = true; } if (that.loaded + that.error === toLoad) { - that.emit('finished', {loaded: that.loaded, error: that.error, total: toLoad, images: that.imgList}, 'test OKKKKKK'); + that.emit('finished', {loaded: that.loaded, error: that.error, errKeys: that.errKeys, total: toLoad, images: that.imgList}); } else { loadNext.call(that); } @@ -92,7 +96,12 @@ function loadNext() { img.addEventListener('abort', onError, false); ttlTimeout = setTimeout(onTimeout, this.ttl); - img.src = url; + if (url) { + img.src = url; + } else { + onError(); + } + loadNext.call(this); } @@ -119,12 +128,19 @@ ImagePreloader.prototype.start = function (options) { this.maxParallel = defaultMaxParallel; } + if (options.placeholderImgData !== undefined) { + this.placeholderImgData = options.placeholderImgData; + } else { + this.placeholderImgData = emptyImg; + } + this.imgList = {}; this._keyMap = Object.keys(this.urlList); this.loading = 0; this.loaded = 0; this.error = 0; + this.errKeys = []; loadNext.call(this); -}; +}; \ No newline at end of file