From 29009d27f381b3c526b06335e28eaa927190b728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Tue, 26 Nov 2013 15:20:04 +0100 Subject: [PATCH] Make ol.style.Image loadable --- src/ol/style/imagestyle.js | 109 ++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/src/ol/style/imagestyle.js b/src/ol/style/imagestyle.js index c4ea5ecc95..3021c960d4 100644 --- a/src/ol/style/imagestyle.js +++ b/src/ol/style/imagestyle.js @@ -1,15 +1,36 @@ // FIXME decide default value for snapToPixel goog.provide('ol.style.Image'); +goog.provide('ol.style.ImageState'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); + + +/** + * @enum {number} + */ +ol.style.ImageState = { + IDLE: 0, + LOADING: 1, + LOADED: 2, + ERROR: 3 +}; /** * @constructor * @param {ol.style.ImageOptions} options Options. + * @extends {goog.events.EventTarget} */ ol.style.Image = function(options) { + goog.base(this); + /** * @type {ol.Pixel} */ @@ -18,7 +39,17 @@ ol.style.Image = function(options) { /** * @type {HTMLCanvasElement|HTMLVideoElement|Image} */ - this.image = options.image; + this.image = goog.isDefAndNotNull(options.image) ? + options.image : new Image(); + if (!goog.isNull(options.crossOrigin)) { + this.image.crossOrigin = options.crossOrigin; + } + + /** + * @type {ol.style.ImageState} + */ + this.imageState = goog.isDef(options.imageState) ? + options.imageState : ol.style.ImageState.IDLE; /** * @type {number|undefined} @@ -40,4 +71,80 @@ ol.style.Image = function(options) { */ this.subtractViewRotation = options.subtractViewRotation; + /** + * @private + * @type {Array.} + */ + this.imageListenerKeys_ = null; + + /** + * @private + * @type {string|undefined} + */ + this.src_ = options.src; + +}; +goog.inherits(ol.style.Image, goog.events.EventTarget); + + +/** + * @private + */ +ol.style.Image.prototype.dispatchChangeEvent_ = function() { + this.dispatchEvent(goog.events.EventType.CHANGE); +}; + + +/** + * Tracks loading or read errors. + * + * @private + */ +ol.style.Image.prototype.handleImageError_ = function() { + this.imageState = ol.style.ImageState.ERROR; + this.unlistenImage_(); + this.dispatchChangeEvent_(); +}; + + +/** + * Tracks successful image load. + * + * @private + */ +ol.style.Image.prototype.handleImageLoad_ = function() { + this.imageState = ol.style.ImageState.LOADED; + this.unlistenImage_(); + this.dispatchChangeEvent_(); +}; + + +/** + * Load not yet loaded URI. + */ +ol.style.Image.prototype.load = function() { + if (this.imageState == ol.style.ImageState.IDLE) { + goog.asserts.assert(goog.isDef(this.src_)); + goog.asserts.assert(goog.isNull(this.imageListenerKeys_)); + this.imageState = ol.style.ImageState.LOADING; + this.imageListenerKeys_ = [ + goog.events.listenOnce(this.image, goog.events.EventType.ERROR, + this.handleImageError_, false, this), + goog.events.listenOnce(this.image, goog.events.EventType.LOAD, + this.handleImageLoad_, false, this) + ]; + this.image.src = this.src_; + } +}; + + +/** + * Discards event handlers which listen for load completion or errors. + * + * @private + */ +ol.style.Image.prototype.unlistenImage_ = function() { + goog.asserts.assert(!goog.isNull(this.imageListenerKeys_)); + goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey); + this.imageListenerKeys_ = null; };