Project

General

Profile

Download (48.7 KB) Statistics
| Branch: | Tag: | Revision:
1
//see also https://github.com/geetarista/jquery-plugin-template/blob/master/jquery.plugin-template.js
2

    
3
/**
4
 * Expected dom structure:
5
 *  '<div class="ahah-content" rel="'.$cdm_proxy_url.'"><span class="loading">Loading ....</span></div>';
6
 */
7
(function($, document, window, undefined) {
8

    
9
    $.fn.cdm_openlayers_map = function(mapserverBaseUrl, mapserverVersion, options) {
10

    
11
      var opts = $.extend({},$.fn.cdm_openlayers_map.defaults, options);
12

    
13
      // sanitize invalid opts.boundingBox
14
      if(opts.boundingBox &&  !( typeof opts.boundingBox  == 'string' && opts.boundingBox .length > 6)) {
15
        opts.boundingBox = null;
16
      }
17

    
18
      return this.each(function(){
19
          this.cdmOpenlayersMap = new CdmOpenLayers.Map($(this), mapserverBaseUrl, mapserverVersion, opts);
20
          this.cdmOpenlayersMap.create();
21
      }); // END each
22

    
23
    }; // END cdm_openlayers_map
24

    
25
})(jQuery, document, window, undefined);
26

    
27
(function($){
28
  $.fn.cdm_openlayers_map.defaults = {  // set up default options
29
    legendPosition:  null,      // 1,2,3,4,5,6 = display a legend in the corner specified by the number
30
    distributionOpacity: 0.75,
31
    legendOpacity: 0.75,
32
    // These are bounds in the epsg_4326 projection in degree
33
    boundingBox: null,
34
    aspectRatio: 2, // w/h
35
    showLayerSwitcher: false,
36
    baseLayerNames: ["open_topomap"],
37
    defaultBaseLayerName: 'open_topomap',
38
    maxZoom: 15,
39
    minZoom: 0,
40
      // hide the map when the data layer has no features
41
      hideEmptyMap: true,
42
    debug: true,
43
    /**
44
     * allows the map to display parts of the layers which are outside
45
     * the maxExtent if the aspect ratio of the map and of the baselayer
46
     * are not equal
47
     */
48
    displayOutsideMaxExtent: false,
49
    //  customWMSBaseLayerData: {
50
    //  name: "Euro+Med",
51
    //  url: "http://edit.africamuseum.be/geoserver/topp/wms",
52
    //  params: {layers: "topp:em_tiny_jan2003", format:"image/png", tiled: true},
53
    //  projection: "EPSG:7777777",
54
    //  maxExtent: "-1600072.75, -1800000, 5600000, 5850093",
55
    //  units: 'm'
56
    //  }
57
    customWMSBaseLayerData: {
58
        name: null,
59
        url: null,
60
        params: null,
61
        projection: null,
62
        proj4js_def: null,
63
        max_extent: null,
64
        units: null,
65
        untiled: null
66
    },
67
    wmsOverlayLayerData: {
68
      name: null,
69
      url: null,
70
      params: null,
71
      untiled: null
72
    },
73
    /**
74
     * when true the map is made resizable by adding the jQueryUI widget resizable
75
     * to the map container. This feature requires that the jQueryUI is loaded
76
     */
77
    resizable: false,
78
    wfsRootUrl: 'http://edit.africamuseum.be/geoserver/topp/ows',
79
    specimenPageBaseUrl: '/cdm_dataportal/occurrence/',
80
      specimenLinkText: 'Open unit'
81
  };
82
})(jQuery);
83

    
84
/**************************************************************************
85
 *                          CdmOpenLayers
86
 **************************************************************************/
87
(function() {
88

    
89
    /**
90
     * The CdmOpenLayers namespace definition
91
     */
92
    window.CdmOpenLayers  = (function () {
93

    
94
        // EPSG:3857 from http://spatialreference.org/ref/sr-org/6864/proj4/
95
        // OpenStreetMap etc
96
        Proj4js.defs["EPSG:3857"] = '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs';
97
        Proj4js.defs["EPSG:7777777"] = '+proj=lcc +lat_1=42 +lat_2=56 +lat_0=35 +lon_0=24 +x_0=3000000 +y_0=100000 +ellps=intl +towgs84=-87,-98,-121,0,0,0,0 +units=m +no_defs';
98

    
99
        var projections = {
100
                epsg_4326: new OpenLayers.Projection("EPSG:4326"),
101
                epsg_900913: new OpenLayers.Projection("EPSG:900913"),
102
                epsg_3857:  new OpenLayers.Projection("EPSG:3857"),
103
                epsg_7777777:  new OpenLayers.Projection("EPSG:7777777")
104
        };
105
        var mapExtends = {
106
                epsg_4326: new OpenLayers.Bounds(-180, -90, 180, 90),
107
                //  Spherical Mercator epsg_900913 is not supporting the whole marble
108
                epsg_900913: new OpenLayers.Bounds(-179, -85, 179, 85),
109
                //  Spherical Mercator
110
                epsg_3857: new OpenLayers.Bounds(-179, -85, 179, 85)
111
        };
112
        // transform epsg_900913 to units meter
113
        mapExtends.epsg_900913.transform(projections.epsg_4326, projections.epsg_900913);
114
        mapExtends.epsg_3857.transform(projections.epsg_4326, projections.epsg_3857);
115

    
116
        // make public by returning an object
117
        return {
118
            projections: projections,
119
            mapExtends: mapExtends,
120
            getMap: function (){},
121
            getLayerByName: function(layerName){} // initially empty function, will be populated by openlayers_layers.js
122
        };
123

    
124
    })(); // end of namespace definition for CdmOpenLayers
125

    
126
    /**
127
     * The CdmOpenLayers.Map constructor
128
     * @param mapElement
129
     * @param mapserverBaseUrl
130
     * @param mapserverVersion
131
     * @param opts
132
     * @returns
133
     */
134
    window.CdmOpenLayers.Map = function(mapElement, mapserverBaseUrl, mapserverVersion, opts){
135

    
136
      var mapServicePath = '/edit_wp5';
137

    
138
      // firebug console stub (avoids errors if firebug is not active)
139
      if(typeof console === "undefined") {
140
          console = { log: function() { } };
141
      }
142

    
143
      // sanitize given options
144
      try {
145
          opts.customWMSBaseLayerData.max_extent = OpenLayers.Bounds.fromString(opts.customWMSBaseLayerData.max_extent);
146
      } catch(e){
147
          opts.customWMSBaseLayerData.max_extent = null;
148
      }
149

    
150

    
151
      var legendImgSrc = null;
152

    
153
      var map = null;
154

    
155
      var infoElement = null;
156

    
157
      var baseLayers = [];
158

    
159
      var defaultBaseLayer = null;
160

    
161
      /**
162
       * The top most layer which will be places above all data layers
163
       *
164
       * @type {null}
165
       */
166
      var wmsOverlay = null;
167

    
168
        /**
169
         * The Control element to handle clicks on features in KML layers
170
         * @type {null}
171
         */
172
      var kmlSelectControl = null;
173

    
174
      /**
175
       * Default bounding box for map viewport in the projection of the base layer.
176
       * as defined by the user, can be null.
177
       *
178
       * These are bounds in the epsg_4326 projection, and will be transformed to the baselayer projection.
179
       *
180
       * @type string
181
       */
182
      var defaultBaseLayerBoundingBox = "-180,-90,180,90";
183

    
184
      /**
185
       * bounding box for map viewport as defined by the user, can be null.
186
       *
187
       * These are bounds in the projection of the base layer.
188
       *
189
       * @type string
190
       */
191
      var boundingBox = null;
192

    
193
      /**
194
       * Bounds for the view port calculated from the data layer responses.
195
       * These are either calculated by the minimum bounding box which
196
       * encloses the data in the data layers, or it is equal to the
197
       * boundingBox as defined by the user.
198
       *
199
       * These are bounds in the projection of the base layer.
200
       *
201
       * @see boundingBox
202
       *
203
       * @type OpenLayers.Bounds
204
       */
205
      var dataBounds = null;
206

    
207
      /**
208
       * Final value for the view port, calculated from the other bounds.
209
       *
210
       * These are bounds in the projection of the base layer.
211
       *
212
       * @type OpenLayers.Bounds
213
       */
214
      var zoomToBounds = null;
215

    
216
        /**
217
         * This as been introduced for #5683 with value TRUE,
218
         * but can cause feature to tbe hidden in KML layers.
219
         * Therefore this is now set to false.
220
         *
221
         * @type {boolean}
222
         */
223
      var zoomToClosestLevel = false;
224

    
225
      var LAYER_DATA_CNT = 0;
226

    
227
      /* this is usually the <div id="openlayers"> element */
228
      var mapContainerElement = mapElement.parent();
229

    
230
      var defaultControls = [
231
         new OpenLayers.Control.PanZoom(),
232
         new OpenLayers.Control.Navigation(
233
           {
234
             zoomWheelEnabled: false,
235
             handleRightClicks:true,
236
             zoomBoxKeyMask: OpenLayers.Handler.MOD_CTRL
237
           }
238
         )
239
      ];
240

    
241

    
242
      var layerByNameMap = {
243
              tdwg1: 'topp:tdwg_level_1',
244
              tdwg2: 'topp:tdwg_level_2',
245
              tdwg3: 'topp:tdwg_level_3',
246
              tdwg4: 'topp:tdwg_level_4'
247
      };
248

    
249
      /**
250
       * Known projections by layer name. This map helps avoid requesting the server for the
251
       * projection. See readProjection()
252
       */
253
      var layerProjections = {
254
        'topp:tdwg_level_1': CdmOpenLayers.projections.epsg_4326,
255
        'topp:tdwg_level_2': CdmOpenLayers.projections.epsg_4326,
256
        'topp:tdwg_level_3': CdmOpenLayers.projections.epsg_4326,
257
        'topp:tdwg_level_4': CdmOpenLayers.projections.epsg_4326,
258
        'topp:phytogeographical_regions_of_greece': CdmOpenLayers.projections.epsg_4326,
259
        'topp:euromed_2013': CdmOpenLayers.projections.epsg_7777777,
260
        'topp:flora_cuba_2016': CdmOpenLayers.projections.epsg_4326
261
      };
262

    
263
      if(opts.resizable === true) {
264
        // resizable requires jQueryUI to  be loaded!!!
265
        mapContainerElement.resizable({
266
          resize: function( event, ui ) {
267
            map.updateSize();
268
            //   this.printInfo();
269
          }
270
        });
271
      }
272

    
273
        /**
274
         * Removes the map and the parent container from the
275
         * DOM and destroys the OpenLayers map object
276
         */
277
        function removeMap() {
278
            //  if you are using an application which removes a container
279
            //  of the map from the DOM, you need to ensure that you destroy the map before this happens;
280
            map.destroy;
281
            jQuery(map.div).parent().remove();
282
        }
283

    
284
        /**
285
         *
286
         */
287
        this.create = function(){ // public function
288

    
289
          // set the height of the container element
290
          adjustHeight();
291

    
292
          // register for resize events to be able to adjust the map aspect ratio and legend position
293
          jQuery( window ).resize(function() {
294
            adjustHeight();
295
            adjustLegendAsElementPosition();
296
          });
297

    
298
          createBaseLayers(opts.baseLayerNames, opts.defaultBaseLayerName, opts.customWMSBaseLayerData);
299

    
300
          initMap();
301

    
302

    
303
          if(opts.boundingBox){
304
            boundingBox = OpenLayers.Bounds.fromString(opts.boundingBox);
305
          }
306

    
307
          // -- Distribution Layer --
308
          var mapServiceRequest;
309
          var distributionQuery = mapElement.attr('data-distributionQuery');
310

    
311
          if(distributionQuery !== undefined){
312
            distributionQuery = mergeQueryStrings(distributionQuery, '&recalculate=false');
313
            if(typeof legendPosition === 'number'){
314
              distributionQuery = mergeQueryStrings(distributionQuery, 'legend=1&mlp=' + opts.legendPosition);
315
            }
316
            if(opts.boundingBox){
317
              distributionQuery = mergeQueryStrings(distributionQuery, 'bbox=' + boundingBox);
318
            }
319

    
320
            distributionQuery = mergeQueryStrings(distributionQuery, 'callback=?');
321
            var legendFormatQuery = mapElement.attr('data-legendFormatQuery');
322
            if(legendFormatQuery !== undefined){
323
              legendImgSrc = mergeQueryStrings('/GetLegendGraphic?SERVICE=WMS&VERSION=1.1.1', legendFormatQuery);
324
            }
325

    
326
            mapServiceRequest = mapserverBaseUrl + mapServicePath + '/' + mapserverVersion + '/rest_gen.php?' + distributionQuery;
327

    
328
            LAYER_DATA_CNT++;
329
            jQuery.ajax({
330
              url: mapServiceRequest,
331
              dataType: "jsonp",
332
              success: function(data){
333
                  var layers = createDataLayer(data, "AREA");
334
                  addLayers(layers);
335
                // layerDataLoaded(); will be called after reading the projection from the WFS for the data layer
336
              }
337
            });
338
          }
339

    
340
          // -- Occurrence Layer --
341
          var occurrenceQuery = mapElement.attr('data-occurrenceQuery');
342
          if(occurrenceQuery !== undefined){
343
            occurrenceQuery = mergeQueryStrings(occurrenceQuery, '&recalculate=false');
344
//              if(typeof legendPosition == 'number'){
345
//              occurrenceQuery = mergeQueryStrings(distributionQuery, 'legend=1&mlp=' + opts.legendPosition);
346
//              }
347

    
348

    
349
            occurrenceQuery = mergeQueryStrings(occurrenceQuery, 'callback=?');
350
//              var legendFormatQuery = mapElement.attr('legendFormatQuery');
351
//              if(legendFormatQuery !== undefined){
352
//              legendImgSrc = mergeQueryStrings('/GetLegendGraphic?SERVICE=WMS&VERSION=1.1.1', legendFormatQuery);
353
//              }
354
            if(opts.boundingBox){
355
              occurrenceQuery = mergeQueryStrings(occurrenceQuery, 'bbox=' + boundingBox);
356
            }
357

    
358
            mapServiceRequest = mapserverBaseUrl + mapServicePath + '/' + mapserverVersion + '/rest_gen.php?' + occurrenceQuery;
359

    
360
            LAYER_DATA_CNT++;
361
            jQuery.ajax({
362
              url: mapServiceRequest,
363
              dataType: "jsonp",
364
              success: function(data){
365
                  var layers = createDataLayer(data, "POINT");
366
                  addLayers(layers);
367
                  // layerDataLoaded(); will be called after reading the projection from the WFS for the data layer
368
              }
369
            });
370
          }
371

    
372
            // -- KML Layer --
373
            var kmlRequestUrl = mapElement.attr('data-kml-request-url');
374
            if(kmlRequestUrl !== undefined){
375

    
376
                LAYER_DATA_CNT++;
377
                var kmlLayer = new OpenLayers.Layer.Vector("KML", {
378
                    strategies: [new OpenLayers.Strategy.Fixed()],
379
                    protocol: new OpenLayers.Protocol.HTTP({
380
                        url: kmlRequestUrl,
381
                        format: new OpenLayers.Format.KML({
382
                            extractStyles: true,
383
                            extractAttributes: true
384
                            // maxDepth: 2
385
                        })
386
                    })
387
                });
388
                map.addLayer(kmlLayer);
389
                // create select control
390
                kmlSelectControl = new OpenLayers.Control.SelectFeature(kmlLayer);
391
                kmlLayer.events.on({
392
                    "featureselected": onKmlFeatureSelect,
393
                    "featureunselected": onKmlFeatureUnselect,
394
                    'loadend': function(event) {
395
                        if(opts.hideEmptyMap && kmlLayer.features.length == 0){
396
                            log("No feature in KML layer, removing map ...")
397
                            removeMap();
398
                        } else {
399
                            applyLayerZoomBounds(event);
400
                            disablePolygonFeatureClick(event);
401
                        }
402
                    }
403
                });
404
                map.addControl(kmlSelectControl);
405
                kmlSelectControl.activate();
406

    
407
                initPostDataLoaded();
408
            }
409

    
410
          if(LAYER_DATA_CNT === 0) {
411
            // a map only with base layer
412
            initPostDataLoaded();
413
          }
414

    
415
          // -- Overlay Layer --
416
          if(opts.wmsOverlayLayerData.params){
417
            overlay_layer_params = opts.wmsOverlayLayerData.params;
418
            overlay_layer_params.transparent=true;
419
            wmsOverlay = createWMSLayer(
420
              opts.wmsOverlayLayerData.name,
421
              opts.wmsOverlayLayerData.url,
422
              overlay_layer_params,
423
              null,
424
              null,
425
              null,
426
              null,
427
              opts.wmsOverlayLayerData.untiled
428
            );
429

    
430
            if(map.addLayer(wmsOverlay)){
431
              wmsOverlay.setVisibility(true);
432
              map.setLayerIndex(wmsOverlay, 100);
433
              log("Overlay wms added");
434
            } else {
435
              log("ERROR adding overlay wms layer")
436
            }
437
          }
438

    
439
          log("Map viewer creation complete.");
440

    
441
        };
442

    
443
      /**
444
       * Provides the layer name which can be used in WMS/WFS requests.
445
       * The layerData.tdwg field contains invalid layer names in case of
446
       * the tdwg layers. This function handles with this bug.
447
       *
448
       * @param layerData
449
       * @returns String
450
       *    the correct layer name
451
       */
452
        var fixLayerName = function(layerData){
453
         var wmsLayerName = layerByNameMap[layerData.tdwg];
454
         if(!wmsLayerName){
455
           wmsLayerName = "topp:" + layerData.tdwg;
456
         }
457
         return wmsLayerName;
458
        };
459

    
460
        var layerDataLoaded = function() {
461
          LAYER_DATA_CNT--;
462
          if(LAYER_DATA_CNT === 0){
463
            initPostDataLoaded();
464
          }
465
        };
466

    
467
        var initPostDataLoaded = function () {
468
          // all layers prepared, make them visible
469
          map.layers.forEach(function(layer){
470
            layer.setVisibility(true);
471
          });
472

    
473
          // zoom to the zoomToBounds
474
          log(" > starting zoomToExtend: " + zoomToBounds + ", zoomToClosestLevel: " + zoomToClosestLevel, true);
475
          map.zoomToExtent(zoomToBounds, zoomToClosestLevel);
476

    
477

    
478
          if(map.getZoom() > opts.maxZoom){
479
            map.zoomTo(opts.maxZoom);
480
          } else if(map.getZoom() < opts.minZoom){
481
            map.zoomTo(opts.minZoom);
482
          }
483

    
484
          // make sure the wmsOverlay is still on top
485
          if(wmsOverlay){
486
            map.setLayerIndex(wmsOverlay, 100);
487
          }
488

    
489
          log(" > zoomToExtend done", true);
490
        };
491

    
492
      /**
493
       * Returns  the projection of the defaultBaseLayer which is the
494
       * the projection to which all other layers and locations must be transformed.
495
       */
496
      var referenceProjection = function() {
497
        if(defaultBaseLayer){
498
          if(defaultBaseLayer.projection){
499
            return defaultBaseLayer.projection;
500
          } else if(defaultBaseLayer.sphericalMercator === true){
501
            return CdmOpenLayers.projections.epsg_900913;
502
          } else {
503
            log("Error - referenceProjection() defaultBaseLayer " + defaultBaseLayer.name + " misses projection information");
504
          }
505

    
506
        } else {
507
          log("Error - referenceProjection() defaultBaseLayer not set");
508
          return null;
509
        }
510
      };
511

    
512
      /**
513
       * Returns the maxExtent of the defaultBaseLayer.
514
       */
515
      var referenceMaxExtent = function() {
516
        if(defaultBaseLayer){
517
          return defaultBaseLayer.maxExtent;
518
        } else {
519
          log("Error - referenceMaxExtent() defaultBaseLayer not set");
520
          return null;
521
        }
522
      };
523

    
524
        var getHeight = function(){
525
          return mapContainerElement.width() / opts.aspectRatio;
526
        };
527

    
528
        var getWidth = function(){
529
          return mapContainerElement.width();
530
        };
531

    
532
        var adjustHeight = function() {
533
          mapContainerElement.css("height", getHeight());
534
        };
535

    
536
        /**
537
         * public function
538
         */
539
        this.registerEvents = function(events){
540
            for (var key in events) {
541
                if (events.hasOwnProperty(key)) {
542
                    map.events.register(key, map , events[key]);
543
                }
544
            }
545
        };
546

    
547

    
548
        /**
549
         * public function
550
         */
551
        this.getMap = function(){
552
            return map;
553
        };
554

    
555
        /**
556
         * Prints info on the current map into the jQuery element
557
         * as set in the options (opts.infoElement)
558
         * public function
559
         *
560
         */
561
        this.printInfo = function(){
562

    
563

    
564
            var mapExtendDegree = null;
565
            if(map.getExtent() != null){
566
              // If the baselayer is not yet set, getExtent() returns null.
567
              mapExtendDegree = map.getExtent().clone();
568
              mapExtendDegree.transform(map.baseLayer.projection, CdmOpenLayers.projections.epsg_4326);
569
            }
570

    
571
            var info = "<dl>";
572
            info += "<dt>zoom:<dt><dd>" + map.getZoom() + "</dd>";
573
            if(opts.debug){
574
                info += "<dt>map resolution:<dt><dd>" + map.getResolution() + "</dd>";
575
                info += "<dt>map max resolution:<dt><dd>" + map.getMaxResolution() + "</dd>";
576
                info += "<dt>map scale:<dt><dd>" + map.getScale() + "</dd>";
577
                info += "<dt>map width, height:<dt><dd>" + mapContainerElement.width() +  ", " + mapContainerElement.height() + "</dd>";
578
                info += "<dt>map aspect ratio:<dt><dd>" + mapContainerElement.width() / mapContainerElement.height() + "</dd>";
579
                if(map.getExtent() != null){
580
                  info += "<dt>map extent bbox:<dt><dd class=\"map-extent-bbox\"><span class=\"layer-value\">" + map.getExtent().toBBOX() + "</span>, (in degree:<span class=\"degree-value\">" + mapExtendDegree.toBBOX() + "</span>)</dd>";
581
                  info += "<dt>map maxExtent bbox:<dt><dd>" + map.getMaxExtent().toBBOX() + "</dd>";
582
                  info += "<dt>baselayer extent bbox:<dt><dd class=\"baselayer-extent-bbox\"><span class=\"layer-value\">" +  map.baseLayer.getExtent().toBBOX() + "</span>, (in degree: <span class=\"degree-value\">"
583
                    + map.baseLayer.getExtent().clone().transform(map.baseLayer.projection, CdmOpenLayers.projections.epsg_4326) + "</span>)</dd>";
584
                  info += "<dt>baselayer projection:<dt><dd>" + map.baseLayer.projection.getCode() + "</dd>";
585
                }
586
            } else {
587
                info += "<dt>bbox:<dt><dd>" + (mapExtendDegree !== null ? mapExtendDegree.toBBOX() : 'NULL') + "</dd>";
588
            }
589
            info += "</dl>";
590

    
591
            if(infoElement === null){
592
                infoElement = jQuery('<div class="map_info"></div>');
593
                mapElement.parent().after(infoElement);
594
            }
595
            infoElement.html(info);
596
        };
597

    
598
        /**
599
         * Initialize the Openlayers Map with the base layer
600
         */
601
        var initMap = function(){
602

    
603
          if(opts.showLayerSwitcher === true){
604
              defaultControls.push(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
605
          }
606

    
607
          defaultControls.unshift(layerLoadingControl()); // as first control, needs to be below all others!
608

    
609
//          var maxExtentByAspectRatio = cropBoundsToAspectRatio(defaultBaseLayer.maxExtent, getWidth/getHeight);
610
          var maxResolution = null;
611
          // gmaps has no maxExtent at this point, need to check for null
612
          if(referenceMaxExtent() !== null){
613
              maxResolution = Math[(opts.displayOutsideMaxExtent ? 'max' : 'min')](
614
                referenceMaxExtent().getWidth() / getWidth(),
615
                referenceMaxExtent().getHeight() / getHeight()
616
              );
617
          }
618
          console.log("mapOptions.maxResolution: " + maxResolution);
619
          console.log("mapOptions.restrictedExtent: " + referenceMaxExtent());
620

    
621
          map = new OpenLayers.Map(
622
            mapElement.attr('id'),
623
            {
624
              // defines the map ui elements and interaction features
625
              controls: defaultControls,
626

    
627
              // maxResolution determines the lowest zoom level and thus places the map
628
              // in its maximum extent into the available view port so that no additional
629
              // gutter is visible and no parts of the map are hidden
630
              // see http://trac.osgeo.org/openlayers/wiki/SettingZoomLevels
631
              // IMPORTANT!!!
632
              // the maxResulution set here will be overwritten if the baselayers maxResolution
633
              // it is set
634
              maxResolution: maxResolution,
635

    
636
              // setting restrictedExtent the the maxExtent prevents from panning the
637
              // map out of its bounds
638
              restrictedExtent: referenceMaxExtent(),
639
//                      maxExtent: referenceMaxExtent(),
640

    
641
              // Setting the map.fractionalZoom property to true allows zooming to an arbitrary level
642
              // (between the min and max resolutions).
643
              // fractional tiles are not supported by XYZ layers like OSM so this option would
644
              // break the tile retrieval for OSM (e.g.: tile for fractional zoom level
645
              // 1.2933333333333332 = http://b.tile.openstreetmap.org/1.2933333333333332/1/0.png)
646
              fractionalZoom: defaultBaseLayer.CLASS_NAME != "OpenLayers.Layer.OSM" && defaultBaseLayer.CLASS_NAME != "OpenLayers.Layer.XYZ",
647

    
648
              eventListeners: opts.eventListeners,
649
              // creating the map with a null theme, since we include the stylesheet directly in the page
650
              theme: null
651

    
652
            }
653
          );
654

    
655
          //add the base layers
656

    
657
          addLayers(baseLayers);
658
          map.setBaseLayer(defaultBaseLayer);
659

    
660
          // calculate the bounds to zoom to
661
          zoomToBounds = calculateZoomToBounds(opts.boundingBox ? opts.boundingBox : defaultBaseLayerBoundingBox);
662
          // zoomToBounds = cropBoundsToAspectRatio(zoomToBounds, map.getSize().w / map.getSize().h);
663
          console.log("baselayer zoomToBounds: " + zoomToBounds);
664

    
665
        };
666

    
667
        var addLayers = function(layers){
668

    
669
          layers.forEach(function(layer){
670
            // layer.setVisibility(false);
671
          });
672

    
673
          map.addLayers(layers);
674
        };
675

    
676
        /**
677
         * add a distribution or occurrence layer
678
         *
679
         * @param mapResponseObj
680
         *   The reponse object returned by the edit map service
681
         * @param dataType
682
         *   either "AREA" or "POINT"
683
         */
684
        var createDataLayer = function(mapResponseObj, dataType){
685

    
686
          console.log("createDataLayer() : creating data layer of type " + dataType);
687

    
688
          dataLayerOptions = makeWMSLayerOptions();
689
          dataLayerOptions.displayOutsideMaxExtent = true; // move into makeWMSLayerOptions?
690

    
691
          var layers = [];
692
          // add additional layers, get them from the mapResponseObj
693
          if(mapResponseObj !== undefined){
694
            if(dataType === "POINT" && mapResponseObj.points_sld !== undefined){
695
              var pointLayer;
696
              // it is a response for an point map
697
              var geoserverUri;
698
              if(mapResponseObj.geoserver) {
699
                  geoserverUri = mapResponseObj.geoserver;
700
              } else {
701
                  // it is an old service which is not providing the corresponding geoserver URI, so we guess it
702
                  geoserverUri = mapserverBaseUrl + "/geoserver/wms";
703
              }
704

    
705
              //TODO points_sld should be renamed to sld in response + fill path to sld should be given
706
              pointLayer = new OpenLayers.Layer.WMS(
707
                'points',
708
                geoserverUri,
709
                {
710
                    layers: 'topp:rest_points',
711
                    transparent:"true",
712
                    format:"image/png"
713
                },
714
                dataLayerOptions
715
              );
716

    
717
              var sld = mapResponseObj.points_sld;
718
              if(sld.indexOf("http://") !== 0){
719
                  // it is an old servive which is not providing the full sdl URI, so we guess it
720
                  //  http://edit.africamuseum.be/synthesys/www/v1/sld/
721
                  //  http://edit.br.fgov.be/synthesys/www/v1/sld/
722
                  sld =  mapserverBaseUrl + "/synthesys/www/v1/sld/" + sld;
723
              }
724
              pointLayer.params.SLD = sld;
725

    
726
              layers.push(pointLayer);
727
            } else {
728
              // it is a response from for a distribution map
729
              console.log("createDataLayer() : start with adding distribution layers :");
730
              for ( var i in mapResponseObj.layers) {
731
                var layerData = mapResponseObj.layers[i];
732

    
733
                var layerName = fixLayerName(layerData);
734
                console.log(" " + i +" -> " +layerName);
735
                var layer = new OpenLayers.Layer.WMS(
736
                  layerName,
737
                  mapResponseObj.geoserver + "/wms",
738
                  {
739
                      layers: fixLayerName(layerData),
740
                      transparent:"true",
741
                      format:"image/png"
742
                  },
743
                  dataLayerOptions
744
                  );
745
                layer.params.SLD = layerData.sld;
746
                layer.setOpacity(opts.distributionOpacity);
747

    
748
                layers.push(layer);
749
              }
750
            }
751

    
752
            if(layers.length > 0) {
753
              // calculate zoomBounds using the first layer
754
              if(mapResponseObj.bbox !== undefined){
755
                var newBounds =  OpenLayers.Bounds.fromString( mapResponseObj.bbox );
756
                var projection;
757
                if(dataType === "POINT"){
758
                  projection = CdmOpenLayers.projections.epsg_4326;
759
                  // mapResponseObj.bbox are bounds  are always returned in EPSG:4326 since the point service does not know about the projection
760
                  // console.log("createDataLayer() POINT: referenceProjection()=" + referenceProjection() + ", map.getProjectionObject()=" + map.getProjectionObject() );
761
                  processDataBounds(projection, newBounds, dataType, layerDataLoaded);
762
                } else {
763
                  // Type == AREA
764
                  // the bounds are in the projection of the data layer
765
                  // here we expect that all data layers are in the same projection and will use the first data layer as reference
766
                  // the edit map service is most probably working the same and is not expected to be able to handle multiple data layers
767
                  // with different projections
768
                  readProjection(layers[0], function(projection) {
769
                    processDataBounds(projection, newBounds, dataType, layerDataLoaded);
770
                  })
771
                }
772

    
773
                console.log("createDataLayer() " + dataType + ": transforming newBounds " + newBounds + " from projection=" +  projection + " to referenceProjection()=" + referenceProjection());
774
                newBounds.transform(projection, referenceProjection());
775
                if(dataBounds !== null){
776
                  dataBounds.extend(newBounds);
777
                } else if(newBounds !== undefined){
778
                  dataBounds = newBounds;
779
                }
780

    
781
                zoomToBounds = dataBounds;
782
                console.log("createDataLayer() : viewport zoomToBounds are now: " + zoomToBounds);
783
                zoomToClosestLevel = false;
784
              }
785
            }
786

    
787
            if(legendImgSrc != null && opts.legendPosition !== undefined && mapResponseObj.legend !== undefined){
788
                var legendSrcUrl = mapResponseObj.geoserver + legendImgSrc + mapResponseObj.legend;
789
                addLegendAsElement(legendSrcUrl);
790
                //addLegendAsLayer(legendSrcUrl, map);
791
            }
792

    
793
            return layers;
794
          }
795

    
796
        };
797

    
798
      /**
799
       * transforms the newBounds from the projection to the referenceProjection() and finally calculates the
800
       * zoomBounds for the viewport.
801
       *
802
       * @param projection
803
       * @param newBounds
804
       * @param layerDataTypeString
805
       *    Only used for logging, (either "AREA" or "POINT")
806
       * @param callback
807
       */
808
        var processDataBounds = function(projection, newBounds, layerDataTypeString, callback){
809

    
810
          console.log("createDataLayer() " + layerDataTypeString + ": transforming newBounds " + newBounds + " from projection=" +  projection + " to referenceProjection()=" + referenceProjection());
811
          newBounds.transform(projection, referenceProjection());
812
          if(dataBounds !== null){
813
            dataBounds.extend(newBounds);
814
          } else if(newBounds !== undefined){
815
            dataBounds = newBounds;
816
          }
817

    
818
          zoomToBounds = dataBounds;
819
          console.log("createDataLayer() : viewport zoomToBounds are now: " + zoomToBounds);
820
          zoomToClosestLevel = false;
821
          callback();
822
        };
823

    
824
      /**
825
       * Get the crs data from the WFS and read the projection name from it. Finally the supplied callback will
826
       * be called with the matching projection object as parameter.
827
       * @param layer
828
       * @param callback
829
       *   Function(Projection projection)
830
       */
831
        var readProjection = function(layer, callback){
832

    
833
          var projection = layer.projection;
834

    
835
          if(!projection) {
836
            projection = layerProjections[layer.name];
837
          }
838

    
839

    
840
          if(projection) {
841
            callback(projection);
842
          } else {
843
            // asking the edit map server would be the best:
844
            //    > http://edit.africamuseum.be/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:euromed_2013&maxFeatures=1&outputFormat=application/json
845
            // or
846
            //    > http://edit.africamuseum.be/geoserver/topp/ows?service=WFS&request=getCapabilities'
847
            // but the latter returns only XML
848
            var parameters = {
849
              service: 'WFS',
850
              version: '1.0.0',
851
              request: 'GetFeature',
852
              typeName: layer.name,
853
              maxFeatures: 1, // only one feature
854
              outputFormat: 'text/javascript',
855
              format_options: 'callback:getJson'
856
            };
857

    
858
            jQuery.ajax({
859
              url: opts.wfsRootUrl + "?" + jQuery.param(parameters),
860
              dataType: 'jsonp',
861
              jsonpCallback: 'getJson',
862
              success: function(data, textStatus, jqXHR){
863
                if(data.crs && data.crs.type && data.crs.properties.code){
864
                  var projectionName = data.crs.type + "_" + data.crs.properties.code;
865
                  log("projection name found in WFS response:" + projectionName);
866
                  projection = CdmOpenLayers.projections[projectionName.toLowerCase()];
867
                  callback(projection);
868
                }
869
              },
870
              error : function(jqXHR, textStatus, errorThrown) {
871
                log("projection name not found in WFS response, due to error: " + textStatus);
872
                projection = CdmOpenLayers.projections.epsg_4326;
873
                callback(projection);
874
              }
875

    
876
            });
877
          }
878
        };
879

    
880
        /**
881
         *
882
         */
883
        var addLegendAsElement= function(legendSrcUrl){
884

    
885
            var legendElement = jQuery('<div class="openlayers_legend"></div>');
886
            var legendImage = jQuery('<img src="' + legendSrcUrl + '"/>');
887
            legendElement
888
                .css('opacity', opts.legendOpacity)
889
                .css('position', 'relative')
890
                .css('z-index', '1002')
891
                .css('top', -mapElement.height());
892
            legendImage.load(function () {
893
                jQuery(this).parent()
894
                    .css('left', getWidth() - jQuery(this).width())
895
                    .width(jQuery(this).width());
896
                // reset height to original value
897
                adjustHeight();
898
            });
899
            legendElement.html(legendImage);
900
            mapElement.after(legendElement);
901
        };
902

    
903
         var adjustLegendAsElementPosition = function (){
904
           var legendContainer = mapContainerElement.children('.openlayers_legend');
905
           var legendImage = legendContainer.children('img');
906
           legendContainer.css('top', -mapElement.height())
907
             .css('left', getWidth() - legendImage.width());
908
         };
909

    
910

    
911
        var addLegendAsLayer= function(legendSrcUrl, map){
912
            var w, h;
913

    
914
            // 1. download image to find height and width
915
            mapElement.after('<div class="openlayers_legend"><img src="' + legendSrcUrl + '"></div>');
916
            mapElement.next('.openlayers_legend').css('display', 'none').css('opacity', opts.legendOpacity).find('img').load(function () {
917

    
918
                w = mapElement.next('.openlayers_legend').find('img').width();
919
                h = mapElement.next('.openlayers_legend').find('img').height();
920
                mapElement.next('.openlayers_legend').remove();
921

    
922
//              createLegendLayer();
923
//              // 2. create the Legend Layer
924
                //TODO createLegendLayer as inner function seems like an error
925
//              var createLegendLayer = function(){
926
                //
927
                //
928
//              var legendLayerOptions={
929
//              maxResolution: '.$maxRes.',
930
//              maxExtent: new OpenLayers.Bounds(0, 0, w, h)
931
//              };
932
                //
933
//              var legendLayer = new OpenLayers.Layer.Image(
934
//              'Legend',
935
//              legendSrcUrl,
936
//              new OpenLayers.Bounds(0, 0, w, h),
937
//              new OpenLayers.Size(w, h),
938
//              imageLayerOptions);
939
//              };
940
            });
941

    
942

    
943
        };
944

    
945
        /**
946
         * merge 2 Url query strings
947
         */
948
        var mergeQueryStrings = function(queryStr1, queryStr2){
949
            if(queryStr1.charAt(queryStr1.length - 1) != '&'){
950
                queryStr1 += '&';
951
            }
952
            if(queryStr2.charAt(0) == '&'){
953
                return queryStr1 + queryStr2.substr(1);
954
            } else {
955
                return queryStr1 + queryStr2;
956
            }
957

    
958
        };
959

    
960
        /**
961
         *
962
         */
963
        var createBaseLayers = function( baseLayerNames, defaultBaseLayerName, customWMSBaseLayerData){
964

    
965
            for(var i = 0; i <  baseLayerNames.length; i++) {
966
                // create the layer
967
                if (baseLayerNames[i] === "custom_wms_base_layer_1"){
968
                    wmsBaseLayer =createWMSLayer(
969
                            customWMSBaseLayerData.name,
970
                            customWMSBaseLayerData.url,
971
                            customWMSBaseLayerData.params,
972
                            customWMSBaseLayerData.projection,
973
                            customWMSBaseLayerData.proj4js_def,
974
                            customWMSBaseLayerData.units,
975
                            customWMSBaseLayerData.max_extent,
976
                            customWMSBaseLayerData.untiled
977
                    );
978
                  wmsBaseLayer.setIsBaseLayer(true);
979
                  baseLayers[i] = wmsBaseLayer;
980
                } else {
981
                    baseLayers[i] = window.CdmOpenLayers.getLayerByName(baseLayerNames[i]);
982
                }
983
                // set default baselayer
984
                if(baseLayerNames[i] === defaultBaseLayerName){
985
                    defaultBaseLayer = baseLayers[i];
986
                }
987

    
988
            }
989
        };
990

    
991
        /**
992
         * returns the intersection of the bounds b1 and b2.
993
         * The b1 and b2 do not intersect b1 will be returned.
994
         *
995
         * @param OpenLayers.Bounds b1
996
         * @param OpenLayers.Bounds b2
997
         *
998
         * @return the bounds of the intersection between both rectangles
999
         */
1000
        var intersectionOfBounds = function (b1, b2){
1001

    
1002
            if(b1.intersectsBounds(b2)){
1003

    
1004
                var left = Math.max(b1.left, b2.left);
1005
                var bottom = Math.max(b1.bottom, b2.bottom);
1006
                var right = Math.min(b1.right, b2.right);
1007
                var top = Math.min(b1.top, b2.top);
1008

    
1009
                return new OpenLayers.Bounds(left, bottom, right, top);
1010

    
1011
            } else {
1012
                return b1;
1013
            }
1014
        };
1015

    
1016
        /**
1017
         *
1018
         * @param b OpenLayers.Bounds to crop
1019
         * @param aspectRatio as fraction of width/height as float value
1020
         *
1021
         * @return the bounds cropped to the given aspectRatio
1022
         */
1023
        var cropBoundsToAspectRatio = function (b, aspectRatio){
1024

    
1025
            var cropedB = b.clone();
1026

    
1027
            if(aspectRatio === 1){
1028
                return cropedB;
1029
            }
1030

    
1031
            /*
1032
             * LonLat:
1033
             *   lon {Float} The x-axis coordinate in map units
1034
             *   lat {Float} The y-axis coordinate in map units
1035
             */
1036
            var center = cropedB.getCenterLonLat();
1037
            var dist;
1038
            if(aspectRatio < 1){
1039
                dist = (b.getHeight() / 2) * aspectRatio;
1040
                cropedB.top = center.lat + dist;
1041
                cropedB.cropedBottom = center.lat - dist;
1042
            } else if(aspectRatio > 1){
1043
                dist = (b.getWidth() / 2) / aspectRatio;
1044
                cropedB.left = center.lon - dist;
1045
                cropedB.right = center.lon + dist;
1046
            }
1047
            return cropedB;
1048
        };
1049

    
1050
        /**
1051
         * returns the version number contained in the version string:
1052
         *   v1.1 --> 1.1
1053
         *   v1.2_dev --> 1.2
1054
         */
1055
        var mapServerVersionNumber = function() {
1056
            var pattern = /v([\d\.]+).*$/;
1057
            var result;
1058
            if (result = mapserverVersion.match(pattern) !== null) {
1059
                return result[0];
1060
            } else {
1061
                return null;
1062
            }
1063
        };
1064

    
1065

    
1066

    
1067
      /**
1068
       * returns the zoom to bounds.
1069
       *
1070
       * @param bboxString
1071
       *     a string representation of the bounds in degree for epsg_4326
1072
       *
1073
       * @return the bboxstring projected onto the layer and intersected with the maximum extent of the layer
1074
       */
1075
      var calculateZoomToBounds = function(bboxString){
1076
        var zoomToBounds;
1077
        if(bboxString) {
1078
          zoomToBounds = OpenLayers.Bounds.fromString(bboxString);
1079
          if(referenceProjection().proj.projName){
1080
            // SpericalMercator is not supporting the full extent -180,-90,180,90
1081
            // crop if need to -179, -85, 179, 85
1082
            if(zoomToBounds.left < -179){
1083
              zoomToBounds.left =  -179;
1084
            }
1085
            if(zoomToBounds.bottom < -85){
1086
              zoomToBounds.bottom =  -85;
1087
            }
1088
            if(zoomToBounds.right > 179){
1089
              zoomToBounds.right =  179;
1090
            }
1091
            if(zoomToBounds.top > 85){
1092
              zoomToBounds.top = 85;
1093
            }
1094
          }
1095
          // transform bounding box given in degree values to the projection of the base layer
1096
          zoomToBounds.transform(CdmOpenLayers.projections.epsg_4326, referenceProjection());
1097
        } else if(referenceMaxExtent()) {
1098
          zoomToBounds = referenceMaxExtent();
1099
          // no need to transform since the bounds are obtained from the layer
1100
        } else {
1101
          // use the more narrow bbox of the SphericalMercator to avoid reprojection problems
1102
          // SpericalMercator is not supporting the full extent!
1103
          zoomToBounds = CdmOpenLayers.mapExtends.epsg_900913;
1104
          // transform bounding box given in degree values to the projection of the base layer
1105
          zoomToBounds.transform(CdmOpenLayers.projections.epsg_4326, referenceProjection());
1106
        }
1107

    
1108
        zoomToBounds = intersectionOfBounds(referenceMaxExtent(), zoomToBounds);
1109

    
1110
        log("zoomBounds calculated: " + zoomToBounds.toString());
1111

    
1112
        return zoomToBounds;
1113
      };
1114

    
1115
      var log = function(message, addTimeStamp){
1116
        var timestamp = '';
1117
        if(addTimeStamp === true){
1118
          var time = new Date();
1119
          timestamp = time.getSeconds() + '.' + time.getMilliseconds() + 's';
1120
        }
1121
        console.log(timestamp + message);
1122
      };
1123

    
1124
      var makeWMSLayerOptions = function(projection, proj4js_def, maxExtent, units, untiled) {
1125
        var wmsOptions = {
1126
          isBaseLayer: false,
1127
          displayInLayerSwitcher: true
1128
        };
1129

    
1130
        if (projection) {
1131
          if (proj4js_def) {
1132
            // in case projection has been defined for the layer and if there is also
1133
            // a Proj4js.defs, add it!
1134
            Proj4js.defs[projection] = proj4js_def;
1135
          }
1136
          wmsOptions.projection = projection;
1137
          if (maxExtent === null) {
1138
            maxExtent = CdmOpenLayers.mapExtends.epsg_4326.clone();
1139
            maxExtent.transform(CdmOpenLayers.projections.epsg_4326, projection);
1140
          }
1141
        } else {
1142
          // use the projection and maxextent of the base layer
1143
          maxExtent = referenceMaxExtent();
1144
        }
1145

    
1146
        if (maxExtent) {
1147
          wmsOptions.maxExtent = maxExtent;
1148
        }
1149

    
1150
        if (units) {
1151
          wmsOptions.units = units;
1152
        }
1153

    
1154
        if (untiled) {
1155
          wmsOptions.singleTile = true;
1156
          wmsOptions.ratio = 1;
1157
        }
1158

    
1159
        return wmsOptions;
1160
      };
1161

    
1162
      var applyLayerZoomBounds = function(event){
1163
            var layer = event.object;
1164
            zoomToBounds = layer.getDataExtent();
1165
            log("data bounds of layer as zoom bounds: " + zoomToBounds.toString());
1166
            layerDataLoaded();
1167
      };
1168

    
1169
      var disablePolygonFeatureClick = function(event){
1170
          var layer = event.object;
1171
          var kmlLayerElement = jQuery('#' + layer.id);
1172
          //log("KML Layer DOM element: " + kmlLayerElement);
1173
          kmlLayerElement.find('path').css('pointer-events', 'none');
1174
      }
1175

    
1176
      /**
1177
       * Creates a WMS Base layer
1178
       * @param String name
1179
       *     A name for the layer
1180
       * @param String url
1181
       *     Base url for the WMS (e.g.  http://wms.jpl.nasa.gov/wms.cgi)
1182
       * @param Object params
1183
       *     An object with key/value pairs representing the GetMap query string parameters and parameter values.
1184
       * @param Object projection
1185
       *    A OpenLayers.Projection object
1186
       */
1187
      var createWMSLayer= function(name, url, params, projection, proj4js_def, units, maxExtent, untiled){
1188

    
1189
        console.log("creating WMS Layer " + name);
1190

    
1191
        var wmsOptions = makeWMSLayerOptions(projection, proj4js_def, maxExtent, units, untiled);
1192

    
1193
        var wmsLayer = new OpenLayers.Layer.WMS(
1194
            name,
1195
            url,
1196
            params,
1197
            wmsOptions
1198
          );
1199

    
1200
          if(wmsLayer === null){
1201
            console.log("Error creating WMS Layer");
1202
          }
1203

    
1204
          return  wmsLayer;
1205
        };
1206

    
1207
      var onKmlFeatureSelect = function(event) {
1208
        var feature = event.feature;
1209
        // Since KML is user-generated, do naive protection against
1210
        // Javascript.
1211
        var content = "";
1212
        if(feature.attributes.name){
1213
            content += "<h3>" + feature.attributes.name + "</h3>";
1214
        }
1215
        if(feature.attributes.description) {
1216
            // ${specimen-base-url}
1217
            var description = feature.attributes.description;
1218
            description = description.replace('${occurrence-link-base-url}', opts.specimenPageBaseUrl);
1219
            //description = description.replace('${specimen-link-text}', opts.specimenLinkText); // no longer used
1220
            content += "<p>" + description + "</p>";
1221
        }
1222
        if (content.search("<script") != -1) {
1223
            content = "Content contained Javascript! Escaped content below.<br>" + content.replace(/</g, "&lt;");
1224
        }
1225
        if(content.length > 0){
1226
            popup = new OpenLayers.Popup.FramedCloud("balloon",
1227
                feature.geometry.getBounds().getCenterLonLat(),
1228
                new OpenLayers.Size(250, 150),
1229
                content,
1230
                null, true, onKmlPopupClose);
1231
                popup.autoSize = false;
1232
                // popup.imageSize = new OpenLayers.Size(1276, 736);
1233
                // popup.fixedRelativePosition = true;
1234
                // popup.maxSize = new OpenLayers.Size(50, 50);
1235
            feature.popup = popup;
1236
            map.addPopup(popup);
1237
        }
1238
      };
1239
      var onKmlFeatureUnselect =   function(event) {
1240
            var feature = event.feature;
1241
            if(feature.popup) {
1242
                map.removePopup(feature.popup);
1243
                feature.popup.destroy();
1244
                delete feature.popup;
1245
            }
1246
        };
1247
      var onKmlPopupClose = function(evt) {
1248
          kmlSelectControl.unselectAll();
1249
        };
1250

    
1251
    var layerLoadingControl = function() {
1252

    
1253
      var control = new OpenLayers.Control();
1254

    
1255
      OpenLayers.Util.extend(control, {
1256

    
1257
        LAYERS_LOADING: 0,
1258

    
1259
        updateState: function () {
1260
          if(this.div != null){
1261
            if (this.LAYERS_LOADING > 0) {
1262
              this.div.style.display = "block";
1263
            } else {
1264
              this.div.style.display = "none";
1265
            }
1266
          }
1267
        },
1268

    
1269
        updateSize: function () {
1270
          this.div.style.width = this.map.size.w + "px";
1271
          this.div.style.height = this.map.size.h  + "px";
1272
          this.div.style.textAlign = "center";
1273
          this.div.style.lineHeight = this.map.size.h  + "px";
1274
        },
1275

    
1276
        counterIncrease: function (layer) {
1277
          this.control.LAYERS_LOADING++;
1278
          log(' > loading start : ' + this.layer.name + ' ' + this.control.LAYERS_LOADING, true);
1279
          this.control.updateState();
1280
        },
1281

    
1282
        counterDecrease: function (layer) {
1283
          this.control.LAYERS_LOADING--;
1284
          log(' > loading end : ' + this.layer.name + ' ' + this.control.LAYERS_LOADING, true);
1285
          this.control.updateState();
1286
        },
1287

    
1288
        draw: function () {
1289

    
1290
          // call the default draw function to initialize this.div
1291
          OpenLayers.Control.prototype.draw.apply(this, arguments);
1292

    
1293
          this.map.events.register('updatesize', this, function(e){
1294
              this.updateSize();
1295
            }
1296
          );
1297

    
1298
          var loadingIcon = document.createElement("i");
1299
          var fa_class = document.createAttribute("class");
1300
          fa_class.value = "fa fa-refresh fa-spin fa-sync-alt fa-5x";
1301
          loadingIcon.attributes.setNamedItem(fa_class);
1302

    
1303
          this.updateSize();
1304

    
1305
          this.div.appendChild(loadingIcon);
1306

    
1307
          this.registerEvents();
1308

    
1309
          return this.div;
1310
        },
1311

    
1312
        registerEvents: function() {
1313

    
1314
          this.map.events.register('preaddlayer', this, function(e){
1315
            console.log(" > preaddlayer " + e.layer.name);
1316
            e.layer.events.register('loadstart', {control: this, layer: e.layer}, this.counterIncrease);
1317
            e.layer.events.register('loadend', {control: this, layer: e.layer}, this.counterDecrease);
1318
          });
1319
        }
1320

    
1321
      });
1322

    
1323
      return control;
1324
    }
1325

    
1326
    }; // end of CdmOpenLayers.Map
1327
})();
1328

    
1329

    
1330

    
1331

    
1332

    
1333

    
1334

    
1335

    
1336

    
(2-2/2)