Merge pull request #99 from twpayne/beyond-image-tiles

Beyond image tiles
This commit is contained in:
Tom Payne
2013-01-11 06:11:38 -08:00
13 changed files with 490 additions and 190 deletions

View File

@@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link rel="stylesheet" href="style.css" type="text/css">
<style type="text/css">
.map {
width: 400px;
height: 400px;
border: thin solid #cccccc;
margin: 1em;
}
</style>
<title>ol3 canvas tiles demo</title>
</head>
<body>
<h1 id="title">Canvas tiles example</h1>
<div id="shortdesc">The black grid tiles are generated on the client with an HTML5 canvas. Note that the tile coordinates are ol3 normalized tile coordinates (origin bottom left), not OSM tile coordinates (origin top left).</div>
<table>
<tr>
<th>DOM</th>
<th>WebGL</th>
</tr>
<tr>
<td><div id="domMap" class="map"></div></td>
<td><div id="webglMap" class="map"></div></td>
</tr>
</table>
<div id="docs">
<p>See the
<a href="canvas-tiles.js" target="_blank">canvas-tiles.js source</a>
to see how this is done.</p>
</div>
<div id="tags">layers, stamen, canvas</div>
<script src="loader.js?id=canvas-tiles" type="text/javascript"></script>
</body>
</html>

43
examples/canvas-tiles.js Normal file
View File

@@ -0,0 +1,43 @@
goog.require('ol.Collection');
goog.require('ol.Coordinate');
goog.require('ol.Map');
goog.require('ol.Projection');
goog.require('ol.RendererHint');
goog.require('ol.layer.TileLayer');
goog.require('ol.source.DebugTileSource');
goog.require('ol.source.Stamen');
var layers = new ol.Collection([
new ol.layer.TileLayer({
source: new ol.source.Stamen({
provider: ol.source.StamenProvider.WATERCOLOR
})
}),
new ol.layer.TileLayer({
source: new ol.source.DebugTileSource({
projection: ol.Projection.getFromCode('EPSG:3857'),
tileGrid: new ol.tilegrid.XYZ({
maxZoom: 22
})
})
})
]);
var webglMap = new ol.Map({
view: new ol.View2D({
center: ol.Projection.transformWithCodes(
new ol.Coordinate(-0.1275, 51.507222), 'EPSG:4326', 'EPSG:3857'),
zoom: 10
}),
layers: layers,
renderer: ol.RendererHint.WEBGL,
target: 'webglMap'
});
var domMap = new ol.Map({
renderer: ol.RendererHint.DOM,
target: 'domMap'
});
domMap.bindTo('layers', webglMap);
domMap.bindTo('view', webglMap);

137
src/ol/imagetile.js Normal file
View File

@@ -0,0 +1,137 @@
goog.provide('ol.ImageTile');
goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileState');
/**
* @constructor
* @extends {ol.Tile}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {string} src Image source URI.
* @param {?string} crossOrigin Cross origin.
*/
ol.ImageTile = function(tileCoord, src, crossOrigin) {
goog.base(this, tileCoord);
/**
* Image URI
*
* @private
* @type {string}
*/
this.src_ = src;
/**
* @private
* @type {Image}
*/
this.image_ = new Image();
if (!goog.isNull(crossOrigin)) {
this.image_.crossOrigin = crossOrigin;
}
/**
* @private
* @type {Object.<number, Image>}
*/
this.imageByContext_ = {};
/**
* @private
* @type {Array.<number>}
*/
this.imageListenerKeys_ = null;
};
goog.inherits(ol.ImageTile, ol.Tile);
/**
* @inheritDoc
*/
ol.ImageTile.prototype.getImage = function(opt_context) {
if (goog.isDef(opt_context)) {
var image;
var key = goog.getUid(opt_context);
if (key in this.imageByContext_) {
return this.imageByContext_[key];
} else if (goog.object.isEmpty(this.imageByContext_)) {
image = this.image_;
} else {
image = /** @type {Image} */ (this.image_.cloneNode(false));
}
this.imageByContext_[key] = image;
return image;
} else {
return this.image_;
}
};
/**
* @inheritDoc
*/
ol.ImageTile.prototype.getKey = function() {
return this.src_;
};
/**
* Tracks loading or read errors.
*
* @private
*/
ol.ImageTile.prototype.handleImageError_ = function() {
this.state = ol.TileState.ERROR;
this.unlistenImage_();
};
/**
* Tracks successful image load.
*
* @private
*/
ol.ImageTile.prototype.handleImageLoad_ = function() {
this.state = ol.TileState.LOADED;
this.unlistenImage_();
this.dispatchChangeEvent();
};
/**
* Load not yet loaded URI.
*/
ol.ImageTile.prototype.load = function() {
if (this.state == ol.TileState.IDLE) {
this.state = ol.TileState.LOADING;
goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
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.ImageTile.prototype.unlistenImage_ = function() {
goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
this.imageListenerKeys_ = null;
};

View File

@@ -17,6 +17,7 @@ goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('goog.style');
goog.require('goog.webgl');
goog.require('ol.Tile');
goog.require('ol.layer.Layer');
goog.require('ol.layer.TileLayer');
goog.require('ol.renderer.webgl.FragmentShader');
@@ -219,15 +220,15 @@ ol.renderer.webgl.Map.prototype.addLayer = function(layer) {
/**
* @param {Image} image Image.
* @param {ol.Tile} tile Tile.
* @param {number} magFilter Mag filter.
* @param {number} minFilter Min filter.
*/
ol.renderer.webgl.Map.prototype.bindImageTexture =
function(image, magFilter, minFilter) {
ol.renderer.webgl.Map.prototype.bindTileTexture =
function(tile, magFilter, minFilter) {
var gl = this.getGL();
var imageKey = image.src;
var textureCacheEntry = this.textureCache_[imageKey];
var tileKey = tile.getKey();
var textureCacheEntry = this.textureCache_[tileKey];
if (goog.isDef(textureCacheEntry)) {
gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture);
if (textureCacheEntry.magFilter != magFilter) {
@@ -244,7 +245,7 @@ ol.renderer.webgl.Map.prototype.bindImageTexture =
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
gl.texImage2D(goog.webgl.TEXTURE_2D, 0, goog.webgl.RGBA, goog.webgl.RGBA,
goog.webgl.UNSIGNED_BYTE, image);
goog.webgl.UNSIGNED_BYTE, tile.getImage());
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter);
gl.texParameteri(
@@ -253,7 +254,7 @@ ol.renderer.webgl.Map.prototype.bindImageTexture =
goog.webgl.CLAMP_TO_EDGE);
gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T,
goog.webgl.CLAMP_TO_EDGE);
this.textureCache_[imageKey] = {
this.textureCache_[tileKey] = {
texture: texture,
magFilter: magFilter,
minFilter: minFilter
@@ -485,11 +486,11 @@ ol.renderer.webgl.Map.prototype.initializeGL_ = function() {
/**
* @param {Image} image Image.
* @return {boolean} Is image texture loaded.
* @param {ol.Tile} tile Tile.
* @return {boolean} Is tile texture loaded.
*/
ol.renderer.webgl.Map.prototype.isImageTextureLoaded = function(image) {
return image.src in this.textureCache_;
ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
return tile.getKey() in this.textureCache_;
};

View File

@@ -386,9 +386,9 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
var tilesToDrawByZ = {};
/**
* @type {Array.<Image>}
* @type {Array.<ol.Tile>}
*/
var imagesToLoad = [];
var tilesToLoad = [];
var allTilesLoaded = true;
@@ -405,12 +405,11 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
if (tileState == ol.TileState.IDLE) {
tile.load();
} else if (tileState == ol.TileState.LOADED) {
var image = tile.getImage();
if (mapRenderer.isImageTextureLoaded(image)) {
if (mapRenderer.isTileTextureLoaded(tile)) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
return;
} else {
imagesToLoad.push(image);
tilesToLoad.push(tile);
}
} else if (tileState == ol.TileState.ERROR) {
return;
@@ -459,29 +458,28 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
framebufferExtentSize.height - 1;
goog.vec.Vec4.setFromValues(uTileOffset, sx, sy, tx, ty);
gl.uniform4fv(this.locations_.uTileOffset, uTileOffset);
mapRenderer.bindImageTexture(
tile.getImage(), goog.webgl.LINEAR, goog.webgl.LINEAR);
mapRenderer.bindTileTexture(tile, goog.webgl.LINEAR, goog.webgl.LINEAR);
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
}, this);
}, this);
if (!goog.array.isEmpty(imagesToLoad)) {
if (!goog.array.isEmpty(tilesToLoad)) {
goog.events.listenOnce(
map,
ol.MapEventType.POSTRENDER,
goog.partial(function(mapRenderer, imagesToLoad) {
goog.partial(function(mapRenderer, tilesToLoad) {
if (goog.DEBUG) {
this.logger.info(
'uploading ' + imagesToLoad.length + ' textures');
'uploading ' + tilesToLoad.length + ' textures');
}
goog.array.forEach(imagesToLoad, function(image) {
mapRenderer.bindImageTexture(
image, goog.webgl.LINEAR, goog.webgl.LINEAR);
goog.array.forEach(tilesToLoad, function(tile) {
mapRenderer.bindTileTexture(
tile, goog.webgl.LINEAR, goog.webgl.LINEAR);
});
if (goog.DEBUG) {
this.logger.info('uploaded textures');
}
}, mapRenderer, imagesToLoad));
}, mapRenderer, tilesToLoad));
}
if (allTilesLoaded) {

View File

@@ -6,7 +6,7 @@ goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.net.Jsonp');
goog.require('ol.TileCoverageArea');
goog.require('ol.source.TileSource');
goog.require('ol.source.ImageTileSource');
goog.require('ol.tilegrid.XYZ');
@@ -25,7 +25,7 @@ ol.BingMapsStyle = {
/**
* @constructor
* @extends {ol.source.TileSource}
* @extends {ol.source.ImageTileSource}
* @param {ol.source.BingMapsOptions} bingMapsOptions Bing Maps options.
*/
ol.source.BingMaps = function(bingMapsOptions) {
@@ -57,7 +57,7 @@ ol.source.BingMaps = function(bingMapsOptions) {
}, goog.bind(this.handleImageryMetadataResponse, this));
};
goog.inherits(ol.source.BingMaps, ol.source.TileSource);
goog.inherits(ol.source.BingMaps, ol.source.ImageTileSource);
/**

View File

@@ -0,0 +1,125 @@
goog.provide('ol.source.DebugTileSource');
goog.provide('ol.source.DebugTileSourceOptions');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.source.TileSource');
goog.require('ol.tilegrid.TileGrid');
/**
* @constructor
* @extends {ol.Tile}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @private
*/
ol.DebugTile_ = function(tileCoord, tileGrid) {
goog.base(this, tileCoord);
this.state = ol.TileState.LOADED;
var tileSize = tileGrid.getTileSize();
/**
* @private
* @type {HTMLCanvasElement}
*/
this.canvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
this.canvas_.width = tileSize.width;
this.canvas_.height = tileSize.height;
var context = this.canvas_.getContext('2d');
context.strokeStyle = 'black';
context.strokeRect(0.5, 0.5, tileSize.width + 0.5, tileSize.height + 0.5);
context.fillStyle = 'black';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.font = '24px sans-serif';
context.fillText(
tileCoord.toString(), tileSize.width / 2, tileSize.height / 2);
/**
* @private
* @type {Object.<number, HTMLCanvasElement>}
*/
this.canvasByContext_ = {};
};
goog.inherits(ol.DebugTile_, ol.Tile);
/**
* @inheritDoc
*/
ol.DebugTile_.prototype.getImage = function(opt_context) {
if (goog.isDef(opt_context)) {
var canvas;
var key = goog.getUid(opt_context);
if (key in this.canvasByContext_) {
return this.canvasByContext_[key];
} else if (goog.object.isEmpty(this.canvasByContext_)) {
canvas = this.canvas_;
} else {
canvas = /** @type {HTMLCanvasElement} */ (this.canvas_.cloneNode(false));
}
this.canvasByContext_[key] = canvas;
return canvas;
} else {
return this.canvas_;
}
};
/**
* @typedef {{extent: (ol.Extent|undefined),
* projection: (ol.Projection|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined)}}
*/
ol.source.DebugTileSourceOptions;
/**
* @constructor
* @extends {ol.source.TileSource}
* @param {ol.source.DebugTileSourceOptions} options Options.
*/
ol.source.DebugTileSource = function(options) {
goog.base(this, {
extent: options.extent,
projection: options.projection,
tileGrid: options.tileGrid
});
/**
* @private
* @type {Object.<string, ol.DebugTile_>}
* FIXME will need to expire elements from this cache
* FIXME see elemoine's work with goog.structs.LinkedMap
*/
this.tileCache_ = {};
};
goog.inherits(ol.source.DebugTileSource, ol.source.TileSource);
/**
* @inheritDoc
*/
ol.source.DebugTileSource.prototype.getTile = function(tileCoord) {
var key = tileCoord.toString();
if (goog.object.containsKey(this.tileCache_, key)) {
return this.tileCache_[key];
} else {
var tile = new ol.DebugTile_(tileCoord, this.tileGrid);
this.tileCache_[key] = tile;
return tile;
}
};

View File

@@ -0,0 +1,95 @@
goog.provide('ol.source.ImageTileSource');
goog.provide('ol.source.ImageTileSourceOptions');
goog.require('ol.Attribution');
goog.require('ol.Extent');
goog.require('ol.ImageTile');
goog.require('ol.Projection');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType');
goog.require('ol.source.TileSource');
goog.require('ol.tilegrid.TileGrid');
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
* extent: (ol.Extent|undefined),
* projection: (ol.Projection|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* tileUrlFunction: (ol.TileUrlFunctionType|undefined)}}
*/
ol.source.ImageTileSourceOptions;
/**
* @constructor
* @extends {ol.source.TileSource}
* @param {ol.source.ImageTileSourceOptions} options Options.
*/
ol.source.ImageTileSource = function(options) {
goog.base(this, {
attributions: options.attributions,
extent: options.extent,
projection: options.projection,
tileGrid: options.tileGrid
});
/**
* @protected
* @type {ol.TileUrlFunctionType}
*/
this.tileUrlFunction = goog.isDef(options.tileUrlFunction) ?
options.tileUrlFunction :
ol.TileUrlFunction.nullTileUrlFunction;
/**
* @private
* @type {?string}
*/
this.crossOrigin_ =
goog.isDef(options.crossOrigin) ? options.crossOrigin : 'anonymous';
/**
* @private
* @type {Object.<string, ol.ImageTile>}
* FIXME will need to expire elements from this cache
* FIXME see elemoine's work with goog.structs.LinkedMap
*/
this.tileCache_ = {};
};
goog.inherits(ol.source.ImageTileSource, ol.source.TileSource);
/**
* @inheritDoc
*/
ol.source.ImageTileSource.prototype.getTile = function(tileCoord) {
var key = tileCoord.toString();
if (goog.object.containsKey(this.tileCache_, key)) {
return this.tileCache_[key];
} else {
var tileUrl = this.getTileCoordUrl(tileCoord);
var tile;
if (goog.isDef(tileUrl)) {
tile = new ol.ImageTile(tileCoord, tileUrl, this.crossOrigin_);
} else {
tile = null;
}
this.tileCache_[key] = tile;
return tile;
}
};
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @return {string|undefined} Tile URL.
*/
ol.source.ImageTileSource.prototype.getTileCoordUrl = function(tileCoord) {
return this.tileUrlFunction(tileCoord);
};

View File

@@ -10,14 +10,14 @@ goog.require('ol.Attribution');
goog.require('ol.Projection');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.source.TileSource');
goog.require('ol.source.ImageTileSource');
goog.require('ol.tilegrid.TileGrid');
/**
* @constructor
* @extends {ol.source.TileSource}
* @extends {ol.source.ImageTileSource}
* @param {ol.source.TiledWMSOptions} tiledWMSOptions options.
*/
ol.source.TiledWMS = function(tiledWMSOptions) {
@@ -116,4 +116,4 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
});
};
goog.inherits(ol.source.TiledWMS, ol.source.TileSource);
goog.inherits(ol.source.TiledWMS, ol.source.ImageTileSource);

View File

@@ -16,7 +16,7 @@ goog.require('goog.string');
goog.require('ol.Projection');
goog.require('ol.TileCoverageArea');
goog.require('ol.TileUrlFunction');
goog.require('ol.source.TileSource');
goog.require('ol.source.ImageTileSource');
goog.require('ol.tilegrid.XYZ');
@@ -45,7 +45,7 @@ goog.exportSymbol('grid', grid);
/**
* @constructor
* @extends {ol.source.TileSource}
* @extends {ol.source.ImageTileSource}
* @param {ol.source.TileJSONOptions} tileJsonOptions TileJSON optios.
*/
ol.source.TileJSON = function(tileJsonOptions) {
@@ -69,7 +69,7 @@ ol.source.TileJSON = function(tileJsonOptions) {
this.deferred_.addCallback(this.handleTileJSONResponse, this);
};
goog.inherits(ol.source.TileJSON, ol.source.TileSource);
goog.inherits(ol.source.TileJSON, ol.source.ImageTileSource);
/**

View File

@@ -14,11 +14,9 @@ goog.require('ol.tilegrid.TileGrid');
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
* extent: (ol.Extent|undefined),
* projection: (ol.Projection|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* tileUrlFunction: (ol.TileUrlFunctionType|undefined)}}
* tileGrid: (ol.tilegrid.TileGrid|undefined)}}
*/
ol.source.TileSourceOptions;
@@ -44,29 +42,6 @@ ol.source.TileSource = function(tileSourceOptions) {
this.tileGrid = goog.isDef(tileSourceOptions.tileGrid) ?
tileSourceOptions.tileGrid : null;
/**
* @protected
* @type {ol.TileUrlFunctionType}
*/
this.tileUrlFunction = goog.isDef(tileSourceOptions.tileUrlFunction) ?
tileSourceOptions.tileUrlFunction :
ol.TileUrlFunction.nullTileUrlFunction;
/**
* @private
* @type {?string}
*/
this.crossOrigin_ = goog.isDef(tileSourceOptions.crossOrigin) ?
tileSourceOptions.crossOrigin : 'anonymous';
/**
* @private
* @type {Object.<string, ol.Tile>}
* FIXME will need to expire elements from this cache
* FIXME see elemoine's work with goog.structs.LinkedMap
*/
this.tileCache_ = {};
};
goog.inherits(ol.source.TileSource, ol.source.Source);
@@ -83,31 +58,7 @@ ol.source.TileSource.prototype.getResolutions = function() {
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @return {ol.Tile} Tile.
*/
ol.source.TileSource.prototype.getTile = function(tileCoord) {
var key = tileCoord.toString();
if (goog.object.containsKey(this.tileCache_, key)) {
return this.tileCache_[key];
} else {
var tileUrl = this.getTileCoordUrl(tileCoord);
var tile;
if (goog.isDef(tileUrl)) {
tile = new ol.Tile(tileCoord, tileUrl, this.crossOrigin_);
} else {
tile = null;
}
this.tileCache_[key] = tile;
return tile;
}
};
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @return {string|undefined} Tile URL.
*/
ol.source.TileSource.prototype.getTileCoordUrl = function(tileCoord) {
return this.tileUrlFunction(tileCoord);
};
ol.source.TileSource.prototype.getTile = goog.abstractMethod;
/**

View File

@@ -11,7 +11,7 @@ goog.require('ol.Size');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType');
goog.require('ol.source.TileSource');
goog.require('ol.source.ImageTileSource');
goog.require('ol.tilegrid.XYZ');
@@ -31,7 +31,7 @@ ol.source.XYZOptions;
/**
* @constructor
* @extends {ol.source.TileSource}
* @extends {ol.source.ImageTileSource}
* @param {ol.source.XYZOptions} xyzOptions XYZ options.
*/
ol.source.XYZ = function(xyzOptions) {
@@ -110,4 +110,4 @@ ol.source.XYZ = function(xyzOptions) {
});
};
goog.inherits(ol.source.XYZ, ol.source.TileSource);
goog.inherits(ol.source.XYZ, ol.source.ImageTileSource);

View File

@@ -24,10 +24,8 @@ ol.TileState = {
* @constructor
* @extends {goog.events.EventTarget}
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {string} src Image source URI.
* @param {?string} crossOrigin Cross origin.
*/
ol.Tile = function(tileCoord, src, crossOrigin) {
ol.Tile = function(tileCoord) {
goog.base(this);
@@ -37,39 +35,10 @@ ol.Tile = function(tileCoord, src, crossOrigin) {
this.tileCoord = tileCoord;
/**
* Image URI
*
* @private
* @type {string}
*/
this.src_ = src;
/**
* @private
* @protected
* @type {ol.TileState}
*/
this.state_ = ol.TileState.IDLE;
/**
* @private
* @type {Image}
*/
this.image_ = new Image();
if (!goog.isNull(crossOrigin)) {
this.image_.crossOrigin = crossOrigin;
}
/**
* @private
* @type {Object.<number, Image>}
*/
this.imageByContext_ = {};
/**
* @private
* @type {Array.<number>}
*/
this.imageListenerKeys_ = null;
this.state = ol.TileState.IDLE;
};
goog.inherits(ol.Tile, goog.events.EventTarget);
@@ -85,24 +54,16 @@ ol.Tile.prototype.dispatchChangeEvent = function() {
/**
* @param {Object=} opt_context Object.
* @return {Image} Image.
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
*/
ol.Tile.prototype.getImage = function(opt_context) {
if (goog.isDef(opt_context)) {
var image;
var key = goog.getUid(opt_context);
if (key in this.imageByContext_) {
return this.imageByContext_[key];
} else if (goog.object.isEmpty(this.imageByContext_)) {
image = this.image_;
} else {
image = /** @type {Image} */ (this.image_.cloneNode(false));
}
this.imageByContext_[key] = image;
return image;
} else {
return this.image_;
}
ol.Tile.prototype.getImage = goog.abstractMethod;
/**
* @return {string} Key.
*/
ol.Tile.prototype.getKey = function() {
return goog.getUid(this).toString();
};
@@ -110,59 +71,10 @@ ol.Tile.prototype.getImage = function(opt_context) {
* @return {ol.TileState} State.
*/
ol.Tile.prototype.getState = function() {
return this.state_;
return this.state;
};
/**
* Tracks loading or read errors.
*
* @private
*/
ol.Tile.prototype.handleImageError_ = function() {
this.state_ = ol.TileState.ERROR;
this.unlistenImage_();
};
/**
* Tracks successful image load.
*
* @private
*/
ol.Tile.prototype.handleImageLoad_ = function() {
this.state_ = ol.TileState.LOADED;
this.unlistenImage_();
this.dispatchChangeEvent();
};
/**
* Load not yet loaded URI.
*/
ol.Tile.prototype.load = function() {
if (this.state_ == ol.TileState.IDLE) {
this.state_ = ol.TileState.LOADING;
goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
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.Tile.prototype.unlistenImage_ = function() {
goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
this.imageListenerKeys_ = null;
};
ol.Tile.prototype.load = goog.abstractMethod;