diff options
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Control/CacheWrite.js')
-rw-r--r-- | misc/openlayers/lib/OpenLayers/Control/CacheWrite.js | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Control/CacheWrite.js b/misc/openlayers/lib/OpenLayers/Control/CacheWrite.js new file mode 100644 index 0000000..3d4ecf5 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Control/CacheWrite.js @@ -0,0 +1,257 @@ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Request.js + * @requires OpenLayers/Console.js + */ + +/** + * Class: OpenLayers.Control.CacheWrite + * A control for caching image tiles in the browser's local storage. The + * <OpenLayers.Control.CacheRead> control is used to fetch and use the cached + * tile images. + * + * Note: Before using this control on any layer that is not your own, make sure + * that the terms of service of the tile provider allow local storage of tiles. + * + * Inherits from: + * - <OpenLayers.Control> + */ +OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: events + * {<OpenLayers.Events>} Events instance for listeners and triggering + * control specific events. + * + * To register events in the constructor, configure <eventListeners>. + * + * Register a listener for a particular event with the following syntax: + * (code) + * control.events.register(type, obj, listener); + * (end) + * + * Supported event types (in addition to those from <OpenLayers.Control.events>): + * cachefull - Triggered when the cache is full. Listeners receive an + * object with a tile property as first argument. The tile references + * the tile that couldn't be cached. + */ + + /** + * APIProperty: eventListeners + * {Object} Object with event listeners, keyed by event name. An optional + * scope property defines the scope that listeners will be executed in. + */ + + /** + * APIProperty: layers + * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching + * will be enabled for these layers only, otherwise for all cacheable + * layers. + */ + layers: null, + + /** + * APIProperty: imageFormat + * {String} The image format used for caching. The default is "image/png". + * Supported formats depend on the user agent. If an unsupported + * <imageFormat> is provided, "image/png" will be used. For aerial + * imagery, "image/jpeg" is recommended. + */ + imageFormat: "image/png", + + /** + * Property: quotaRegEx + * {RegExp} + */ + quotaRegEx: (/quota/i), + + /** + * Constructor: OpenLayers.Control.CacheWrite + * + * Parameters: + * options - {Object} Object with API properties for this control. + */ + + /** + * Method: setMap + * Set the map property for the control. + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + setMap: function(map) { + OpenLayers.Control.prototype.setMap.apply(this, arguments); + var i, layers = this.layers || map.layers; + for (i=layers.length-1; i>=0; --i) { + this.addLayer({layer: layers[i]}); + } + if (!this.layers) { + map.events.on({ + addlayer: this.addLayer, + removeLayer: this.removeLayer, + scope: this + }); + } + }, + + /** + * Method: addLayer + * Adds a layer to the control. Once added, tiles requested for this layer + * will be cached. + * + * Parameters: + * evt - {Object} Object with a layer property referencing an + * <OpenLayers.Layer> instance + */ + addLayer: function(evt) { + evt.layer.events.on({ + tileloadstart: this.makeSameOrigin, + tileloaded: this.onTileLoaded, + scope: this + }); + }, + + /** + * Method: removeLayer + * Removes a layer from the control. Once removed, tiles requested for this + * layer will no longer be cached. + * + * Parameters: + * evt - {Object} Object with a layer property referencing an + * <OpenLayers.Layer> instance + */ + removeLayer: function(evt) { + evt.layer.events.un({ + tileloadstart: this.makeSameOrigin, + tileloaded: this.onTileLoaded, + scope: this + }); + }, + + /** + * Method: makeSameOrigin + * If the tile does not have CORS image loading enabled and is from a + * different origin, use OpenLayers.ProxyHost to make it a same origin url. + * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + makeSameOrigin: function(evt) { + if (this.active) { + var tile = evt.tile; + if (tile instanceof OpenLayers.Tile.Image && + !tile.crossOriginKeyword && + tile.url.substr(0, 5) !== "data:") { + var sameOriginUrl = OpenLayers.Request.makeSameOrigin( + tile.url, OpenLayers.ProxyHost + ); + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; + tile.url = sameOriginUrl; + } + } + }, + + /** + * Method: onTileLoaded + * Decides whether a tile can be cached and calls the cache method. + * + * Parameters: + * evt - {Event} + */ + onTileLoaded: function(evt) { + if (this.active && !evt.aborted && + evt.tile instanceof OpenLayers.Tile.Image && + evt.tile.url.substr(0, 5) !== 'data:') { + this.cache({tile: evt.tile}); + delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url]; + } + }, + + /** + * Method: cache + * Adds a tile to the cache. When the cache is full, the "cachefull" event + * is triggered. + * + * Parameters: + * obj - {Object} Object with a tile property, tile being the + * <OpenLayers.Tile.Image> with the data to add to the cache + */ + cache: function(obj) { + if (window.localStorage) { + var tile = obj.tile; + try { + var canvasContext = tile.getCanvasContext(); + if (canvasContext) { + var urlMap = OpenLayers.Control.CacheWrite.urlMap; + var url = urlMap[tile.url] || tile.url; + window.localStorage.setItem( + "olCache_" + url, + canvasContext.canvas.toDataURL(this.imageFormat) + ); + } + } catch(e) { + // local storage full or CORS violation + var reason = e.name || e.message; + if (reason && this.quotaRegEx.test(reason)) { + this.events.triggerEvent("cachefull", {tile: tile}); + } else { + OpenLayers.Console.error(e.toString()); + } + } + } + }, + + /** + * Method: destroy + * The destroy method is used to perform any clean up before the control + * is dereferenced. Typically this is where event listeners are removed + * to prevent memory leaks. + */ + destroy: function() { + if (this.layers || this.map) { + var i, layers = this.layers || this.map.layers; + for (i=layers.length-1; i>=0; --i) { + this.removeLayer({layer: layers[i]}); + } + } + if (this.map) { + this.map.events.un({ + addlayer: this.addLayer, + removeLayer: this.removeLayer, + scope: this + }); + } + OpenLayers.Control.prototype.destroy.apply(this, arguments); + }, + + CLASS_NAME: "OpenLayers.Control.CacheWrite" +}); + +/** + * APIFunction: OpenLayers.Control.CacheWrite.clearCache + * Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache. + */ +OpenLayers.Control.CacheWrite.clearCache = function() { + if (!window.localStorage) { return; } + var i, key; + for (i=window.localStorage.length-1; i>=0; --i) { + key = window.localStorage.key(i); + if (key.substr(0, 8) === "olCache_") { + window.localStorage.removeItem(key); + } + } +}; + +/** + * Property: OpenLayers.Control.CacheWrite.urlMap + * {Object} Mapping of same origin urls to cache url keys. Entries will be + * deleted as soon as a tile was cached. + */ +OpenLayers.Control.CacheWrite.urlMap = {}; + + |