Project

General

Profile

Download (8.08 KB) Statistics
| Branch: | Tag: | Revision:
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

    
(5-5/45)