~mortenoh/+junk/dhis2-detailed-import-export

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/openlayers/lib/OpenLayers/Control/LayerSwitcher.js

  • Committer: larshelge at gmail
  • Date: 2009-03-03 16:46:36 UTC
  • Revision ID: larshelge@gmail.com-20090303164636-2sjlrquo7ib1gf7r
Initial check-in

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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. */
 
4
 
 
5
/** 
 
6
 * @requires OpenLayers/Control.js
 
7
 */
 
8
 
 
9
/**
 
10
 * Class: OpenLayers.Control.LayerSwitcher
 
11
 *
 
12
 * Inherits from:
 
13
 *  - <OpenLayers.Control>
 
14
 */
 
15
OpenLayers.Control.LayerSwitcher = 
 
16
  OpenLayers.Class(OpenLayers.Control, {
 
17
 
 
18
    /**  
 
19
     * Property: activeColor
 
20
     * {String}
 
21
     */
 
22
    activeColor: "darkblue",
 
23
    
 
24
    /**  
 
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.
 
29
     */
 
30
    layerStates: null,
 
31
    
 
32
 
 
33
  // DOM Elements
 
34
  
 
35
    /**
 
36
     * Property: layersDiv
 
37
     * {DOMElement} 
 
38
     */
 
39
    layersDiv: null,
 
40
    
 
41
    /** 
 
42
     * Property: baseLayersDiv
 
43
     * {DOMElement}
 
44
     */
 
45
    baseLayersDiv: null,
 
46
 
 
47
    /** 
 
48
     * Property: baseLayers
 
49
     * {Array(<OpenLayers.Layer>)}
 
50
     */
 
51
    baseLayers: null,
 
52
    
 
53
    
 
54
    /** 
 
55
     * Property: dataLbl
 
56
     * {DOMElement} 
 
57
     */
 
58
    dataLbl: null,
 
59
    
 
60
    /** 
 
61
     * Property: dataLayersDiv
 
62
     * {DOMElement} 
 
63
     */
 
64
    dataLayersDiv: null,
 
65
 
 
66
    /** 
 
67
     * Property: dataLayers
 
68
     * {Array(<OpenLayers.Layer>)} 
 
69
     */
 
70
    dataLayers: null,
 
71
 
 
72
 
 
73
    /** 
 
74
     * Property: minimizeDiv
 
75
     * {DOMElement} 
 
76
     */
 
77
    minimizeDiv: null,
 
78
 
 
79
    /** 
 
80
     * Property: maximizeDiv
 
81
     * {DOMElement} 
 
82
     */
 
83
    maximizeDiv: null,
 
84
    
 
85
    /**
 
86
     * APIProperty: ascending
 
87
     * {Boolean} 
 
88
     */
 
89
    ascending: true,
 
90
 
 
91
    /**
 
92
     * Constructor: OpenLayers.Control.LayerSwitcher
 
93
     * 
 
94
     * Parameters:
 
95
     * options - {Object}
 
96
     */
 
97
    initialize: function(options) {
 
98
        OpenLayers.Control.prototype.initialize.apply(this, arguments);
 
99
        this.layerStates = [];
 
100
    },
 
101
 
 
102
    /**
 
103
     * APIMethod: destroy 
 
104
     */    
 
105
    destroy: function() {
 
106
        
 
107
        OpenLayers.Event.stopObservingElement(this.div);
 
108
 
 
109
        OpenLayers.Event.stopObservingElement(this.minimizeDiv);
 
110
        OpenLayers.Event.stopObservingElement(this.maximizeDiv);
 
111
 
 
112
        //clear out layers info and unregister their events 
 
113
        this.clearLayersArray("base");
 
114
        this.clearLayersArray("data");
 
115
        
 
116
        this.map.events.un({
 
117
            "addlayer": this.redraw,
 
118
            "changelayer": this.redraw,
 
119
            "removelayer": this.redraw,
 
120
            "changebaselayer": this.redraw,
 
121
            scope: this
 
122
        });
 
123
        
 
124
        OpenLayers.Control.prototype.destroy.apply(this, arguments);
 
125
    },
 
126
 
 
127
    /** 
 
128
     * Method: setMap
 
129
     *
 
130
     * Properties:
 
131
     * map - {<OpenLayers.Map>} 
 
132
     */
 
133
    setMap: function(map) {
 
134
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
 
135
 
 
136
        this.map.events.on({
 
137
            "addlayer": this.redraw,
 
138
            "changelayer": this.redraw,
 
139
            "removelayer": this.redraw,
 
140
            "changebaselayer": this.redraw,
 
141
            scope: this
 
142
        });
 
143
    },
 
144
 
 
145
    /**
 
146
     * Method: draw
 
147
     *
 
148
     * Returns:
 
149
     * {DOMElement} A reference to the DIV DOMElement containing the 
 
150
     *     switcher tabs.
 
151
     */  
 
152
    draw: function() {
 
153
        OpenLayers.Control.prototype.draw.apply(this);
 
154
 
 
155
        // create layout divs
 
156
        this.loadContents();
 
157
 
 
158
        // set mode to minimize
 
159
        if(!this.outsideViewport) {
 
160
            this.minimizeControl();
 
161
        }
 
162
 
 
163
        // populate div with current info
 
164
        this.redraw();    
 
165
 
 
166
        return this.div;
 
167
    },
 
168
 
 
169
    /** 
 
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.
 
173
     * 
 
174
     * Parameters:
 
175
     * layersType - {String}  
 
176
     */
 
177
    clearLayersArray: function(layersType) {
 
178
        var layers = this[layersType + "Layers"];
 
179
        if (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);
 
184
            }
 
185
        }
 
186
        this[layersType + "LayersDiv"].innerHTML = "";
 
187
        this[layersType + "Layers"] = [];
 
188
    },
 
189
 
 
190
 
 
191
    /**
 
192
     * Method: checkRedraw
 
193
     * Checks if the layer state has changed since the last redraw() call.
 
194
     * 
 
195
     * Returns:
 
196
     * {Boolean} The layer state changed since the last redraw() call. 
 
197
     */
 
198
    checkRedraw: function() {
 
199
        var redraw = false;
 
200
        if ( !this.layerStates.length ||
 
201
             (this.map.layers.length != this.layerStates.length) ) {
 
202
            redraw = true;
 
203
        } else {
 
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) ) {
 
211
                    redraw = true;
 
212
                    break;
 
213
                }    
 
214
            }
 
215
        }    
 
216
        return redraw;
 
217
    },
 
218
    
 
219
    /** 
 
220
     * Method: redraw
 
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.
 
224
     *
 
225
     * Returns: 
 
226
     * {DOMElement} A reference to the DIV DOMElement containing the control
 
227
     */  
 
228
    redraw: function() {
 
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()) { 
 
232
            return this.div; 
 
233
        } 
 
234
 
 
235
        //clear out previous layers 
 
236
        this.clearLayersArray("base");
 
237
        this.clearLayersArray("data");
 
238
        
 
239
        var containsOverlays = false;
 
240
        var containsBaseLayers = false;
 
241
        
 
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] = {
 
251
                'name': layer.name, 
 
252
                'visibility': layer.visibility,
 
253
                'inRange': layer.inRange,
 
254
                'id': layer.id
 
255
            };
 
256
        }    
 
257
 
 
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;
 
263
 
 
264
            if (layer.displayInLayerSwitcher) {
 
265
 
 
266
                if (baseLayer) {
 
267
                    containsBaseLayers = true;
 
268
                } else {
 
269
                    containsOverlays = true;
 
270
                }    
 
271
 
 
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();
 
276
    
 
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;
 
285
 
 
286
                if (!baseLayer && !layer.inRange) {
 
287
                    inputElem.disabled = true;
 
288
                }
 
289
                var context = {
 
290
                    'inputElem': inputElem,
 
291
                    'layer': layer,
 
292
                    'layerSwitcher': this
 
293
                };
 
294
                OpenLayers.Event.observe(inputElem, "mouseup", 
 
295
                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
 
296
                                                            context)
 
297
                );
 
298
                
 
299
                // create span
 
300
                var labelSpan = document.createElement("span");
 
301
                if (!baseLayer && !layer.inRange) {
 
302
                    labelSpan.style.color = "gray";
 
303
                }
 
304
                labelSpan.innerHTML = layer.name;
 
305
                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" 
 
306
                                                            : "baseline";
 
307
                OpenLayers.Event.observe(labelSpan, "click", 
 
308
                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
 
309
                                                            context)
 
310
                );
 
311
                // create line break
 
312
                var br = document.createElement("br");
 
313
    
 
314
                
 
315
                var groupArray = (baseLayer) ? this.baseLayers
 
316
                                             : this.dataLayers;
 
317
                groupArray.push({
 
318
                    'layer': layer,
 
319
                    'inputElem': inputElem,
 
320
                    'labelSpan': labelSpan
 
321
                });
 
322
                                                     
 
323
    
 
324
                var groupDiv = (baseLayer) ? this.baseLayersDiv
 
325
                                           : this.dataLayersDiv;
 
326
                groupDiv.appendChild(inputElem);
 
327
                groupDiv.appendChild(labelSpan);
 
328
                groupDiv.appendChild(br);
 
329
            }
 
330
        }
 
331
 
 
332
        // if no overlays, dont display the overlay label
 
333
        this.dataLbl.style.display = (containsOverlays) ? "" : "none";        
 
334
        
 
335
        // if no baselayers, dont display the baselayer label
 
336
        this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";        
 
337
 
 
338
        return this.div;
 
339
    },
 
340
 
 
341
    /** 
 
342
     * Method:
 
343
     * A label has been clicked, check or uncheck its corresponding input
 
344
     * 
 
345
     * Parameters:
 
346
     * e - {Event} 
 
347
     *
 
348
     * Context:  
 
349
     *  - {DOMElement} inputElem
 
350
     *  - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
 
351
     *  - {<OpenLayers.Layer>} layer
 
352
     */
 
353
 
 
354
    onInputClick: function(e) {
 
355
 
 
356
        if (!this.inputElem.disabled) {
 
357
            if (this.inputElem.type == "radio") {
 
358
                this.inputElem.checked = true;
 
359
                this.layer.map.setBaseLayer(this.layer);
 
360
            } else {
 
361
                this.inputElem.checked = !this.inputElem.checked;
 
362
                this.layerSwitcher.updateMap();
 
363
            }
 
364
        }
 
365
        OpenLayers.Event.stop(e);
 
366
    },
 
367
    
 
368
    /**
 
369
     * Method: onLayerClick
 
370
     * Need to update the map accordingly whenever user clicks in either of
 
371
     *     the layers.
 
372
     * 
 
373
     * Parameters: 
 
374
     * e - {Event} 
 
375
     */
 
376
    onLayerClick: function(e) {
 
377
        this.updateMap();
 
378
    },
 
379
 
 
380
 
 
381
    /** 
 
382
     * Method: updateMap
 
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 
 
386
     *     the control.
 
387
     */
 
388
    updateMap: function() {
 
389
 
 
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);
 
395
            }
 
396
        }
 
397
 
 
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);
 
402
        }
 
403
 
 
404
    },
 
405
 
 
406
    /** 
 
407
     * Method: maximizeControl
 
408
     * Set up the labels and divs for the control
 
409
     * 
 
410
     * Parameters:
 
411
     * e - {Event} 
 
412
     */
 
413
    maximizeControl: function(e) {
 
414
 
 
415
        //HACK HACK HACK - find a way to auto-size this layerswitcher
 
416
        this.div.style.width = "20em";
 
417
        this.div.style.height = "";
 
418
 
 
419
        this.showControls(false);
 
420
 
 
421
        if (e != null) {
 
422
            OpenLayers.Event.stop(e);                                            
 
423
        }
 
424
    },
 
425
    
 
426
    /** 
 
427
     * Method: minimizeControl
 
428
     * Hide all the contents of the control, shrink the size, 
 
429
     *     add the maximize icon
 
430
     *
 
431
     * Parameters:
 
432
     * e - {Event} 
 
433
     */
 
434
    minimizeControl: function(e) {
 
435
 
 
436
        this.div.style.width = "0px";
 
437
        this.div.style.height = "0px";
 
438
 
 
439
        this.showControls(true);
 
440
 
 
441
        if (e != null) {
 
442
            OpenLayers.Event.stop(e);                                            
 
443
        }
 
444
    },
 
445
 
 
446
    /**
 
447
     * Method: showControls
 
448
     * Hide/Show all LayerSwitcher controls depending on whether we are
 
449
     *     minimized or not
 
450
     * 
 
451
     * Parameters:
 
452
     * minimize - {Boolean}
 
453
     */
 
454
    showControls: function(minimize) {
 
455
 
 
456
        this.maximizeDiv.style.display = minimize ? "" : "none";
 
457
        this.minimizeDiv.style.display = minimize ? "none" : "";
 
458
 
 
459
        this.layersDiv.style.display = minimize ? "none" : "";
 
460
    },
 
461
    
 
462
    /** 
 
463
     * Method: loadContents
 
464
     * Set up the labels and divs for the control
 
465
     */
 
466
    loadContents: function() {
 
467
 
 
468
        //configure main div
 
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";
 
481
    
 
482
        OpenLayers.Event.observe(this.div, "mouseup", 
 
483
            OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
 
484
        OpenLayers.Event.observe(this.div, "click",
 
485
                      this.ignoreEvent);
 
486
        OpenLayers.Event.observe(this.div, "mousedown",
 
487
            OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
 
488
        OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
 
489
 
 
490
 
 
491
        // layers list div        
 
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;        
 
499
 
 
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
 
502
        //
 
503
        this.layersDiv.style.width = "100%";
 
504
        this.layersDiv.style.height = "100%";
 
505
 
 
506
 
 
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";
 
512
        
 
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));
 
517
        */
 
518
                     
 
519
 
 
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";
 
525
        
 
526
        this.dataLayersDiv = document.createElement("div");
 
527
        this.dataLayersDiv.style.paddingLeft = "10px";
 
528
 
 
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);
 
534
        } else {
 
535
            this.layersDiv.appendChild(this.dataLbl);
 
536
            this.layersDiv.appendChild(this.dataLayersDiv);
 
537
            this.layersDiv.appendChild(this.baseLbl);
 
538
            this.layersDiv.appendChild(this.baseLayersDiv);
 
539
        }    
 
540
 
 
541
        this.div.appendChild(this.layersDiv);
 
542
 
 
543
        OpenLayers.Rico.Corner.round(this.div, {corners: "tl bl",
 
544
                                        bgColor: "transparent",
 
545
                                        color: this.activeColor,
 
546
                                        blend: false});
 
547
 
 
548
        OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);
 
549
 
 
550
        var imgLocation = OpenLayers.Util.getImagesLocation();
 
551
        var sz = new OpenLayers.Size(18,18);        
 
552
 
 
553
        // maximize button div
 
554
        var img = imgLocation + 'layer-switcher-maximize.png';
 
555
        this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
 
556
                                    "OpenLayers_Control_MaximizeDiv", 
 
557
                                    null, 
 
558
                                    sz, 
 
559
                                    img, 
 
560
                                    "absolute");
 
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)
 
567
        );
 
568
        
 
569
        this.div.appendChild(this.maximizeDiv);
 
570
 
 
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", 
 
576
                                    null, 
 
577
                                    sz, 
 
578
                                    img, 
 
579
                                    "absolute");
 
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)
 
586
        );
 
587
 
 
588
        this.div.appendChild(this.minimizeDiv);
 
589
    },
 
590
    
 
591
    /** 
 
592
     * Method: ignoreEvent
 
593
     * 
 
594
     * Parameters:
 
595
     * evt - {Event} 
 
596
     */
 
597
    ignoreEvent: function(evt) {
 
598
        OpenLayers.Event.stop(evt);
 
599
    },
 
600
 
 
601
    /** 
 
602
     * Method: mouseDown
 
603
     * Register a local 'mouseDown' flag so that we'll know whether or not
 
604
     *     to ignore a mouseUp event
 
605
     * 
 
606
     * Parameters:
 
607
     * evt - {Event}
 
608
     */
 
609
    mouseDown: function(evt) {
 
610
        this.isMouseDown = true;
 
611
        this.ignoreEvent(evt);
 
612
    },
 
613
 
 
614
    /** 
 
615
     * Method: mouseUp
 
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.
 
619
     *  
 
620
     * Parameters:
 
621
     * evt - {Event} 
 
622
     */
 
623
    mouseUp: function(evt) {
 
624
        if (this.isMouseDown) {
 
625
            this.isMouseDown = false;
 
626
            this.ignoreEvent(evt);
 
627
        }
 
628
    },
 
629
 
 
630
    CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
 
631
});