1
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3
* full text of the license. */
6
* @requires OpenLayers/Control.js
10
* Class: OpenLayers.Control.LayerSwitcher
13
* - <OpenLayers.Control>
15
OpenLayers.Control.LayerSwitcher =
16
OpenLayers.Class(OpenLayers.Control, {
19
* Property: activeColor
22
activeColor: "darkblue",
25
* Property: layerStates
26
* {Array(Object)} Basically a copy of the "state" of the map's layers
27
* the last time the control was drawn. We have this in order to avoid
28
* unnecessarily redrawing the control.
42
* Property: baseLayersDiv
48
* Property: baseLayers
49
* {Array(<OpenLayers.Layer>)}
61
* Property: dataLayersDiv
67
* Property: dataLayers
68
* {Array(<OpenLayers.Layer>)}
74
* Property: minimizeDiv
80
* Property: maximizeDiv
86
* APIProperty: ascending
92
* Constructor: OpenLayers.Control.LayerSwitcher
97
initialize: function(options) {
98
OpenLayers.Control.prototype.initialize.apply(this, arguments);
99
this.layerStates = [];
105
destroy: function() {
107
OpenLayers.Event.stopObservingElement(this.div);
109
OpenLayers.Event.stopObservingElement(this.minimizeDiv);
110
OpenLayers.Event.stopObservingElement(this.maximizeDiv);
112
//clear out layers info and unregister their events
113
this.clearLayersArray("base");
114
this.clearLayersArray("data");
117
"addlayer": this.redraw,
118
"changelayer": this.redraw,
119
"removelayer": this.redraw,
120
"changebaselayer": this.redraw,
124
OpenLayers.Control.prototype.destroy.apply(this, arguments);
131
* map - {<OpenLayers.Map>}
133
setMap: function(map) {
134
OpenLayers.Control.prototype.setMap.apply(this, arguments);
137
"addlayer": this.redraw,
138
"changelayer": this.redraw,
139
"removelayer": this.redraw,
140
"changebaselayer": this.redraw,
149
* {DOMElement} A reference to the DIV DOMElement containing the
153
OpenLayers.Control.prototype.draw.apply(this);
155
// create layout divs
158
// set mode to minimize
159
if(!this.outsideViewport) {
160
this.minimizeControl();
163
// populate div with current info
170
* Method: clearLayersArray
171
* User specifies either "base" or "data". we then clear all the
172
* corresponding listeners, the div, and reinitialize a new array.
175
* layersType - {String}
177
clearLayersArray: function(layersType) {
178
var layers = this[layersType + "Layers"];
180
for(var i=0, len=layers.length; i<len ; i++) {
181
var layer = layers[i];
182
OpenLayers.Event.stopObservingElement(layer.inputElem);
183
OpenLayers.Event.stopObservingElement(layer.labelSpan);
186
this[layersType + "LayersDiv"].innerHTML = "";
187
this[layersType + "Layers"] = [];
192
* Method: checkRedraw
193
* Checks if the layer state has changed since the last redraw() call.
196
* {Boolean} The layer state changed since the last redraw() call.
198
checkRedraw: function() {
200
if ( !this.layerStates.length ||
201
(this.map.layers.length != this.layerStates.length) ) {
204
for (var i=0, len=this.layerStates.length; i<len; i++) {
205
var layerState = this.layerStates[i];
206
var layer = this.map.layers[i];
207
if ( (layerState.name != layer.name) ||
208
(layerState.inRange != layer.inRange) ||
209
(layerState.id != layer.id) ||
210
(layerState.visibility != layer.visibility) ) {
221
* Goes through and takes the current state of the Map and rebuilds the
222
* control to display that state. Groups base layers into a
223
* radio-button group and lists each data layer with a checkbox.
226
* {DOMElement} A reference to the DIV DOMElement containing the control
229
//if the state hasn't changed since last redraw, no need
230
// to do anything. Just return the existing div.
231
if (!this.checkRedraw()) {
235
//clear out previous layers
236
this.clearLayersArray("base");
237
this.clearLayersArray("data");
239
var containsOverlays = false;
240
var containsBaseLayers = false;
242
// Save state -- for checking layer if the map state changed.
243
// We save this before redrawing, because in the process of redrawing
244
// we will trigger more visibility changes, and we want to not redraw
245
// and enter an infinite loop.
246
var len = this.map.layers.length;
247
this.layerStates = new Array(len);
248
for (var i=0; i <len; i++) {
249
var layer = this.map.layers[i];
250
this.layerStates[i] = {
252
'visibility': layer.visibility,
253
'inRange': layer.inRange,
258
var layers = this.map.layers.slice();
259
if (!this.ascending) { layers.reverse(); }
260
for(var i=0, len=layers.length; i<len; i++) {
261
var layer = layers[i];
262
var baseLayer = layer.isBaseLayer;
264
if (layer.displayInLayerSwitcher) {
267
containsBaseLayers = true;
269
containsOverlays = true;
272
// only check a baselayer if it is *the* baselayer, check data
273
// layers if they are visible
274
var checked = (baseLayer) ? (layer == this.map.baseLayer)
275
: layer.getVisibility();
277
// create input element
278
var inputElem = document.createElement("input");
279
inputElem.id = this.id + "_input_" + layer.name;
280
inputElem.name = (baseLayer) ? "baseLayers" : layer.name;
281
inputElem.type = (baseLayer) ? "radio" : "checkbox";
282
inputElem.value = layer.name;
283
inputElem.checked = checked;
284
inputElem.defaultChecked = checked;
286
if (!baseLayer && !layer.inRange) {
287
inputElem.disabled = true;
290
'inputElem': inputElem,
292
'layerSwitcher': this
294
OpenLayers.Event.observe(inputElem, "mouseup",
295
OpenLayers.Function.bindAsEventListener(this.onInputClick,
300
var labelSpan = document.createElement("span");
301
if (!baseLayer && !layer.inRange) {
302
labelSpan.style.color = "gray";
304
labelSpan.innerHTML = layer.name;
305
labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
307
OpenLayers.Event.observe(labelSpan, "click",
308
OpenLayers.Function.bindAsEventListener(this.onInputClick,
312
var br = document.createElement("br");
315
var groupArray = (baseLayer) ? this.baseLayers
319
'inputElem': inputElem,
320
'labelSpan': labelSpan
324
var groupDiv = (baseLayer) ? this.baseLayersDiv
325
: this.dataLayersDiv;
326
groupDiv.appendChild(inputElem);
327
groupDiv.appendChild(labelSpan);
328
groupDiv.appendChild(br);
332
// if no overlays, dont display the overlay label
333
this.dataLbl.style.display = (containsOverlays) ? "" : "none";
335
// if no baselayers, dont display the baselayer label
336
this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";
343
* A label has been clicked, check or uncheck its corresponding input
349
* - {DOMElement} inputElem
350
* - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
351
* - {<OpenLayers.Layer>} layer
354
onInputClick: function(e) {
356
if (!this.inputElem.disabled) {
357
if (this.inputElem.type == "radio") {
358
this.inputElem.checked = true;
359
this.layer.map.setBaseLayer(this.layer);
361
this.inputElem.checked = !this.inputElem.checked;
362
this.layerSwitcher.updateMap();
365
OpenLayers.Event.stop(e);
369
* Method: onLayerClick
370
* Need to update the map accordingly whenever user clicks in either of
376
onLayerClick: function(e) {
383
* Cycles through the loaded data and base layer input arrays and makes
384
* the necessary calls to the Map object such that that the map's
385
* visual state corresponds to what the user has selected in
388
updateMap: function() {
390
// set the newly selected base layer
391
for(var i=0, len=this.baseLayers.length; i<len; i++) {
392
var layerEntry = this.baseLayers[i];
393
if (layerEntry.inputElem.checked) {
394
this.map.setBaseLayer(layerEntry.layer, false);
398
// set the correct visibilities for the overlays
399
for(var i=0, len=this.dataLayers.length; i<len; i++) {
400
var layerEntry = this.dataLayers[i];
401
layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
407
* Method: maximizeControl
408
* Set up the labels and divs for the control
413
maximizeControl: function(e) {
415
//HACK HACK HACK - find a way to auto-size this layerswitcher
416
this.div.style.width = "20em";
417
this.div.style.height = "";
419
this.showControls(false);
422
OpenLayers.Event.stop(e);
427
* Method: minimizeControl
428
* Hide all the contents of the control, shrink the size,
429
* add the maximize icon
434
minimizeControl: function(e) {
436
this.div.style.width = "0px";
437
this.div.style.height = "0px";
439
this.showControls(true);
442
OpenLayers.Event.stop(e);
447
* Method: showControls
448
* Hide/Show all LayerSwitcher controls depending on whether we are
452
* minimize - {Boolean}
454
showControls: function(minimize) {
456
this.maximizeDiv.style.display = minimize ? "" : "none";
457
this.minimizeDiv.style.display = minimize ? "none" : "";
459
this.layersDiv.style.display = minimize ? "none" : "";
463
* Method: loadContents
464
* Set up the labels and divs for the control
466
loadContents: function() {
469
this.div.style.position = "absolute";
470
this.div.style.top = "25px";
471
this.div.style.right = "0px";
472
this.div.style.left = "";
473
this.div.style.fontFamily = "sans-serif";
474
this.div.style.fontWeight = "bold";
475
this.div.style.marginTop = "3px";
476
this.div.style.marginLeft = "3px";
477
this.div.style.marginBottom = "3px";
478
this.div.style.fontSize = "smaller";
479
this.div.style.color = "white";
480
this.div.style.backgroundColor = "transparent";
482
OpenLayers.Event.observe(this.div, "mouseup",
483
OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
484
OpenLayers.Event.observe(this.div, "click",
486
OpenLayers.Event.observe(this.div, "mousedown",
487
OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
488
OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
492
this.layersDiv = document.createElement("div");
493
this.layersDiv.id = this.id + "_layersDiv";
494
this.layersDiv.style.paddingTop = "5px";
495
this.layersDiv.style.paddingLeft = "10px";
496
this.layersDiv.style.paddingBottom = "5px";
497
this.layersDiv.style.paddingRight = "75px";
498
this.layersDiv.style.backgroundColor = this.activeColor;
500
// had to set width/height to get transparency in IE to work.
501
// thanks -- http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html
503
this.layersDiv.style.width = "100%";
504
this.layersDiv.style.height = "100%";
507
this.baseLbl = document.createElement("div");
508
this.baseLbl.innerHTML = OpenLayers.i18n("baseLayer");
509
this.baseLbl.style.marginTop = "3px";
510
this.baseLbl.style.marginLeft = "3px";
511
this.baseLbl.style.marginBottom = "3px";
513
this.baseLayersDiv = document.createElement("div");
514
this.baseLayersDiv.style.paddingLeft = "10px";
515
/*OpenLayers.Event.observe(this.baseLayersDiv, "click",
516
OpenLayers.Function.bindAsEventListener(this.onLayerClick, this));
520
this.dataLbl = document.createElement("div");
521
this.dataLbl.innerHTML = OpenLayers.i18n("overlays");
522
this.dataLbl.style.marginTop = "3px";
523
this.dataLbl.style.marginLeft = "3px";
524
this.dataLbl.style.marginBottom = "3px";
526
this.dataLayersDiv = document.createElement("div");
527
this.dataLayersDiv.style.paddingLeft = "10px";
529
if (this.ascending) {
530
this.layersDiv.appendChild(this.baseLbl);
531
this.layersDiv.appendChild(this.baseLayersDiv);
532
this.layersDiv.appendChild(this.dataLbl);
533
this.layersDiv.appendChild(this.dataLayersDiv);
535
this.layersDiv.appendChild(this.dataLbl);
536
this.layersDiv.appendChild(this.dataLayersDiv);
537
this.layersDiv.appendChild(this.baseLbl);
538
this.layersDiv.appendChild(this.baseLayersDiv);
541
this.div.appendChild(this.layersDiv);
543
OpenLayers.Rico.Corner.round(this.div, {corners: "tl bl",
544
bgColor: "transparent",
545
color: this.activeColor,
548
OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);
550
var imgLocation = OpenLayers.Util.getImagesLocation();
551
var sz = new OpenLayers.Size(18,18);
553
// maximize button div
554
var img = imgLocation + 'layer-switcher-maximize.png';
555
this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
556
"OpenLayers_Control_MaximizeDiv",
561
this.maximizeDiv.style.top = "5px";
562
this.maximizeDiv.style.right = "0px";
563
this.maximizeDiv.style.left = "";
564
this.maximizeDiv.style.display = "none";
565
OpenLayers.Event.observe(this.maximizeDiv, "click",
566
OpenLayers.Function.bindAsEventListener(this.maximizeControl, this)
569
this.div.appendChild(this.maximizeDiv);
571
// minimize button div
572
var img = imgLocation + 'layer-switcher-minimize.png';
573
var sz = new OpenLayers.Size(18,18);
574
this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
575
"OpenLayers_Control_MinimizeDiv",
580
this.minimizeDiv.style.top = "5px";
581
this.minimizeDiv.style.right = "0px";
582
this.minimizeDiv.style.left = "";
583
this.minimizeDiv.style.display = "none";
584
OpenLayers.Event.observe(this.minimizeDiv, "click",
585
OpenLayers.Function.bindAsEventListener(this.minimizeControl, this)
588
this.div.appendChild(this.minimizeDiv);
592
* Method: ignoreEvent
597
ignoreEvent: function(evt) {
598
OpenLayers.Event.stop(evt);
603
* Register a local 'mouseDown' flag so that we'll know whether or not
604
* to ignore a mouseUp event
609
mouseDown: function(evt) {
610
this.isMouseDown = true;
611
this.ignoreEvent(evt);
616
* If the 'isMouseDown' flag has been set, that means that the drag was
617
* started from within the LayerSwitcher control, and thus we can
618
* ignore the mouseup. Otherwise, let the Event continue.
623
mouseUp: function(evt) {
624
if (this.isMouseDown) {
625
this.isMouseDown = false;
626
this.ignoreEvent(evt);
630
CLASS_NAME: "OpenLayers.Control.LayerSwitcher"