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
|
/**
|
8
|
* @requires OpenLayers/BaseTypes/Class.js
|
9
|
* @requires OpenLayers/Util.js
|
10
|
*/
|
11
|
|
12
|
/**
|
13
|
* Class: OpenLayers.Tile
|
14
|
* This is a class designed to designate a single tile, however
|
15
|
* it is explicitly designed to do relatively little. Tiles store
|
16
|
* information about themselves -- such as the URL that they are related
|
17
|
* to, and their size - but do not add themselves to the layer div
|
18
|
* automatically, for example. Create a new tile with the
|
19
|
* <OpenLayers.Tile> constructor, or a subclass.
|
20
|
*
|
21
|
* TBD 3.0 - remove reference to url in above paragraph
|
22
|
*
|
23
|
*/
|
24
|
OpenLayers.Tile = OpenLayers.Class({
|
25
|
|
26
|
/**
|
27
|
* APIProperty: events
|
28
|
* {<OpenLayers.Events>} An events object that handles all
|
29
|
* events on the tile.
|
30
|
*
|
31
|
* Register a listener for a particular event with the following syntax:
|
32
|
* (code)
|
33
|
* tile.events.register(type, obj, listener);
|
34
|
* (end)
|
35
|
*
|
36
|
* Supported event types:
|
37
|
* beforedraw - Triggered before the tile is drawn. Used to defer
|
38
|
* drawing to an animation queue. To defer drawing, listeners need
|
39
|
* to return false, which will abort drawing. The queue handler needs
|
40
|
* to call <draw>(true) to actually draw the tile.
|
41
|
* loadstart - Triggered when tile loading starts.
|
42
|
* loadend - Triggered when tile loading ends.
|
43
|
* loaderror - Triggered before the loadend event (i.e. when the tile is
|
44
|
* still hidden) if the tile could not be loaded.
|
45
|
* reload - Triggered when an already loading tile is reloaded.
|
46
|
* unload - Triggered before a tile is unloaded.
|
47
|
*/
|
48
|
events: null,
|
49
|
|
50
|
/**
|
51
|
* APIProperty: eventListeners
|
52
|
* {Object} If set as an option at construction, the eventListeners
|
53
|
* object will be registered with <OpenLayers.Events.on>. Object
|
54
|
* structure must be a listeners object as shown in the example for
|
55
|
* the events.on method.
|
56
|
*
|
57
|
* This options can be set in the ``tileOptions`` option from
|
58
|
* <OpenLayers.Layer.Grid>. For example, to be notified of the
|
59
|
* ``loadend`` event of each tiles:
|
60
|
* (code)
|
61
|
* new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', {
|
62
|
* tileOptions: {
|
63
|
* eventListeners: {
|
64
|
* 'loadend': function(evt) {
|
65
|
* // do something on loadend
|
66
|
* }
|
67
|
* }
|
68
|
* }
|
69
|
* });
|
70
|
* (end)
|
71
|
*/
|
72
|
eventListeners: null,
|
73
|
|
74
|
/**
|
75
|
* Property: id
|
76
|
* {String} null
|
77
|
*/
|
78
|
id: null,
|
79
|
|
80
|
/**
|
81
|
* Property: layer
|
82
|
* {<OpenLayers.Layer>} layer the tile is attached to
|
83
|
*/
|
84
|
layer: null,
|
85
|
|
86
|
/**
|
87
|
* Property: url
|
88
|
* {String} url of the request.
|
89
|
*
|
90
|
* TBD 3.0
|
91
|
* Deprecated. The base tile class does not need an url. This should be
|
92
|
* handled in subclasses. Does not belong here.
|
93
|
*/
|
94
|
url: null,
|
95
|
|
96
|
/**
|
97
|
* APIProperty: bounds
|
98
|
* {<OpenLayers.Bounds>} null
|
99
|
*/
|
100
|
bounds: null,
|
101
|
|
102
|
/**
|
103
|
* Property: size
|
104
|
* {<OpenLayers.Size>} null
|
105
|
*/
|
106
|
size: null,
|
107
|
|
108
|
/**
|
109
|
* Property: position
|
110
|
* {<OpenLayers.Pixel>} Top Left pixel of the tile
|
111
|
*/
|
112
|
position: null,
|
113
|
|
114
|
/**
|
115
|
* Property: isLoading
|
116
|
* {Boolean} Is the tile loading?
|
117
|
*/
|
118
|
isLoading: false,
|
119
|
|
120
|
/** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
|
121
|
* there is no need for the base tile class to have a url.
|
122
|
*/
|
123
|
|
124
|
/**
|
125
|
* Constructor: OpenLayers.Tile
|
126
|
* Constructor for a new <OpenLayers.Tile> instance.
|
127
|
*
|
128
|
* Parameters:
|
129
|
* layer - {<OpenLayers.Layer>} layer that the tile will go in.
|
130
|
* position - {<OpenLayers.Pixel>}
|
131
|
* bounds - {<OpenLayers.Bounds>}
|
132
|
* url - {<String>}
|
133
|
* size - {<OpenLayers.Size>}
|
134
|
* options - {Object}
|
135
|
*/
|
136
|
initialize: function(layer, position, bounds, url, size, options) {
|
137
|
this.layer = layer;
|
138
|
this.position = position.clone();
|
139
|
this.setBounds(bounds);
|
140
|
this.url = url;
|
141
|
if (size) {
|
142
|
this.size = size.clone();
|
143
|
}
|
144
|
|
145
|
//give the tile a unique id based on its BBOX.
|
146
|
this.id = OpenLayers.Util.createUniqueID("Tile_");
|
147
|
|
148
|
OpenLayers.Util.extend(this, options);
|
149
|
|
150
|
this.events = new OpenLayers.Events(this);
|
151
|
if (this.eventListeners instanceof Object) {
|
152
|
this.events.on(this.eventListeners);
|
153
|
}
|
154
|
},
|
155
|
|
156
|
/**
|
157
|
* Method: unload
|
158
|
* Call immediately before destroying if you are listening to tile
|
159
|
* events, so that counters are properly handled if tile is still
|
160
|
* loading at destroy-time. Will only fire an event if the tile is
|
161
|
* still loading.
|
162
|
*/
|
163
|
unload: function() {
|
164
|
if (this.isLoading) {
|
165
|
this.isLoading = false;
|
166
|
this.events.triggerEvent("unload");
|
167
|
}
|
168
|
},
|
169
|
|
170
|
/**
|
171
|
* APIMethod: destroy
|
172
|
* Nullify references to prevent circular references and memory leaks.
|
173
|
*/
|
174
|
destroy:function() {
|
175
|
this.layer = null;
|
176
|
this.bounds = null;
|
177
|
this.size = null;
|
178
|
this.position = null;
|
179
|
|
180
|
if (this.eventListeners) {
|
181
|
this.events.un(this.eventListeners);
|
182
|
}
|
183
|
this.events.destroy();
|
184
|
this.eventListeners = null;
|
185
|
this.events = null;
|
186
|
},
|
187
|
|
188
|
/**
|
189
|
* Method: draw
|
190
|
* Clear whatever is currently in the tile, then return whether or not
|
191
|
* it should actually be re-drawn. This is an example implementation
|
192
|
* that can be overridden by subclasses. The minimum thing to do here
|
193
|
* is to call <clear> and return the result from <shouldDraw>.
|
194
|
*
|
195
|
* Parameters:
|
196
|
* force - {Boolean} If true, the tile will not be cleared and no beforedraw
|
197
|
* event will be fired. This is used for drawing tiles asynchronously
|
198
|
* after drawing has been cancelled by returning false from a beforedraw
|
199
|
* listener.
|
200
|
*
|
201
|
* Returns:
|
202
|
* {Boolean} Whether or not the tile should actually be drawn. Returns null
|
203
|
* if a beforedraw listener returned false.
|
204
|
*/
|
205
|
draw: function(force) {
|
206
|
if (!force) {
|
207
|
//clear tile's contents and mark as not drawn
|
208
|
this.clear();
|
209
|
}
|
210
|
var draw = this.shouldDraw();
|
211
|
if (draw && !force && this.events.triggerEvent("beforedraw") === false) {
|
212
|
draw = null;
|
213
|
}
|
214
|
return draw;
|
215
|
},
|
216
|
|
217
|
/**
|
218
|
* Method: shouldDraw
|
219
|
* Return whether or not the tile should actually be (re-)drawn. The only
|
220
|
* case where we *wouldn't* want to draw the tile is if the tile is outside
|
221
|
* its layer's maxExtent
|
222
|
*
|
223
|
* Returns:
|
224
|
* {Boolean} Whether or not the tile should actually be drawn.
|
225
|
*/
|
226
|
shouldDraw: function() {
|
227
|
var withinMaxExtent = false,
|
228
|
maxExtent = this.layer.maxExtent;
|
229
|
if (maxExtent) {
|
230
|
var map = this.layer.map;
|
231
|
var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();
|
232
|
if (this.bounds.intersectsBounds(maxExtent, {inclusive: false, worldBounds: worldBounds})) {
|
233
|
withinMaxExtent = true;
|
234
|
}
|
235
|
}
|
236
|
|
237
|
return withinMaxExtent || this.layer.displayOutsideMaxExtent;
|
238
|
},
|
239
|
|
240
|
/**
|
241
|
* Method: setBounds
|
242
|
* Sets the bounds on this instance
|
243
|
*
|
244
|
* Parameters:
|
245
|
* bounds {<OpenLayers.Bounds>}
|
246
|
*/
|
247
|
setBounds: function(bounds) {
|
248
|
bounds = bounds.clone();
|
249
|
if (this.layer.map.baseLayer.wrapDateLine) {
|
250
|
var worldExtent = this.layer.map.getMaxExtent(),
|
251
|
tolerance = this.layer.map.getResolution();
|
252
|
bounds = bounds.wrapDateLine(worldExtent, {
|
253
|
leftTolerance: tolerance,
|
254
|
rightTolerance: tolerance
|
255
|
});
|
256
|
}
|
257
|
this.bounds = bounds;
|
258
|
},
|
259
|
|
260
|
/**
|
261
|
* Method: moveTo
|
262
|
* Reposition the tile.
|
263
|
*
|
264
|
* Parameters:
|
265
|
* bounds - {<OpenLayers.Bounds>}
|
266
|
* position - {<OpenLayers.Pixel>}
|
267
|
* redraw - {Boolean} Call draw method on tile after moving.
|
268
|
* Default is true
|
269
|
*/
|
270
|
moveTo: function (bounds, position, redraw) {
|
271
|
if (redraw == null) {
|
272
|
redraw = true;
|
273
|
}
|
274
|
|
275
|
this.setBounds(bounds);
|
276
|
this.position = position.clone();
|
277
|
if (redraw) {
|
278
|
this.draw();
|
279
|
}
|
280
|
},
|
281
|
|
282
|
/**
|
283
|
* Method: clear
|
284
|
* Clear the tile of any bounds/position-related data so that it can
|
285
|
* be reused in a new location.
|
286
|
*/
|
287
|
clear: function(draw) {
|
288
|
// to be extended by subclasses
|
289
|
},
|
290
|
|
291
|
CLASS_NAME: "OpenLayers.Tile"
|
292
|
});
|