1
|
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
|
2
|
* full list of contributors). Published under the 2-clause BSD license.
|
3
|
* See license.txt in the OpenLayers distribution or repository for the
|
4
|
* full text of the license. */
|
5
|
|
6
|
/**
|
7
|
* @requires OpenLayers/Control.js
|
8
|
* @requires OpenLayers/Request.js
|
9
|
* @requires OpenLayers/Console.js
|
10
|
*/
|
11
|
|
12
|
/**
|
13
|
* Class: OpenLayers.Control.CacheWrite
|
14
|
* A control for caching image tiles in the browser's local storage. The
|
15
|
* <OpenLayers.Control.CacheRead> control is used to fetch and use the cached
|
16
|
* tile images.
|
17
|
*
|
18
|
* Note: Before using this control on any layer that is not your own, make sure
|
19
|
* that the terms of service of the tile provider allow local storage of tiles.
|
20
|
*
|
21
|
* Inherits from:
|
22
|
* - <OpenLayers.Control>
|
23
|
*/
|
24
|
OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
|
25
|
|
26
|
/**
|
27
|
* APIProperty: events
|
28
|
* {<OpenLayers.Events>} Events instance for listeners and triggering
|
29
|
* control specific events.
|
30
|
*
|
31
|
* To register events in the constructor, configure <eventListeners>.
|
32
|
*
|
33
|
* Register a listener for a particular event with the following syntax:
|
34
|
* (code)
|
35
|
* control.events.register(type, obj, listener);
|
36
|
* (end)
|
37
|
*
|
38
|
* Supported event types (in addition to those from <OpenLayers.Control.events>):
|
39
|
* cachefull - Triggered when the cache is full. Listeners receive an
|
40
|
* object with a tile property as first argument. The tile references
|
41
|
* the tile that couldn't be cached.
|
42
|
*/
|
43
|
|
44
|
/**
|
45
|
* APIProperty: eventListeners
|
46
|
* {Object} Object with event listeners, keyed by event name. An optional
|
47
|
* scope property defines the scope that listeners will be executed in.
|
48
|
*/
|
49
|
|
50
|
/**
|
51
|
* APIProperty: layers
|
52
|
* {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching
|
53
|
* will be enabled for these layers only, otherwise for all cacheable
|
54
|
* layers.
|
55
|
*/
|
56
|
layers: null,
|
57
|
|
58
|
/**
|
59
|
* APIProperty: imageFormat
|
60
|
* {String} The image format used for caching. The default is "image/png".
|
61
|
* Supported formats depend on the user agent. If an unsupported
|
62
|
* <imageFormat> is provided, "image/png" will be used. For aerial
|
63
|
* imagery, "image/jpeg" is recommended.
|
64
|
*/
|
65
|
imageFormat: "image/png",
|
66
|
|
67
|
/**
|
68
|
* Property: quotaRegEx
|
69
|
* {RegExp}
|
70
|
*/
|
71
|
quotaRegEx: (/quota/i),
|
72
|
|
73
|
/**
|
74
|
* Constructor: OpenLayers.Control.CacheWrite
|
75
|
*
|
76
|
* Parameters:
|
77
|
* options - {Object} Object with API properties for this control.
|
78
|
*/
|
79
|
|
80
|
/**
|
81
|
* Method: setMap
|
82
|
* Set the map property for the control.
|
83
|
*
|
84
|
* Parameters:
|
85
|
* map - {<OpenLayers.Map>}
|
86
|
*/
|
87
|
setMap: function(map) {
|
88
|
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
89
|
var i, layers = this.layers || map.layers;
|
90
|
for (i=layers.length-1; i>=0; --i) {
|
91
|
this.addLayer({layer: layers[i]});
|
92
|
}
|
93
|
if (!this.layers) {
|
94
|
map.events.on({
|
95
|
addlayer: this.addLayer,
|
96
|
removeLayer: this.removeLayer,
|
97
|
scope: this
|
98
|
});
|
99
|
}
|
100
|
},
|
101
|
|
102
|
/**
|
103
|
* Method: addLayer
|
104
|
* Adds a layer to the control. Once added, tiles requested for this layer
|
105
|
* will be cached.
|
106
|
*
|
107
|
* Parameters:
|
108
|
* evt - {Object} Object with a layer property referencing an
|
109
|
* <OpenLayers.Layer> instance
|
110
|
*/
|
111
|
addLayer: function(evt) {
|
112
|
evt.layer.events.on({
|
113
|
tileloadstart: this.makeSameOrigin,
|
114
|
tileloaded: this.onTileLoaded,
|
115
|
scope: this
|
116
|
});
|
117
|
},
|
118
|
|
119
|
/**
|
120
|
* Method: removeLayer
|
121
|
* Removes a layer from the control. Once removed, tiles requested for this
|
122
|
* layer will no longer be cached.
|
123
|
*
|
124
|
* Parameters:
|
125
|
* evt - {Object} Object with a layer property referencing an
|
126
|
* <OpenLayers.Layer> instance
|
127
|
*/
|
128
|
removeLayer: function(evt) {
|
129
|
evt.layer.events.un({
|
130
|
tileloadstart: this.makeSameOrigin,
|
131
|
tileloaded: this.onTileLoaded,
|
132
|
scope: this
|
133
|
});
|
134
|
},
|
135
|
|
136
|
/**
|
137
|
* Method: makeSameOrigin
|
138
|
* If the tile does not have CORS image loading enabled and is from a
|
139
|
* different origin, use OpenLayers.ProxyHost to make it a same origin url.
|
140
|
*
|
141
|
* Parameters:
|
142
|
* evt - {<OpenLayers.Event>}
|
143
|
*/
|
144
|
makeSameOrigin: function(evt) {
|
145
|
if (this.active) {
|
146
|
var tile = evt.tile;
|
147
|
if (tile instanceof OpenLayers.Tile.Image &&
|
148
|
!tile.crossOriginKeyword &&
|
149
|
tile.url.substr(0, 5) !== "data:") {
|
150
|
var sameOriginUrl = OpenLayers.Request.makeSameOrigin(
|
151
|
tile.url, OpenLayers.ProxyHost
|
152
|
);
|
153
|
OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url;
|
154
|
tile.url = sameOriginUrl;
|
155
|
}
|
156
|
}
|
157
|
},
|
158
|
|
159
|
/**
|
160
|
* Method: onTileLoaded
|
161
|
* Decides whether a tile can be cached and calls the cache method.
|
162
|
*
|
163
|
* Parameters:
|
164
|
* evt - {Event}
|
165
|
*/
|
166
|
onTileLoaded: function(evt) {
|
167
|
if (this.active && !evt.aborted &&
|
168
|
evt.tile instanceof OpenLayers.Tile.Image &&
|
169
|
evt.tile.url.substr(0, 5) !== 'data:') {
|
170
|
this.cache({tile: evt.tile});
|
171
|
delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url];
|
172
|
}
|
173
|
},
|
174
|
|
175
|
/**
|
176
|
* Method: cache
|
177
|
* Adds a tile to the cache. When the cache is full, the "cachefull" event
|
178
|
* is triggered.
|
179
|
*
|
180
|
* Parameters:
|
181
|
* obj - {Object} Object with a tile property, tile being the
|
182
|
* <OpenLayers.Tile.Image> with the data to add to the cache
|
183
|
*/
|
184
|
cache: function(obj) {
|
185
|
if (window.localStorage) {
|
186
|
var tile = obj.tile;
|
187
|
try {
|
188
|
var canvasContext = tile.getCanvasContext();
|
189
|
if (canvasContext) {
|
190
|
var urlMap = OpenLayers.Control.CacheWrite.urlMap;
|
191
|
var url = urlMap[tile.url] || tile.url;
|
192
|
window.localStorage.setItem(
|
193
|
"olCache_" + url,
|
194
|
canvasContext.canvas.toDataURL(this.imageFormat)
|
195
|
);
|
196
|
}
|
197
|
} catch(e) {
|
198
|
// local storage full or CORS violation
|
199
|
var reason = e.name || e.message;
|
200
|
if (reason && this.quotaRegEx.test(reason)) {
|
201
|
this.events.triggerEvent("cachefull", {tile: tile});
|
202
|
} else {
|
203
|
OpenLayers.Console.error(e.toString());
|
204
|
}
|
205
|
}
|
206
|
}
|
207
|
},
|
208
|
|
209
|
/**
|
210
|
* Method: destroy
|
211
|
* The destroy method is used to perform any clean up before the control
|
212
|
* is dereferenced. Typically this is where event listeners are removed
|
213
|
* to prevent memory leaks.
|
214
|
*/
|
215
|
destroy: function() {
|
216
|
if (this.layers || this.map) {
|
217
|
var i, layers = this.layers || this.map.layers;
|
218
|
for (i=layers.length-1; i>=0; --i) {
|
219
|
this.removeLayer({layer: layers[i]});
|
220
|
}
|
221
|
}
|
222
|
if (this.map) {
|
223
|
this.map.events.un({
|
224
|
addlayer: this.addLayer,
|
225
|
removeLayer: this.removeLayer,
|
226
|
scope: this
|
227
|
});
|
228
|
}
|
229
|
OpenLayers.Control.prototype.destroy.apply(this, arguments);
|
230
|
},
|
231
|
|
232
|
CLASS_NAME: "OpenLayers.Control.CacheWrite"
|
233
|
});
|
234
|
|
235
|
/**
|
236
|
* APIFunction: OpenLayers.Control.CacheWrite.clearCache
|
237
|
* Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache.
|
238
|
*/
|
239
|
OpenLayers.Control.CacheWrite.clearCache = function() {
|
240
|
if (!window.localStorage) { return; }
|
241
|
var i, key;
|
242
|
for (i=window.localStorage.length-1; i>=0; --i) {
|
243
|
key = window.localStorage.key(i);
|
244
|
if (key.substr(0, 8) === "olCache_") {
|
245
|
window.localStorage.removeItem(key);
|
246
|
}
|
247
|
}
|
248
|
};
|
249
|
|
250
|
/**
|
251
|
* Property: OpenLayers.Control.CacheWrite.urlMap
|
252
|
* {Object} Mapping of same origin urls to cache url keys. Entries will be
|
253
|
* deleted as soon as a tile was cached.
|
254
|
*/
|
255
|
OpenLayers.Control.CacheWrite.urlMap = {};
|
256
|
|
257
|
|