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/BaseTypes.js
|
9
|
* @requires OpenLayers/Events/buttonclick.js
|
10
|
* @requires OpenLayers/Map.js
|
11
|
* @requires OpenLayers/Handler/Click.js
|
12
|
* @requires OpenLayers/Handler/Drag.js
|
13
|
*/
|
14
|
|
15
|
/**
|
16
|
* Class: OpenLayers.Control.OverviewMap
|
17
|
* The OverMap control creates a small overview map, useful to display the
|
18
|
* extent of a zoomed map and your main map and provide additional
|
19
|
* navigation options to the User. By default the overview map is drawn in
|
20
|
* the lower right corner of the main map. Create a new overview map with the
|
21
|
* <OpenLayers.Control.OverviewMap> constructor.
|
22
|
*
|
23
|
* Inherits from:
|
24
|
* - <OpenLayers.Control>
|
25
|
*/
|
26
|
OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
|
27
|
|
28
|
/**
|
29
|
* Property: element
|
30
|
* {DOMElement} The DOM element that contains the overview map
|
31
|
*/
|
32
|
element: null,
|
33
|
|
34
|
/**
|
35
|
* APIProperty: ovmap
|
36
|
* {<OpenLayers.Map>} A reference to the overview map itself.
|
37
|
*/
|
38
|
ovmap: null,
|
39
|
|
40
|
/**
|
41
|
* APIProperty: size
|
42
|
* {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
|
43
|
* the size of the map itself - the element that contains the map (default
|
44
|
* class name olControlOverviewMapElement) may have padding or other style
|
45
|
* attributes added via CSS.
|
46
|
*/
|
47
|
size: {w: 180, h: 90},
|
48
|
|
49
|
/**
|
50
|
* APIProperty: layers
|
51
|
* {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
|
52
|
* If none are sent at construction, the base layer for the main map is used.
|
53
|
*/
|
54
|
layers: null,
|
55
|
|
56
|
/**
|
57
|
* APIProperty: minRectSize
|
58
|
* {Integer} The minimum width or height (in pixels) of the extent
|
59
|
* rectangle on the overview map. When the extent rectangle reaches
|
60
|
* this size, it will be replaced depending on the value of the
|
61
|
* <minRectDisplayClass> property. Default is 15 pixels.
|
62
|
*/
|
63
|
minRectSize: 15,
|
64
|
|
65
|
/**
|
66
|
* APIProperty: minRectDisplayClass
|
67
|
* {String} Replacement style class name for the extent rectangle when
|
68
|
* <minRectSize> is reached. This string will be suffixed on to the
|
69
|
* displayClass. Default is "RectReplacement".
|
70
|
*
|
71
|
* Example CSS declaration:
|
72
|
* (code)
|
73
|
* .olControlOverviewMapRectReplacement {
|
74
|
* overflow: hidden;
|
75
|
* cursor: move;
|
76
|
* background-image: url("img/overview_replacement.gif");
|
77
|
* background-repeat: no-repeat;
|
78
|
* background-position: center;
|
79
|
* }
|
80
|
* (end)
|
81
|
*/
|
82
|
minRectDisplayClass: "RectReplacement",
|
83
|
|
84
|
/**
|
85
|
* APIProperty: minRatio
|
86
|
* {Float} The ratio of the overview map resolution to the main map
|
87
|
* resolution at which to zoom farther out on the overview map.
|
88
|
*/
|
89
|
minRatio: 8,
|
90
|
|
91
|
/**
|
92
|
* APIProperty: maxRatio
|
93
|
* {Float} The ratio of the overview map resolution to the main map
|
94
|
* resolution at which to zoom farther in on the overview map.
|
95
|
*/
|
96
|
maxRatio: 32,
|
97
|
|
98
|
/**
|
99
|
* APIProperty: mapOptions
|
100
|
* {Object} An object containing any non-default properties to be sent to
|
101
|
* the overview map's map constructor. These should include any
|
102
|
* non-default options that the main map was constructed with.
|
103
|
*/
|
104
|
mapOptions: null,
|
105
|
|
106
|
/**
|
107
|
* APIProperty: autoPan
|
108
|
* {Boolean} Always pan the overview map, so the extent marker remains in
|
109
|
* the center. Default is false. If true, when you drag the extent
|
110
|
* marker, the overview map will update itself so the marker returns
|
111
|
* to the center.
|
112
|
*/
|
113
|
autoPan: false,
|
114
|
|
115
|
/**
|
116
|
* Property: handlers
|
117
|
* {Object}
|
118
|
*/
|
119
|
handlers: null,
|
120
|
|
121
|
/**
|
122
|
* Property: resolutionFactor
|
123
|
* {Object}
|
124
|
*/
|
125
|
resolutionFactor: 1,
|
126
|
|
127
|
/**
|
128
|
* APIProperty: maximized
|
129
|
* {Boolean} Start as maximized (visible). Defaults to false.
|
130
|
*/
|
131
|
maximized: false,
|
132
|
|
133
|
/**
|
134
|
* APIProperty: maximizeTitle
|
135
|
* {String} This property is used for showing a tooltip over the
|
136
|
* maximize div. Defaults to "" (no title).
|
137
|
*/
|
138
|
maximizeTitle: "",
|
139
|
|
140
|
/**
|
141
|
* APIProperty: minimizeTitle
|
142
|
* {String} This property is used for showing a tooltip over the
|
143
|
* minimize div. Defaults to "" (no title).
|
144
|
*/
|
145
|
minimizeTitle: "",
|
146
|
|
147
|
/**
|
148
|
* Constructor: OpenLayers.Control.OverviewMap
|
149
|
* Create a new overview map
|
150
|
*
|
151
|
* Parameters:
|
152
|
* options - {Object} Properties of this object will be set on the overview
|
153
|
* map object. Note, to set options on the map object contained in this
|
154
|
* control, set <mapOptions> as one of the options properties.
|
155
|
*/
|
156
|
initialize: function(options) {
|
157
|
this.layers = [];
|
158
|
this.handlers = {};
|
159
|
OpenLayers.Control.prototype.initialize.apply(this, [options]);
|
160
|
},
|
161
|
|
162
|
/**
|
163
|
* APIMethod: destroy
|
164
|
* Deconstruct the control
|
165
|
*/
|
166
|
destroy: function() {
|
167
|
if (!this.mapDiv) { // we've already been destroyed
|
168
|
return;
|
169
|
}
|
170
|
if (this.handlers.click) {
|
171
|
this.handlers.click.destroy();
|
172
|
}
|
173
|
if (this.handlers.drag) {
|
174
|
this.handlers.drag.destroy();
|
175
|
}
|
176
|
|
177
|
this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle);
|
178
|
this.extentRectangle = null;
|
179
|
|
180
|
if (this.rectEvents) {
|
181
|
this.rectEvents.destroy();
|
182
|
this.rectEvents = null;
|
183
|
}
|
184
|
|
185
|
if (this.ovmap) {
|
186
|
this.ovmap.destroy();
|
187
|
this.ovmap = null;
|
188
|
}
|
189
|
|
190
|
this.element.removeChild(this.mapDiv);
|
191
|
this.mapDiv = null;
|
192
|
|
193
|
this.div.removeChild(this.element);
|
194
|
this.element = null;
|
195
|
|
196
|
if (this.maximizeDiv) {
|
197
|
this.div.removeChild(this.maximizeDiv);
|
198
|
this.maximizeDiv = null;
|
199
|
}
|
200
|
|
201
|
if (this.minimizeDiv) {
|
202
|
this.div.removeChild(this.minimizeDiv);
|
203
|
this.minimizeDiv = null;
|
204
|
}
|
205
|
|
206
|
this.map.events.un({
|
207
|
buttonclick: this.onButtonClick,
|
208
|
moveend: this.update,
|
209
|
changebaselayer: this.baseLayerDraw,
|
210
|
scope: this
|
211
|
});
|
212
|
|
213
|
OpenLayers.Control.prototype.destroy.apply(this, arguments);
|
214
|
},
|
215
|
|
216
|
/**
|
217
|
* Method: draw
|
218
|
* Render the control in the browser.
|
219
|
*/
|
220
|
draw: function() {
|
221
|
OpenLayers.Control.prototype.draw.apply(this, arguments);
|
222
|
if (this.layers.length === 0) {
|
223
|
if (this.map.baseLayer) {
|
224
|
var layer = this.map.baseLayer.clone();
|
225
|
this.layers = [layer];
|
226
|
} else {
|
227
|
this.map.events.register("changebaselayer", this, this.baseLayerDraw);
|
228
|
return this.div;
|
229
|
}
|
230
|
}
|
231
|
|
232
|
// create overview map DOM elements
|
233
|
this.element = document.createElement('div');
|
234
|
this.element.className = this.displayClass + 'Element';
|
235
|
this.element.style.display = 'none';
|
236
|
|
237
|
this.mapDiv = document.createElement('div');
|
238
|
this.mapDiv.style.width = this.size.w + 'px';
|
239
|
this.mapDiv.style.height = this.size.h + 'px';
|
240
|
this.mapDiv.style.position = 'relative';
|
241
|
this.mapDiv.style.overflow = 'hidden';
|
242
|
this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
|
243
|
|
244
|
this.extentRectangle = document.createElement('div');
|
245
|
this.extentRectangle.style.position = 'absolute';
|
246
|
this.extentRectangle.style.zIndex = 1000; //HACK
|
247
|
this.extentRectangle.className = this.displayClass+'ExtentRectangle';
|
248
|
|
249
|
this.element.appendChild(this.mapDiv);
|
250
|
|
251
|
this.div.appendChild(this.element);
|
252
|
|
253
|
// Optionally add min/max buttons if the control will go in the
|
254
|
// map viewport.
|
255
|
if(!this.outsideViewport) {
|
256
|
this.div.className += " " + this.displayClass + 'Container';
|
257
|
// maximize button div
|
258
|
var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');
|
259
|
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
|
260
|
this.displayClass + 'MaximizeButton',
|
261
|
null,
|
262
|
null,
|
263
|
img,
|
264
|
'absolute');
|
265
|
this.maximizeDiv.style.display = 'none';
|
266
|
this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton';
|
267
|
if (this.maximizeTitle) {
|
268
|
this.maximizeDiv.title = this.maximizeTitle;
|
269
|
}
|
270
|
this.div.appendChild(this.maximizeDiv);
|
271
|
|
272
|
// minimize button div
|
273
|
var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');
|
274
|
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
|
275
|
'OpenLayers_Control_minimizeDiv',
|
276
|
null,
|
277
|
null,
|
278
|
img,
|
279
|
'absolute');
|
280
|
this.minimizeDiv.style.display = 'none';
|
281
|
this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton';
|
282
|
if (this.minimizeTitle) {
|
283
|
this.minimizeDiv.title = this.minimizeTitle;
|
284
|
}
|
285
|
this.div.appendChild(this.minimizeDiv);
|
286
|
this.minimizeControl();
|
287
|
} else {
|
288
|
// show the overview map
|
289
|
this.element.style.display = '';
|
290
|
}
|
291
|
if(this.map.getExtent()) {
|
292
|
this.update();
|
293
|
}
|
294
|
|
295
|
this.map.events.on({
|
296
|
buttonclick: this.onButtonClick,
|
297
|
moveend: this.update,
|
298
|
scope: this
|
299
|
});
|
300
|
|
301
|
if (this.maximized) {
|
302
|
this.maximizeControl();
|
303
|
}
|
304
|
return this.div;
|
305
|
},
|
306
|
|
307
|
/**
|
308
|
* Method: baseLayerDraw
|
309
|
* Draw the base layer - called if unable to complete in the initial draw
|
310
|
*/
|
311
|
baseLayerDraw: function() {
|
312
|
this.draw();
|
313
|
this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
|
314
|
},
|
315
|
|
316
|
/**
|
317
|
* Method: rectDrag
|
318
|
* Handle extent rectangle drag
|
319
|
*
|
320
|
* Parameters:
|
321
|
* px - {<OpenLayers.Pixel>} The pixel location of the drag.
|
322
|
*/
|
323
|
rectDrag: function(px) {
|
324
|
var deltaX = this.handlers.drag.last.x - px.x;
|
325
|
var deltaY = this.handlers.drag.last.y - px.y;
|
326
|
if(deltaX != 0 || deltaY != 0) {
|
327
|
var rectTop = this.rectPxBounds.top;
|
328
|
var rectLeft = this.rectPxBounds.left;
|
329
|
var rectHeight = Math.abs(this.rectPxBounds.getHeight());
|
330
|
var rectWidth = this.rectPxBounds.getWidth();
|
331
|
// don't allow dragging off of parent element
|
332
|
var newTop = Math.max(0, (rectTop - deltaY));
|
333
|
newTop = Math.min(newTop,
|
334
|
this.ovmap.size.h - this.hComp - rectHeight);
|
335
|
var newLeft = Math.max(0, (rectLeft - deltaX));
|
336
|
newLeft = Math.min(newLeft,
|
337
|
this.ovmap.size.w - this.wComp - rectWidth);
|
338
|
this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
|
339
|
newTop + rectHeight,
|
340
|
newLeft + rectWidth,
|
341
|
newTop));
|
342
|
}
|
343
|
},
|
344
|
|
345
|
/**
|
346
|
* Method: mapDivClick
|
347
|
* Handle browser events
|
348
|
*
|
349
|
* Parameters:
|
350
|
* evt - {<OpenLayers.Event>} evt
|
351
|
*/
|
352
|
mapDivClick: function(evt) {
|
353
|
var pxCenter = this.rectPxBounds.getCenterPixel();
|
354
|
var deltaX = evt.xy.x - pxCenter.x;
|
355
|
var deltaY = evt.xy.y - pxCenter.y;
|
356
|
var top = this.rectPxBounds.top;
|
357
|
var left = this.rectPxBounds.left;
|
358
|
var height = Math.abs(this.rectPxBounds.getHeight());
|
359
|
var width = this.rectPxBounds.getWidth();
|
360
|
var newTop = Math.max(0, (top + deltaY));
|
361
|
newTop = Math.min(newTop, this.ovmap.size.h - height);
|
362
|
var newLeft = Math.max(0, (left + deltaX));
|
363
|
newLeft = Math.min(newLeft, this.ovmap.size.w - width);
|
364
|
this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
|
365
|
newTop + height,
|
366
|
newLeft + width,
|
367
|
newTop));
|
368
|
this.updateMapToRect();
|
369
|
},
|
370
|
|
371
|
/**
|
372
|
* Method: onButtonClick
|
373
|
*
|
374
|
* Parameters:
|
375
|
* evt - {Event}
|
376
|
*/
|
377
|
onButtonClick: function(evt) {
|
378
|
if (evt.buttonElement === this.minimizeDiv) {
|
379
|
this.minimizeControl();
|
380
|
} else if (evt.buttonElement === this.maximizeDiv) {
|
381
|
this.maximizeControl();
|
382
|
}
|
383
|
},
|
384
|
|
385
|
/**
|
386
|
* Method: maximizeControl
|
387
|
* Unhide the control. Called when the control is in the map viewport.
|
388
|
*
|
389
|
* Parameters:
|
390
|
* e - {<OpenLayers.Event>}
|
391
|
*/
|
392
|
maximizeControl: function(e) {
|
393
|
this.element.style.display = '';
|
394
|
this.showToggle(false);
|
395
|
if (e != null) {
|
396
|
OpenLayers.Event.stop(e);
|
397
|
}
|
398
|
},
|
399
|
|
400
|
/**
|
401
|
* Method: minimizeControl
|
402
|
* Hide all the contents of the control, shrink the size,
|
403
|
* add the maximize icon
|
404
|
*
|
405
|
* Parameters:
|
406
|
* e - {<OpenLayers.Event>}
|
407
|
*/
|
408
|
minimizeControl: function(e) {
|
409
|
this.element.style.display = 'none';
|
410
|
this.showToggle(true);
|
411
|
if (e != null) {
|
412
|
OpenLayers.Event.stop(e);
|
413
|
}
|
414
|
},
|
415
|
|
416
|
/**
|
417
|
* Method: showToggle
|
418
|
* Hide/Show the toggle depending on whether the control is minimized
|
419
|
*
|
420
|
* Parameters:
|
421
|
* minimize - {Boolean}
|
422
|
*/
|
423
|
showToggle: function(minimize) {
|
424
|
if (this.maximizeDiv) {
|
425
|
this.maximizeDiv.style.display = minimize ? '' : 'none';
|
426
|
}
|
427
|
if (this.minimizeDiv) {
|
428
|
this.minimizeDiv.style.display = minimize ? 'none' : '';
|
429
|
}
|
430
|
},
|
431
|
|
432
|
/**
|
433
|
* Method: update
|
434
|
* Update the overview map after layers move.
|
435
|
*/
|
436
|
update: function() {
|
437
|
if(this.ovmap == null) {
|
438
|
this.createMap();
|
439
|
}
|
440
|
|
441
|
if(this.autoPan || !this.isSuitableOverview()) {
|
442
|
this.updateOverview();
|
443
|
}
|
444
|
|
445
|
// update extent rectangle
|
446
|
this.updateRectToMap();
|
447
|
},
|
448
|
|
449
|
/**
|
450
|
* Method: isSuitableOverview
|
451
|
* Determines if the overview map is suitable given the extent and
|
452
|
* resolution of the main map.
|
453
|
*/
|
454
|
isSuitableOverview: function() {
|
455
|
var mapExtent = this.map.getExtent();
|
456
|
var maxExtent = this.map.getMaxExtent();
|
457
|
var testExtent = new OpenLayers.Bounds(
|
458
|
Math.max(mapExtent.left, maxExtent.left),
|
459
|
Math.max(mapExtent.bottom, maxExtent.bottom),
|
460
|
Math.min(mapExtent.right, maxExtent.right),
|
461
|
Math.min(mapExtent.top, maxExtent.top));
|
462
|
|
463
|
if (this.ovmap.getProjection() != this.map.getProjection()) {
|
464
|
testExtent = testExtent.transform(
|
465
|
this.map.getProjectionObject(),
|
466
|
this.ovmap.getProjectionObject() );
|
467
|
}
|
468
|
|
469
|
var resRatio = this.ovmap.getResolution() / this.map.getResolution();
|
470
|
return ((resRatio > this.minRatio) &&
|
471
|
(resRatio <= this.maxRatio) &&
|
472
|
(this.ovmap.getExtent().containsBounds(testExtent)));
|
473
|
},
|
474
|
|
475
|
/**
|
476
|
* Method updateOverview
|
477
|
* Called by <update> if <isSuitableOverview> returns true
|
478
|
*/
|
479
|
updateOverview: function() {
|
480
|
var mapRes = this.map.getResolution();
|
481
|
var targetRes = this.ovmap.getResolution();
|
482
|
var resRatio = targetRes / mapRes;
|
483
|
if(resRatio > this.maxRatio) {
|
484
|
// zoom in overview map
|
485
|
targetRes = this.minRatio * mapRes;
|
486
|
} else if(resRatio <= this.minRatio) {
|
487
|
// zoom out overview map
|
488
|
targetRes = this.maxRatio * mapRes;
|
489
|
}
|
490
|
var center;
|
491
|
if (this.ovmap.getProjection() != this.map.getProjection()) {
|
492
|
center = this.map.center.clone();
|
493
|
center.transform(this.map.getProjectionObject(),
|
494
|
this.ovmap.getProjectionObject() );
|
495
|
} else {
|
496
|
center = this.map.center;
|
497
|
}
|
498
|
this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
|
499
|
targetRes * this.resolutionFactor));
|
500
|
this.updateRectToMap();
|
501
|
},
|
502
|
|
503
|
/**
|
504
|
* Method: createMap
|
505
|
* Construct the map that this control contains
|
506
|
*/
|
507
|
createMap: function() {
|
508
|
// create the overview map
|
509
|
var options = OpenLayers.Util.extend(
|
510
|
{controls: [], maxResolution: 'auto',
|
511
|
fallThrough: false}, this.mapOptions);
|
512
|
this.ovmap = new OpenLayers.Map(this.mapDiv, options);
|
513
|
this.ovmap.viewPortDiv.appendChild(this.extentRectangle);
|
514
|
|
515
|
// prevent ovmap from being destroyed when the page unloads, because
|
516
|
// the OverviewMap control has to do this (and does it).
|
517
|
OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
|
518
|
|
519
|
this.ovmap.addLayers(this.layers);
|
520
|
this.ovmap.zoomToMaxExtent();
|
521
|
// check extent rectangle border width
|
522
|
this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
|
523
|
'border-left-width')) +
|
524
|
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
|
525
|
'border-right-width'));
|
526
|
this.wComp = (this.wComp) ? this.wComp : 2;
|
527
|
this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
|
528
|
'border-top-width')) +
|
529
|
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
|
530
|
'border-bottom-width'));
|
531
|
this.hComp = (this.hComp) ? this.hComp : 2;
|
532
|
|
533
|
this.handlers.drag = new OpenLayers.Handler.Drag(
|
534
|
this, {move: this.rectDrag, done: this.updateMapToRect},
|
535
|
{map: this.ovmap}
|
536
|
);
|
537
|
this.handlers.click = new OpenLayers.Handler.Click(
|
538
|
this, {
|
539
|
"click": this.mapDivClick
|
540
|
},{
|
541
|
"single": true, "double": false,
|
542
|
"stopSingle": true, "stopDouble": true,
|
543
|
"pixelTolerance": 1,
|
544
|
map: this.ovmap
|
545
|
}
|
546
|
);
|
547
|
this.handlers.click.activate();
|
548
|
|
549
|
this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
|
550
|
null, true);
|
551
|
this.rectEvents.register("mouseover", this, function(e) {
|
552
|
if(!this.handlers.drag.active && !this.map.dragging) {
|
553
|
this.handlers.drag.activate();
|
554
|
}
|
555
|
});
|
556
|
this.rectEvents.register("mouseout", this, function(e) {
|
557
|
if(!this.handlers.drag.dragging) {
|
558
|
this.handlers.drag.deactivate();
|
559
|
}
|
560
|
});
|
561
|
|
562
|
if (this.ovmap.getProjection() != this.map.getProjection()) {
|
563
|
var sourceUnits = this.map.getProjectionObject().getUnits() ||
|
564
|
this.map.units || this.map.baseLayer.units;
|
565
|
var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
|
566
|
this.ovmap.units || this.ovmap.baseLayer.units;
|
567
|
this.resolutionFactor = sourceUnits && targetUnits ?
|
568
|
OpenLayers.INCHES_PER_UNIT[sourceUnits] /
|
569
|
OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
|
570
|
}
|
571
|
},
|
572
|
|
573
|
/**
|
574
|
* Method: updateRectToMap
|
575
|
* Updates the extent rectangle position and size to match the map extent
|
576
|
*/
|
577
|
updateRectToMap: function() {
|
578
|
// If the projections differ we need to reproject
|
579
|
var bounds;
|
580
|
if (this.ovmap.getProjection() != this.map.getProjection()) {
|
581
|
bounds = this.map.getExtent().transform(
|
582
|
this.map.getProjectionObject(),
|
583
|
this.ovmap.getProjectionObject() );
|
584
|
} else {
|
585
|
bounds = this.map.getExtent();
|
586
|
}
|
587
|
var pxBounds = this.getRectBoundsFromMapBounds(bounds);
|
588
|
if (pxBounds) {
|
589
|
this.setRectPxBounds(pxBounds);
|
590
|
}
|
591
|
},
|
592
|
|
593
|
/**
|
594
|
* Method: updateMapToRect
|
595
|
* Updates the map extent to match the extent rectangle position and size
|
596
|
*/
|
597
|
updateMapToRect: function() {
|
598
|
var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
|
599
|
if (this.ovmap.getProjection() != this.map.getProjection()) {
|
600
|
lonLatBounds = lonLatBounds.transform(
|
601
|
this.ovmap.getProjectionObject(),
|
602
|
this.map.getProjectionObject() );
|
603
|
}
|
604
|
this.map.panTo(lonLatBounds.getCenterLonLat());
|
605
|
},
|
606
|
|
607
|
/**
|
608
|
* Method: setRectPxBounds
|
609
|
* Set extent rectangle pixel bounds.
|
610
|
*
|
611
|
* Parameters:
|
612
|
* pxBounds - {<OpenLayers.Bounds>}
|
613
|
*/
|
614
|
setRectPxBounds: function(pxBounds) {
|
615
|
var top = Math.max(pxBounds.top, 0);
|
616
|
var left = Math.max(pxBounds.left, 0);
|
617
|
var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
|
618
|
this.ovmap.size.h - this.hComp);
|
619
|
var right = Math.min(pxBounds.left + pxBounds.getWidth(),
|
620
|
this.ovmap.size.w - this.wComp);
|
621
|
var width = Math.max(right - left, 0);
|
622
|
var height = Math.max(bottom - top, 0);
|
623
|
if(width < this.minRectSize || height < this.minRectSize) {
|
624
|
this.extentRectangle.className = this.displayClass +
|
625
|
this.minRectDisplayClass;
|
626
|
var rLeft = left + (width / 2) - (this.minRectSize / 2);
|
627
|
var rTop = top + (height / 2) - (this.minRectSize / 2);
|
628
|
this.extentRectangle.style.top = Math.round(rTop) + 'px';
|
629
|
this.extentRectangle.style.left = Math.round(rLeft) + 'px';
|
630
|
this.extentRectangle.style.height = this.minRectSize + 'px';
|
631
|
this.extentRectangle.style.width = this.minRectSize + 'px';
|
632
|
} else {
|
633
|
this.extentRectangle.className = this.displayClass +
|
634
|
'ExtentRectangle';
|
635
|
this.extentRectangle.style.top = Math.round(top) + 'px';
|
636
|
this.extentRectangle.style.left = Math.round(left) + 'px';
|
637
|
this.extentRectangle.style.height = Math.round(height) + 'px';
|
638
|
this.extentRectangle.style.width = Math.round(width) + 'px';
|
639
|
}
|
640
|
this.rectPxBounds = new OpenLayers.Bounds(
|
641
|
Math.round(left), Math.round(bottom),
|
642
|
Math.round(right), Math.round(top)
|
643
|
);
|
644
|
},
|
645
|
|
646
|
/**
|
647
|
* Method: getRectBoundsFromMapBounds
|
648
|
* Get the rect bounds from the map bounds.
|
649
|
*
|
650
|
* Parameters:
|
651
|
* lonLatBounds - {<OpenLayers.Bounds>}
|
652
|
*
|
653
|
* Returns:
|
654
|
* {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
|
655
|
* translated into pixel bounds for the overview map
|
656
|
*/
|
657
|
getRectBoundsFromMapBounds: function(lonLatBounds) {
|
658
|
var leftBottomPx = this.getOverviewPxFromLonLat({
|
659
|
lon: lonLatBounds.left,
|
660
|
lat: lonLatBounds.bottom
|
661
|
});
|
662
|
var rightTopPx = this.getOverviewPxFromLonLat({
|
663
|
lon: lonLatBounds.right,
|
664
|
lat: lonLatBounds.top
|
665
|
});
|
666
|
var bounds = null;
|
667
|
if (leftBottomPx && rightTopPx) {
|
668
|
bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
|
669
|
rightTopPx.x, rightTopPx.y);
|
670
|
}
|
671
|
return bounds;
|
672
|
},
|
673
|
|
674
|
/**
|
675
|
* Method: getMapBoundsFromRectBounds
|
676
|
* Get the map bounds from the rect bounds.
|
677
|
*
|
678
|
* Parameters:
|
679
|
* pxBounds - {<OpenLayers.Bounds>}
|
680
|
*
|
681
|
* Returns:
|
682
|
* {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
|
683
|
* translated into lon/lat bounds for the overview map
|
684
|
*/
|
685
|
getMapBoundsFromRectBounds: function(pxBounds) {
|
686
|
var leftBottomLonLat = this.getLonLatFromOverviewPx({
|
687
|
x: pxBounds.left,
|
688
|
y: pxBounds.bottom
|
689
|
});
|
690
|
var rightTopLonLat = this.getLonLatFromOverviewPx({
|
691
|
x: pxBounds.right,
|
692
|
y: pxBounds.top
|
693
|
});
|
694
|
return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
|
695
|
rightTopLonLat.lon, rightTopLonLat.lat);
|
696
|
},
|
697
|
|
698
|
/**
|
699
|
* Method: getLonLatFromOverviewPx
|
700
|
* Get a map location from a pixel location
|
701
|
*
|
702
|
* Parameters:
|
703
|
* overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or
|
704
|
* an object with a
|
705
|
* 'x' and 'y' properties.
|
706
|
*
|
707
|
* Returns:
|
708
|
* {Object} Location which is the passed-in overview map
|
709
|
* OpenLayers.Pixel, translated into lon/lat by the overview
|
710
|
* map. An object with a 'lon' and 'lat' properties.
|
711
|
*/
|
712
|
getLonLatFromOverviewPx: function(overviewMapPx) {
|
713
|
var size = this.ovmap.size;
|
714
|
var res = this.ovmap.getResolution();
|
715
|
var center = this.ovmap.getExtent().getCenterLonLat();
|
716
|
|
717
|
var deltaX = overviewMapPx.x - (size.w / 2);
|
718
|
var deltaY = overviewMapPx.y - (size.h / 2);
|
719
|
|
720
|
return {
|
721
|
lon: center.lon + deltaX * res,
|
722
|
lat: center.lat - deltaY * res
|
723
|
};
|
724
|
},
|
725
|
|
726
|
/**
|
727
|
* Method: getOverviewPxFromLonLat
|
728
|
* Get a pixel location from a map location
|
729
|
*
|
730
|
* Parameters:
|
731
|
* lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
|
732
|
* object with a 'lon' and 'lat' properties.
|
733
|
*
|
734
|
* Returns:
|
735
|
* {Object} Location which is the passed-in OpenLayers.LonLat,
|
736
|
* translated into overview map pixels
|
737
|
*/
|
738
|
getOverviewPxFromLonLat: function(lonlat) {
|
739
|
var res = this.ovmap.getResolution();
|
740
|
var extent = this.ovmap.getExtent();
|
741
|
if (extent) {
|
742
|
return {
|
743
|
x: Math.round(1/res * (lonlat.lon - extent.left)),
|
744
|
y: Math.round(1/res * (extent.top - lonlat.lat))
|
745
|
};
|
746
|
}
|
747
|
},
|
748
|
|
749
|
CLASS_NAME: 'OpenLayers.Control.OverviewMap'
|
750
|
});
|