Merge pull request #99 from twpayne/beyond-image-tiles
Beyond image tiles
This commit is contained in:
38
examples/canvas-tiles.html
Normal file
38
examples/canvas-tiles.html
Normal 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
43
examples/canvas-tiles.js
Normal 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
137
src/ol/imagetile.js
Normal 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;
|
||||
};
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
125
src/ol/source/debugtilesource.js
Normal file
125
src/ol/source/debugtilesource.js
Normal 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;
|
||||
}
|
||||
};
|
||||
95
src/ol/source/imagetilesource.js
Normal file
95
src/ol/source/imagetilesource.js
Normal 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);
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
116
src/ol/tile.js
116
src/ol/tile.js
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user