mirror of
https://github.com/google/earthengine-api.git
synced 2025-12-08 19:26:12 +00:00
251 lines
7.7 KiB
JavaScript
251 lines
7.7 KiB
JavaScript
goog.provide('ee.MapLayerOverlay');
|
|
|
|
goog.require('ee.MapTileManager');
|
|
goog.require('goog.array');
|
|
goog.require('goog.dom');
|
|
goog.require('goog.events.Event');
|
|
goog.require('goog.events.EventTarget');
|
|
goog.require('goog.events.EventType');
|
|
goog.require('goog.iter');
|
|
goog.require('goog.net.EventType');
|
|
goog.require('goog.structs.Set');
|
|
goog.require('goog.style');
|
|
|
|
|
|
|
|
/**
|
|
* A google.maps.MapType implementation used to display Earth Engine tiles.
|
|
* This class behaves much like an ImageMapType, but emits events when tiles
|
|
* are loaded.
|
|
* @param {string} url The url for fetching this layer's tiles.
|
|
* @param {string} mapId The map ID for fetching this layer's tiles.
|
|
* @param {string} token The temporary token for fetching tiles.
|
|
* @param {Object} init Initialization options, of the same form as a
|
|
* google.maps.ImageMapTypeOptions object.
|
|
* @constructor
|
|
* @extends {goog.events.EventTarget}
|
|
* @ignore
|
|
*/
|
|
ee.MapLayerOverlay = function(url, mapId, token, init) {
|
|
goog.base(this);
|
|
|
|
// Store mapId and token.
|
|
this.mapId = mapId;
|
|
this.token = token;
|
|
|
|
// Set ImageMapTypeOptions properties.
|
|
this.minZoom = init.minZoom || 0;
|
|
this.maxZoom = init.maxZoom || 20;
|
|
if (!window['google'] || !window['google']['maps']) {
|
|
throw Error("Google Maps API hasn't been initialized.");
|
|
}
|
|
this.tileSize = init.tileSize || new google.maps.Size(256, 256);
|
|
this.isPng = goog.isDef(init.isPng) ? init.isPng : true;
|
|
|
|
/**
|
|
* Array representing the set of tiles that are currently being
|
|
* loaded. They are added to this array by getTile() and removed
|
|
* with handleImageCompleted_().
|
|
* @private {!Array.<string>}
|
|
*/
|
|
this.tilesLoading_ = [];
|
|
|
|
/** @private {goog.structs.Set} The set of loaded tiles. */
|
|
this.tiles_ = new goog.structs.Set();
|
|
|
|
/** @private {goog.structs.Set} The set of failed tile IDs. */
|
|
this.tilesFailed_ = new goog.structs.Set();
|
|
|
|
/**
|
|
* Incrementing counter that helps make tile request ids unique.
|
|
* @private {number}
|
|
*/
|
|
this.tileCounter_ = 0;
|
|
|
|
/** @protected {string} The url from which to fetch tiles. */
|
|
this.url = url;
|
|
|
|
/** @private {number} The layer's opacity. */
|
|
this.opacity_ = 1.0;
|
|
|
|
/** @private {boolean} Whether the layer is currently visible. */
|
|
this.visible_ = true;
|
|
};
|
|
goog.inherits(ee.MapLayerOverlay, goog.events.EventTarget);
|
|
|
|
|
|
/** @enum {string} Event types. */
|
|
ee.MapLayerOverlay.EventType = {
|
|
TILE_LOADED: 'tileevent'
|
|
};
|
|
|
|
|
|
/**
|
|
* Send an event about a change in the number of outstanding tiles.
|
|
* @private
|
|
*/
|
|
ee.MapLayerOverlay.prototype.dispatchTileEvent_ = function() {
|
|
this.dispatchEvent(new ee.TileEvent_(this.tilesLoading_.length));
|
|
};
|
|
|
|
|
|
/**
|
|
* Implements getTile() for the google.maps.MapType interface.
|
|
* @param {google.maps.Point} coord Position of tile.
|
|
* @param {number} zoom Zoom level.
|
|
* @param {Node} ownerDocument Parent document.
|
|
* @return {Node} Element to be displayed as a map tile.
|
|
*/
|
|
ee.MapLayerOverlay.prototype.getTile = function(
|
|
coord, zoom, ownerDocument) {
|
|
var result;
|
|
var maxCoord = 1 << zoom;
|
|
if (zoom < this.minZoom || coord.y < 0 || coord.y >= maxCoord) {
|
|
// Construct and return the tile immediately.
|
|
var img = ownerDocument.createElement('IMG');
|
|
img.style.width = '0px';
|
|
img.style.height = '0px';
|
|
return img;
|
|
}
|
|
// Wrap longitude around.
|
|
var x = coord.x % maxCoord;
|
|
if (x < 0) {
|
|
x += maxCoord;
|
|
}
|
|
|
|
var tileId = [this.mapId, zoom, x, coord.y].join('/');
|
|
var src = [this.url, tileId].join('/') + '?token=' + this.token;
|
|
|
|
// Append a unique string to the tileid to make sure that
|
|
// repeated requests for the same tile and cancellations thereof
|
|
// (which may occur if the user quickly moves the map around)
|
|
// don't overwrite each other's state.
|
|
var uniqueTileId = tileId + '/' + this.tileCounter_;
|
|
this.tileCounter_ += 1;
|
|
|
|
var div = goog.dom.createDom('div', {'id': uniqueTileId});
|
|
|
|
// Use the current time in seconds as the priority for the tile
|
|
// loading queue. Smaller priorities move to the front of the queue,
|
|
// which is what we want - the Maps API loads the tiles in a spiral
|
|
// starting from the center, and we would like to preserve this order.
|
|
// Requests for tiles that are no longer visible won't clog the queue:
|
|
// if the map is moved around a lot, Maps API calls our releaseTile()
|
|
// method, and the obsolete requests will be removed from the queue.
|
|
var priority = new Date().getTime() / 1000;
|
|
this.tilesLoading_.push(uniqueTileId);
|
|
ee.MapTileManager.getInstance().send(
|
|
uniqueTileId, src, priority,
|
|
goog.bind(this.handleImageCompleted_, this, div, uniqueTileId));
|
|
this.dispatchTileEvent_();
|
|
result = div;
|
|
return result;
|
|
};
|
|
|
|
|
|
/** @return {number} The number of tiles successfully loaded. */
|
|
ee.MapLayerOverlay.prototype.getLoadedTilesCount = function() {
|
|
return this.tiles_.getCount();
|
|
};
|
|
|
|
|
|
/** @return {number} The number of tiles currently loading. */
|
|
ee.MapLayerOverlay.prototype.getLoadingTilesCount = function() {
|
|
return this.tilesLoading_.length;
|
|
};
|
|
|
|
|
|
/** @return {number} The number of tiles which have failed. */
|
|
ee.MapLayerOverlay.prototype.getFailedTilesCount = function() {
|
|
return this.tilesFailed_.getCount();
|
|
};
|
|
|
|
|
|
/**
|
|
* Implements releaseTile() for the google.maps.MapType
|
|
* interface.
|
|
* @param {Node} tileDiv The tile that has been released.
|
|
*/
|
|
ee.MapLayerOverlay.prototype.releaseTile = function(tileDiv) {
|
|
ee.MapTileManager.getInstance().abort(tileDiv.id);
|
|
var tileImg = goog.dom.getFirstElementChild(tileDiv);
|
|
this.tiles_.remove(tileImg);
|
|
this.tilesFailed_.remove(tileDiv.id);
|
|
};
|
|
|
|
|
|
/**
|
|
* Implements setOpacity() for the google.maps.MapType interface.
|
|
* @param {number} opacity The opacity to set this layer to.
|
|
*/
|
|
ee.MapLayerOverlay.prototype.setOpacity = function(opacity) {
|
|
this.opacity_ = opacity;
|
|
var iter = this.tiles_.__iterator__();
|
|
goog.iter.forEach(iter, function(tile) {
|
|
goog.style.setOpacity(tile, opacity);
|
|
});
|
|
};
|
|
|
|
// Export getTile and removeTile so they are not eliminated by dead
|
|
// code removal during compilation
|
|
goog.exportProperty(
|
|
ee.MapLayerOverlay.prototype,
|
|
'getTile',
|
|
ee.MapLayerOverlay.prototype.getTile);
|
|
goog.exportProperty(
|
|
ee.MapLayerOverlay.prototype,
|
|
'setOpacity',
|
|
ee.MapLayerOverlay.prototype.setOpacity);
|
|
goog.exportProperty(
|
|
ee.MapLayerOverlay.prototype,
|
|
'releaseTile',
|
|
ee.MapLayerOverlay.prototype.releaseTile);
|
|
|
|
|
|
/**
|
|
* Handle image 'load' and 'error' events. When the last one has
|
|
* finished, dispatch an ee.MapLayerOverlay.EventType.TILE_LOADED event.
|
|
* Handle bookkeeping to keep the tilesLoading_ array accurate.
|
|
* @param {Node} div Tile div to which images should be appended.
|
|
* @param {string} tileId The id of the tile that was requested.
|
|
* @param {goog.events.Event} e Image loading event.
|
|
* @private
|
|
*/
|
|
ee.MapLayerOverlay.prototype.handleImageCompleted_ = function(
|
|
div, tileId, e) {
|
|
if (e.type == goog.net.EventType.ERROR) {
|
|
// Forward error events.
|
|
goog.array.remove(this.tilesLoading_, tileId);
|
|
this.tilesFailed_.add(tileId);
|
|
this.dispatchEvent(e);
|
|
} else {
|
|
// Convert tile loading events to our own type.
|
|
goog.array.remove(this.tilesLoading_, tileId);
|
|
var tile;
|
|
if (e.target && (e.type == goog.events.EventType.LOAD)) {
|
|
tile = /** @type {Node} */ (e.target);
|
|
this.tiles_.add(tile);
|
|
if (this.opacity_ != 1.0) {
|
|
goog.style.setOpacity(/** @type {Element} */ (tile), this.opacity_);
|
|
}
|
|
div.appendChild(tile);
|
|
}
|
|
this.dispatchTileEvent_();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* An event contaning the information about the tile status
|
|
* @param {number} count The number of outstanding tile requests.
|
|
* @constructor
|
|
* @private
|
|
* @extends {goog.events.Event}
|
|
*/
|
|
ee.TileEvent_ = function(count) {
|
|
goog.events.Event.call(this, ee.MapLayerOverlay.EventType.TILE_LOADED);
|
|
this.count = count;
|
|
};
|
|
goog.inherits(ee.TileEvent_, goog.events.Event);
|