1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
/* 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/Layer.js
*/
/**
* Class: OpenLayers.Layer.FixedZoomLevels
* Some Layers will already have established zoom levels (like google
* or ve). Instead of trying to determine them and populate a resolutions[]
* Array with those values, we will hijack the resolution functionality
* here.
*
* When you subclass FixedZoomLevels:
*
* The initResolutions() call gets nullified, meaning no resolutions[] array
* is set up. Which would be a big problem getResolution() in Layer, since
* it merely takes map.zoom and indexes into resolutions[]... but....
*
* The getResolution() call is also overridden. Instead of using the
* resolutions[] array, we simply calculate the current resolution based
* on the current extent and the current map size. But how will we be able
* to calculate the current extent without knowing the resolution...?
*
* The getExtent() function is also overridden. Instead of calculating extent
* based on the center point and the current resolution, we instead
* calculate the extent by getting the lonlats at the top-left and
* bottom-right by using the getLonLatFromViewPortPx() translation function,
* taken from the pixel locations (0,0) and the size of the map. But how
* will we be able to do lonlat-px translation without resolution....?
*
* The getZoomForResolution() method is overridden. Instead of indexing into
* the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
* the desired resolution. With this extent, we then call getZoomForExtent()
*
*
* Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
* it is your responsibility to provide the following three functions:
*
* - getLonLatFromViewPortPx
* - getViewPortPxFromLonLat
* - getZoomForExtent
*
* ...those three functions should generally be provided by any reasonable
* API that you might be working from.
*
*/
OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
/********************************************************/
/* */
/* Baselayer Functions */
/* */
/* The following functions must all be implemented */
/* by all base layers */
/* */
/********************************************************/
/**
* Constructor: OpenLayers.Layer.FixedZoomLevels
* Create a new fixed zoom levels layer.
*/
initialize: function() {
//this class is only just to add the following functions...
// nothing to actually do here... but it is probably a good
// idea to have layers that use these functions call this
// inititalize() anyways, in case at some point we decide we
// do want to put some functionality or state in here.
},
/**
* Method: initResolutions
* Populate the resolutions array
*/
initResolutions: function() {
var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels'];
for(var i=0, len=props.length; i<len; i++) {
var property = props[i];
this[property] = (this.options[property] != null)
? this.options[property]
: this.map[property];
}
if ( (this.minZoomLevel == null) ||
(this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
this.minZoomLevel = this.MIN_ZOOM_LEVEL;
}
//
// At this point, we know what the minimum desired zoom level is, and
// we must calculate the total number of zoom levels.
//
// Because we allow for the setting of either the 'numZoomLevels'
// or the 'maxZoomLevel' properties... on either the layer or the
// map, we have to define some rules to see which we take into
// account first in this calculation.
//
// The following is the precedence list for these properties:
//
// (1) numZoomLevels set on layer
// (2) maxZoomLevel set on layer
// (3) numZoomLevels set on map
// (4) maxZoomLevel set on map*
// (5) none of the above*
//
// *Note that options (4) and (5) are only possible if the user
// _explicitly_ sets the 'numZoomLevels' property on the map to
// null, since it is set by default to 16.
//
//
// Note to future: In 3.0, I think we should remove the default
// value of 16 for map.numZoomLevels. Rather, I think that value
// should be set as a default on the Layer.WMS class. If someone
// creates a 3rd party layer and does not specify any 'minZoomLevel',
// 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
// specified any of those on the map object either.. then I think
// it is fair to say that s/he wants all the zoom levels available.
//
// By making map.numZoomLevels *null* by default, that will be the
// case. As it is, I don't feel comfortable changing that right now
// as it would be a glaring API change and actually would probably
// break many peoples' codes.
//
//the number of zoom levels we'd like to have.
var desiredZoomLevels;
//this is the maximum number of zoom levels the layer will allow,
// given the specified starting minimum zoom level.
var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
if ( ((this.options.numZoomLevels == null) &&
(this.options.maxZoomLevel != null)) // (2)
||
((this.numZoomLevels == null) &&
(this.maxZoomLevel != null)) // (4)
) {
//calculate based on specified maxZoomLevel (on layer or map)
desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
} else {
//calculate based on specified numZoomLevels (on layer or map)
// this covers cases (1) and (3)
desiredZoomLevels = this.numZoomLevels;
}
if (desiredZoomLevels != null) {
//Now that we know what we would *like* the number of zoom levels
// to be, based on layer or map options, we have to make sure that
// it does not conflict with the actual limit, as specified by
// the constants on the layer itself (and calculated into the
// 'limitZoomLevels' variable).
this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
} else {
// case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
// set on either the layer or the map. So we just use the
// maximum limit as calculated by the layer's constants.
this.numZoomLevels = limitZoomLevels;
}
//now that the 'numZoomLevels' is appropriately, safely set,
// we go back and re-calculate the 'maxZoomLevel'.
this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
if (this.RESOLUTIONS != null) {
var resolutionsIndex = 0;
this.resolutions = [];
for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
}
this.maxResolution = this.resolutions[0];
this.minResolution = this.resolutions[this.resolutions.length - 1];
}
},
/**
* APIMethod: getResolution
* Get the current map resolution
*
* Returns:
* {Float} Map units per Pixel
*/
getResolution: function() {
if (this.resolutions != null) {
return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
} else {
var resolution = null;
var viewSize = this.map.getSize();
var extent = this.getExtent();
if ((viewSize != null) && (extent != null)) {
resolution = Math.max( extent.getWidth() / viewSize.w,
extent.getHeight() / viewSize.h );
}
return resolution;
}
},
/**
* APIMethod: getExtent
* Calculates using px-> lonlat translation functions on tl and br
* corners of viewport
*
* Returns:
* {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
* bounds of the current viewPort.
*/
getExtent: function () {
var size = this.map.getSize();
var tl = this.getLonLatFromViewPortPx({
x: 0, y: 0
});
var br = this.getLonLatFromViewPortPx({
x: size.w, y: size.h
});
if ((tl != null) && (br != null)) {
return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat);
} else {
return null;
}
},
/**
* Method: getZoomForResolution
* Get the zoom level for a given resolution
*
* Parameters:
* resolution - {Float}
*
* Returns:
* {Integer} A suitable zoom level for the specified resolution.
* If no baselayer is set, returns null.
*/
getZoomForResolution: function(resolution) {
if (this.resolutions != null) {
return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
} else {
var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
return this.getZoomForExtent(extent);
}
},
/********************************************************/
/* */
/* Translation Functions */
/* */
/* The following functions translate GMaps and OL */
/* formats for Pixel, LonLat, Bounds, and Zoom */
/* */
/********************************************************/
//
// TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
//
/**
* Method: getOLZoomFromMapObjectZoom
* Get the OL zoom index from the map object zoom level
*
* Parameters:
* moZoom - {Integer}
*
* Returns:
* {Integer} An OpenLayers Zoom level, translated from the passed in zoom
* Returns null if null value is passed in
*/
getOLZoomFromMapObjectZoom: function(moZoom) {
var zoom = null;
if (moZoom != null) {
zoom = moZoom - this.minZoomLevel;
if (this.map.baseLayer !== this) {
zoom = this.map.baseLayer.getZoomForResolution(
this.getResolutionForZoom(zoom)
);
}
}
return zoom;
},
/**
* Method: getMapObjectZoomFromOLZoom
* Get the map object zoom level from the OL zoom level
*
* Parameters:
* olZoom - {Integer}
*
* Returns:
* {Integer} A MapObject level, translated from the passed in olZoom
* Returns null if null value is passed in
*/
getMapObjectZoomFromOLZoom: function(olZoom) {
var zoom = null;
if (olZoom != null) {
zoom = olZoom + this.minZoomLevel;
if (this.map.baseLayer !== this) {
zoom = this.getZoomForResolution(
this.map.baseLayer.getResolutionForZoom(zoom)
);
}
}
return zoom;
},
CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
});
|