Project

General

Profile

Download (38.6 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
    debug: true,
41
    /**
42
     * allows the map to display parts of the layers which are outside
43
     * the maxExtent if the aspect ratio of the map and of the baselayer
44
     * are not equal
45
     */
46
    displayOutsideMaxExtent: false,
47
    //  customWMSBaseLayerData: {
48
    //  name: "Euro+Med",
49
    //  url: "http://edit.africamuseum.be/geoserver/topp/wms",
50
    //  params: {layers: "topp:em_tiny_jan2003", format:"image/png", tiled: true},
51
    //  projection: "EPSG:7777777",
52
    //  maxExtent: "-1600072.75, -1800000, 5600000, 5850093",
53
    //  units: 'm'
54
    //  }
55
    customWMSBaseLayerData: {
56
        name: null,
57
        url: null,
58
        params: null,
59
        projection: null,
60
        proj4js_def: null,
61
        max_extent: null,
62
        units: null,
63
        untiled: null
64
    },
65
    wmsOverlayLayerData: {
66
      name: null,
67
      url: null,
68
      params: null,
69
      untiled: null
70
    },
71
    /**
72
     * when true the map is made resizable by adding the jQueryUI widget resizable
73
     * to the map container. This feature requires that the jQueryUI is loaded
74
     */
75
    resizable: false
76
  };
77
})(jQuery);
78

    
79
/**************************************************************************
80
 *                          CdmOpenLayers
81
 **************************************************************************/
82
(function() {
83

    
84
    /**
85
     * The CdmOpenLayers namespace definition
86
     */
87
    window.CdmOpenLayers  = (function () {
88

    
89
        // EPSG:3857 from http://spatialreference.org/ref/sr-org/6864/proj4/
90
        // OpenStreetMap etc
91
        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';
92

    
93
        var projections = {
94
                epsg_4326: new OpenLayers.Projection("EPSG:4326"),
95
                epsg_900913: new OpenLayers.Projection("EPSG:900913"),
96
                epsg_3857:  new OpenLayers.Projection("EPSG:3857")
97
        };
98
        var mapExtends = {
99
                epsg_4326: new OpenLayers.Bounds(-180, -90, 180, 90),
100
                //  Spherical Mercator epsg_900913 is not supporting the whole marble
101
                epsg_900913: new OpenLayers.Bounds(-179, -85, 179, 85),
102
                //  Spherical Mercator
103
                epsg_3857: new OpenLayers.Bounds(-179, -85, 179, 85)
104
        };
105
        // transform epsg_900913 to units meter
106
        mapExtends.epsg_900913.transform(projections.epsg_4326, projections.epsg_900913);
107
        mapExtends.epsg_3857.transform(projections.epsg_4326, projections.epsg_3857);
108

    
109
        // make public by returning an object
110
        return {
111
            projections: projections,
112
            mapExtends: mapExtends,
113
            getMap: function (){},
114
            getLayerByName: function(layerName){} // initially empty function, will be populated by openlayers_layers.js
115
        };
116

    
117
    })(); // end of namespace definition for CdmOpenLayers
118

    
119
    /**
120
     * The CdmOpenLayers.Map constructor
121
     * @param mapElement
122
     * @param mapserverBaseUrl
123
     * @param mapserverVersion
124
     * @param opts
125
     * @returns
126
     */
127
    window.CdmOpenLayers.Map = function(mapElement, mapserverBaseUrl, mapserverVersion, opts){
128

    
129
      var mapServicePath = '/edit_wp5';
130

    
131
      // firebug console stub (avoids errors if firebug is not active)
132
      if(typeof console === "undefined") {
133
          console = { log: function() { } };
134
      }
135

    
136
      // sanitize given options
137
      try {
138
          opts.customWMSBaseLayerData.max_extent = OpenLayers.Bounds.fromString(opts.customWMSBaseLayerData.max_extent);
139
      } catch(e){
140
          opts.customWMSBaseLayerData.max_extent = null;
141
      }
142

    
143

    
144
      var legendImgSrc = null;
145

    
146
      var map = null;
147

    
148
      var infoElement = null;
149

    
150
      var baseLayers = [];
151

    
152
      var defaultBaseLayer = null;
153

    
154
      /**
155
       * The top most layer which will be places above all data layers
156
       *
157
       * @type {null}
158
       */
159
      var wmsOverlay = null;
160

    
161
      /**
162
       * Default bounding box for map viewport in the projection of the base layer.
163
       * as defined by the user, can be null.
164
       *
165
       * These are bounds in the epsg_4326 projection, and will be transformed to the baselayer projection.
166
       *
167
       * @type string
168
       */
169
      var defaultBaseLayerBoundingBox = "-180,-90,180,90";
170

    
171
      /**
172
       * bounding box for map viewport as defined by the user, can be null.
173
       *
174
       * These are bounds in the projection of the base layer.
175
       *
176
       * @type string
177
       */
178
      var boundingBox = null;
179

    
180
      /**
181
       * Bounds for the view port calculated from the data layer responses.
182
       * These are either calculated by the minimum bounding box which
183
       * encloses the data in the data layers, or it is equal to the
184
       * boundingBox as defined by the user.
185
       *
186
       * These are bounds in the projection of the base layer.
187
       *
188
       * @see boundingBox
189
       *
190
       * @type OpenLayers.Bounds
191
       */
192
      var dataBounds = null;
193

    
194
      /**
195
       * Final value for the view port, calculated from the other bounds.
196
       *
197
       * These are bounds in the projection of the base layer.
198
       *
199
       * @type OpenLayers.Bounds
200
       */
201
      var zoomToBounds = null;
202

    
203
      var zoomToClosestLevel = true;
204

    
205
      var LAYER_DATA_CNT = 0;
206

    
207
      /* this is usually the <div id="openlayers"> element */
208
      var mapContainerElement = mapElement.parent();
209

    
210
      var defaultControls = [
211
         new OpenLayers.Control.PanZoom(),
212
         new OpenLayers.Control.Navigation(
213
           {
214
             zoomWheelEnabled: false,
215
             handleRightClicks:true,
216
             zoomBoxKeyMask: OpenLayers.Handler.MOD_CTRL
217
           }
218
         )
219
      ];
220

    
221

    
222
      var layerByNameMap = {
223
              tdwg1: 'topp:tdwg_level_1',
224
              tdwg2: 'topp:tdwg_level_2',
225
              tdwg3: 'topp:tdwg_level_3',
226
              tdwg4: 'topp:tdwg_level_4'
227
      };
228

    
229
      if(opts.resizable === true) {
230
        // resizable requires jQueryUI to  be loaded!!!
231
        mapContainerElement.resizable({
232
          resize: function( event, ui ) {
233
            map.updateSize();
234
            //   this.printInfo();
235
          }
236
        });
237
      }
238

    
239
        /**
240
         *
241
         */
242
        this.create = function(){ // public function
243

    
244
          // set the height of the container element
245
          adjustHeight();
246

    
247
          // register for resize events to be able to adjust the map aspect ratio and legend position
248
          jQuery( window ).resize(function() {
249
            adjustHeight();
250
            adjustLegendAsElementPosition();
251
          });
252

    
253
          createBaseLayers(opts.baseLayerNames, opts.defaultBaseLayerName, opts.customWMSBaseLayerData);
254

    
255
          initMap();
256

    
257
          // now it is
258
          if(opts.boundingBox){
259
            boundingBox = OpenLayers.Bounds.fromString(opts.boundingBox);
260
            boundingBox.transform(CdmOpenLayers.projections.epsg_4326, map.getProjectionObject());
261
          }
262

    
263
          // -- Distribution Layer --
264
          var mapServiceRequest;
265
          var distributionQuery = mapElement.attr('distributionQuery');
266

    
267
          if(distributionQuery !== undefined){
268
            distributionQuery = mergeQueryStrings(distributionQuery, '&recalculate=false');
269
            if(typeof legendPosition === 'number'){
270
              distributionQuery = mergeQueryStrings(distributionQuery, 'legend=1&mlp=' + opts.legendPosition);
271
            }
272
            if(opts.boundingBox){
273
              distributionQuery = mergeQueryStrings(distributionQuery, 'bbox=' + boundingBox);
274
            }
275

    
276
            distributionQuery = mergeQueryStrings(distributionQuery, 'callback=?');
277
            var legendFormatQuery = mapElement.attr('legendFormatQuery');
278
            if(legendFormatQuery !== undefined){
279
              legendImgSrc = mergeQueryStrings('/GetLegendGraphic?SERVICE=WMS&VERSION=1.1.1', legendFormatQuery);
280
            }
281

    
282
            mapServiceRequest = mapserverBaseUrl + mapServicePath + '/' + mapserverVersion + '/rest_gen.php?' + distributionQuery;
283

    
284
            LAYER_DATA_CNT++;
285
            jQuery.ajax({
286
              url: mapServiceRequest,
287
              dataType: "jsonp",
288
              success: function(data){
289
                  var layers = createDataLayer(data, "AREA");
290
                  addLayers(layers);
291
                  layerDataLoaded();
292
              }
293
            });
294
          }
295

    
296
          // -- Occurrence Layer --
297
          var occurrenceQuery = mapElement.attr('occurrenceQuery');
298
          if(occurrenceQuery !== undefined){
299
            occurrenceQuery = mergeQueryStrings(occurrenceQuery, '&recalculate=false');
300
//              if(typeof legendPosition == 'number'){
301
//              occurrenceQuery = mergeQueryStrings(distributionQuery, 'legend=1&mlp=' + opts.legendPosition);
302
//              }
303

    
304

    
305
            occurrenceQuery = mergeQueryStrings(occurrenceQuery, 'callback=?');
306
//              var legendFormatQuery = mapElement.attr('legendFormatQuery');
307
//              if(legendFormatQuery !== undefined){
308
//              legendImgSrc = mergeQueryStrings('/GetLegendGraphic?SERVICE=WMS&VERSION=1.1.1', legendFormatQuery);
309
//              }
310
            if(opts.boundingBox){
311
              occurrenceQuery = mergeQueryStrings(occurrenceQuery, 'bbox=' + boundingBox);
312
            }
313

    
314
            mapServiceRequest = mapserverBaseUrl + mapServicePath + '/' + mapserverVersion + '/rest_gen.php?' + occurrenceQuery;
315

    
316
            LAYER_DATA_CNT++;
317
            jQuery.ajax({
318
              url: mapServiceRequest,
319
              dataType: "jsonp",
320
              success: function(data){
321
                  var layers = createDataLayer(data, "POINT");
322
                  addLayers(layers);
323
                  layerDataLoaded();
324
              }
325
            });
326
          }
327

    
328
          if(LAYER_DATA_CNT === 0) {
329
            // a map only with base layer
330
            initPostDataLoaded();
331
          }
332

    
333
          // -- Overlay Layer --
334
          if(opts.wmsOverlayLayerData.params){
335
            overlay_layer_params = opts.wmsOverlayLayerData.params;
336
            overlay_layer_params.transparent=true;
337
            wmsOverlay = createWMSLayer(
338
              opts.wmsOverlayLayerData.name,
339
              opts.wmsOverlayLayerData.url,
340
              overlay_layer_params,
341
              null,
342
              null,
343
              null,
344
              null,
345
              opts.wmsOverlayLayerData.untiled
346
            );
347

    
348
            if(map.addLayer(wmsOverlay)){
349
              wmsOverlay.setVisibility(true);
350
              map.setLayerIndex(wmsOverlay, 100);
351
              log("Overlay wms added");
352
            } else {
353
              log("ERROR adding overlay wms layer")
354
            }
355
          }
356

    
357
          log("Map viewer creation complete.");
358

    
359
        };
360

    
361
        var layerDataLoaded = function() {
362
          LAYER_DATA_CNT--;
363
          if(LAYER_DATA_CNT === 0){
364
            initPostDataLoaded();
365
          }
366
        };
367

    
368
        var initPostDataLoaded = function () {
369
          // all layers prepared, make the visible
370
          map.layers.forEach(function(layer){
371
            layer.setVisibility(true);
372
          });
373

    
374
          // zoom to the zoomToBounds
375
          log(" > starting zoomToExtend: " + zoomToBounds + ", zoomToClosestLevel: " + zoomToClosestLevel, true);
376
          map.zoomToExtent(zoomToBounds, zoomToClosestLevel);
377

    
378

    
379
          if(map.getZoom() > opts.maxZoom){
380
            map.zoomTo(opts.maxZoom);
381
          } else if(map.getZoom() < opts.minZoom){
382
            map.zoomTo(opts.minZoom);
383
          }
384

    
385
          // make sure the wmsOverlay is still on top
386
          if(wmsOverlay){
387
            map.setLayerIndex(wmsOverlay, 100);
388
          }
389

    
390
          log(" > zoomToExtend done", true);
391
        };
392

    
393
      /**
394
       * Returns  the projection of the defaultBaseLayer which is the
395
       * the projection to which all other layers and locations must be transformed.
396
       */
397
      var referenceProjection = function() {
398
        if(defaultBaseLayer){
399
          if(defaultBaseLayer.projection){
400
            return defaultBaseLayer.projection;
401
          } else if(defaultBaseLayer.sphericalMercator === true){
402
            return CdmOpenLayers.projections.epsg_900913;
403
          } else {
404
            log("Error - referenceProjection() defaultBaseLayer " + defaultBaseLayer.name + " misses projection information");
405
          }
406

    
407
        } else {
408
          log("Error - referenceProjection() defaultBaseLayer not set");
409
          return null;
410
        }
411
      };
412

    
413
      /**
414
       * Returns the maxExtent of the defaultBaseLayer.
415
       */
416
      var referenceMaxExtent = function() {
417
        if(defaultBaseLayer){
418
          return defaultBaseLayer.maxExtent;
419
        } else {
420
          log("Error - referenceMaxExtent() defaultBaseLayer not set");
421
          return null;
422
        }
423
      };
424

    
425
        var getHeight = function(){
426
          return mapContainerElement.width() / opts.aspectRatio;
427
        };
428

    
429
        var getWidth = function(){
430
          return mapContainerElement.width();
431
        };
432

    
433
        var adjustHeight = function() {
434
          mapContainerElement.css("height", getHeight());
435
        };
436

    
437
        /**
438
         * public function
439
         */
440
        this.registerEvents = function(events){
441
            for (var key in events) {
442
                if (events.hasOwnProperty(key)) {
443
                    map.events.register(key, map , events[key]);
444
                }
445
            }
446
        };
447

    
448

    
449
        /**
450
         * public function
451
         */
452
        this.getMap = function(){
453
            return map;
454
        };
455

    
456
        /**
457
         * Prints info on the current map into the jQuery element
458
         * as set in the options (opts.infoElement)
459
         * public function
460
         *
461
         */
462
        this.printInfo = function(){
463

    
464

    
465
            var mapExtendDegree = null;
466
            if(map.getExtent() != null){
467
              // If the baselayer is not yet set, getExtent() returns null.
468
              mapExtendDegree = map.getExtent().clone();
469
              mapExtendDegree.transform(map.baseLayer.projection, CdmOpenLayers.projections.epsg_4326);
470
            }
471

    
472
            var info = "<dl>";
473
            info += "<dt>zoom:<dt><dd>" + map.getZoom() + "</dd>";
474
            if(opts.debug){
475
                info += "<dt>map resolution:<dt><dd>" + map.getResolution() + "</dd>";
476
                info += "<dt>map max resolution:<dt><dd>" + map.getMaxResolution() + "</dd>";
477
                info += "<dt>map scale:<dt><dd>" + map.getScale() + "</dd>";
478
                info += "<dt>map width, height:<dt><dd>" + mapContainerElement.width() +  ", " + mapContainerElement.height() + "</dd>";
479
                info += "<dt>map aspect ratio:<dt><dd>" + mapContainerElement.width() / mapContainerElement.height() + "</dd>";
480
                if(map.getExtent() != null){
481
                  info += "<dt>map extent bbox:<dt><dd class=\"map-extent-bbox\">" + map.getExtent().toBBOX() + ", <strong>degree:</strong> <span class=\"degree-value\">" + mapExtendDegree.toBBOX() + "</span></dd>";
482
                  info += "<dt>map maxExtent bbox:<dt><dd>" + map.getMaxExtent().toBBOX() + "</dd>";
483
                  info += "<dt>baselayer extent bbox:<dt><dd class=\"baselayer-extent-bbox\">" +  map.baseLayer.getExtent().toBBOX() + ", <strong>degree:</strong> <span class=\"degree-value\">"
484
                    + map.baseLayer.getExtent().clone().transform(map.baseLayer.projection, CdmOpenLayers.projections.epsg_4326) + "</span></dd>"
485
                  info += "<dt>baselayer projection:<dt><dd>" + map.baseLayer.projection.getCode() + "</dd>";
486
                }
487
            } else {
488
                info += "<dt>bbox:<dt><dd>" + (mapExtendDegree !== null ? mapExtendDegree.toBBOX() : 'NULL') + "</dd>";
489
            }
490
            info += "</dl>";
491

    
492
            if(infoElement === null){
493
                infoElement = jQuery('<div class="map_info"></div>');
494
                mapElement.parent().after(infoElement);
495
            }
496
            infoElement.html(info);
497
        };
498

    
499
        /**
500
         * Initialize the Openlayers Map with the base layer
501
         */
502
        var initMap = function(){
503

    
504
          if(opts.showLayerSwitcher === true){
505
              defaultControls.push(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
506
          }
507

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

    
510
//          var maxExtentByAspectRatio = cropBoundsToAspectRatio(defaultBaseLayer.maxExtent, getWidth/getHeight);
511
          var maxResolution = null;
512
          // gmaps has no maxExtent at this point, need to check for null
513
          if(referenceMaxExtent() !== null){
514
              maxResolution = Math[(opts.displayOutsideMaxExtent ? 'max' : 'min')](
515
                referenceMaxExtent().getWidth() / getWidth(),
516
                referenceMaxExtent().getHeight() / getHeight()
517
              );
518
          }
519
          console.log("mapOptions.maxResolution: " + maxResolution);
520
          console.log("mapOptions.restrictedExtent: " + referenceMaxExtent());
521

    
522
          map = new OpenLayers.Map(
523
            mapElement.attr('id'),
524
            {
525
              // defines the map ui elements and interaction features
526
              controls: defaultControls,
527

    
528
              // maxResolution determines the lowest zoom level and thus places the map
529
              // in its maximum extent into the available view port so that no additinal
530
              // gutter is visible and no parts of the map are hidden
531
              // see http://trac.osgeo.org/openlayers/wiki/SettingZoomLevels
532
              // IMPORTANT!!!
533
              // the maxResulution set here will be overwritten if the baselayers maxResolution
534
              // it is set
535
              maxResolution: maxResolution,
536

    
537
              // setting restrictedExtent the the maxExtent prevents from panning the
538
              // map out of its bounds
539
              restrictedExtent: referenceMaxExtent(),
540
//                      maxExtent: referenceMaxExtent(),
541

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

    
549
              eventListeners: opts.eventListeners,
550
              // creating the map with a null theme, since we include the stylesheet directly in the page
551
              theme: null
552

    
553
            }
554
          );
555

    
556
          //add the base layers
557

    
558
          addLayers(baseLayers);
559
          map.setBaseLayer(defaultBaseLayer);
560

    
561
          // calculate the bounds to zoom to
562
          zoomToBounds = calculateZoomToBounds(opts.boundingBox ? opts.boundingBox : defaultBaseLayerBoundingBox);
563
          // zoomToBounds = cropBoundsToAspectRatio(zoomToBounds, map.getSize().w / map.getSize().h);
564
          console.log("baselayer zoomToBounds: " + zoomToBounds);
565

    
566
        };
567

    
568
        var addLayers = function(layers){
569

    
570
          layers.forEach(function(layer){
571
            // layer.setVisibility(false);
572
          });
573

    
574
          map.addLayers(layers);
575
        };
576

    
577
        /**
578
         * add a distribution or occurrence layer
579
         *
580
         * @param mapResponseObj
581
         *   The reponse object returned by the edit map service
582
         * @param dataType
583
         *   either "AREA" or "POINT"
584
         */
585
        var createDataLayer = function(mapResponseObj, dataType){
586

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

    
589
          dataLayerOptions = makeWMSLayerOptions();
590
          dataLayerOptions.displayOutsideMaxExtent = true; // move into makeWMSLayerOptions?
591

    
592
          var layers = [];
593
          // add additional layers, get them from the mapResponseObj
594
          if(mapResponseObj !== undefined){
595
            if(dataType === "POINT" && mapResponseObj.points_sld !== undefined){
596
              var pointLayer;
597
              // it is a response for an point map
598
              var geoserverUri;
599
              if(mapResponseObj.geoserver) {
600
                  geoserverUri = mapResponseObj.geoserver;
601
              } else {
602
                  // it is an old service which is not providing the corresponding geoserver URI, so we guess it
603
                  geoserverUri = mapserverBaseUrl + "/geoserver/wms";
604
              }
605

    
606
              //TODO points_sld should be renamed to sld in response + fill path to sld should be given
607
              pointLayer = new OpenLayers.Layer.WMS(
608
                'points',
609
                geoserverUri,
610
                {
611
                    layers: 'topp:rest_points',
612
                    transparent:"true",
613
                    format:"image/png"
614
                },
615
                dataLayerOptions
616
              );
617

    
618
              var sld = mapResponseObj.points_sld;
619
              if(sld.indexOf("http://") !== 0){
620
                  // it is an old servive which is not providing the full sdl URI, so we guess it
621
                  //  http://edit.africamuseum.be/synthesys/www/v1/sld/
622
                  //  http://edit.br.fgov.be/synthesys/www/v1/sld/
623
                  sld =  mapserverBaseUrl + "/synthesys/www/v1/sld/" + sld;
624
              }
625
              pointLayer.params.SLD = sld;
626

    
627
              layers.push(pointLayer);
628
            } else {
629
              // it is a response from for a distribution map
630
              console.log("createDataLayer() : start with adding distribution layers :");
631
              for ( var i in mapResponseObj.layers) {
632
                var layerData = mapResponseObj.layers[i];
633

    
634
                console.log(" " + i +" -> " + layerData.tdwg);
635
                var layer = new OpenLayers.Layer.WMS(
636
                  layerData.tdwg,
637
                  mapResponseObj.geoserver + "/wms",
638
                  {
639
                      layers: layerByNameMap[layerData.tdwg],
640
                      transparent:"true",
641
                      format:"image/png"
642
                  },
643
                  dataLayerOptions
644
                  );
645
                layer.params.SLD = layerData.sld;
646
                layer.setOpacity(opts.distributionOpacity);
647

    
648
                layers.push(layer);
649
              }
650
            }
651

    
652
            if(layers.length > 0) {
653
              // calculate zoomBounds using the first layer
654
              if(mapResponseObj.bbox !== undefined){
655
                // mapResponseObj.bbox are bounds  are always returned in EPSG:4326 since the point service does not know about the projection
656
                var newBounds =  OpenLayers.Bounds.fromString( mapResponseObj.bbox );
657
                if(dataType === "POINT"){
658
                  console.log("createDataLayer() : transforming newBounds: " + newBounds + " to referenceProjection()=" + referenceProjection() + "(map.getProjectionObject()=" + map.getProjectionObject() +")" );
659
                  // newBounds.transform(layers[0].projection, map.getProjectionObject());
660
                  newBounds.transform(CdmOpenLayers.projections.epsg_4326, referenceProjection());
661
                } else {
662
                  // Type == AREA
663
                  console.log("createDataLayer() : no need to transform the newBounds: " + newBounds + " to referenceProjection()=" + referenceProjection());
664
                  // expecting that the bounds are already in the correct projection.
665
                }
666

    
667
                if(dataBounds !== null){
668
                  dataBounds.extend(newBounds);
669
                } else if(newBounds !== undefined){
670
                  dataBounds = newBounds;
671
                }
672

    
673
                zoomToBounds = dataBounds;
674
                console.log("createDataLayer() : data layer zoomToBounds: " + zoomToBounds);
675
                zoomToClosestLevel = false;
676
              }
677
            }
678

    
679

    
680

    
681
            if(legendImgSrc != null && opts.legendPosition !== undefined && mapResponseObj.legend !== undefined){
682
                var legendSrcUrl = mapResponseObj.geoserver + legendImgSrc + mapResponseObj.legend;
683
                addLegendAsElement(legendSrcUrl);
684
                //addLegendAsLayer(legendSrcUrl, map);
685
            }
686

    
687
            return layers;
688
          }
689

    
690
        };
691

    
692
        /**
693
         *
694
         */
695
        var addLegendAsElement= function(legendSrcUrl){
696

    
697
            var legendElement = jQuery('<div class="openlayers_legend"></div>');
698
            var legendImage = jQuery('<img src="' + legendSrcUrl + '"/>');
699
            legendElement
700
                .css('opacity', opts.legendOpacity)
701
                .css('position', 'relative')
702
                .css('z-index', '1002')
703
                .css('top', -mapElement.height());
704
            legendImage.load(function () {
705
                jQuery(this).parent()
706
                    .css('left', getWidth() - jQuery(this).width())
707
                    .width(jQuery(this).width());
708
                // reset height to original value
709
                adjustHeight();
710
            });
711
            legendElement.html(legendImage);
712
            mapElement.after(legendElement);
713
        };
714

    
715
         var adjustLegendAsElementPosition = function (){
716
           var legendContainer = mapContainerElement.children('.openlayers_legend');
717
           var legendImage = legendContainer.children('img');
718
           legendContainer.css('top', -mapElement.height())
719
             .css('left', getWidth() - legendImage.width());
720
         };
721

    
722

    
723
        var addLegendAsLayer= function(legendSrcUrl, map){
724
            var w, h;
725

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

    
730
                w = mapElement.next('.openlayers_legend').find('img').width();
731
                h = mapElement.next('.openlayers_legend').find('img').height();
732
                mapElement.next('.openlayers_legend').remove();
733

    
734
//              createLegendLayer();
735
//              // 2. create the Legend Layer
736
                //TODO createLegendLayer as inner function seems like an error
737
//              var createLegendLayer = function(){
738
                //
739
                //
740
//              var legendLayerOptions={
741
//              maxResolution: '.$maxRes.',
742
//              maxExtent: new OpenLayers.Bounds(0, 0, w, h)
743
//              };
744
                //
745
//              var legendLayer = new OpenLayers.Layer.Image(
746
//              'Legend',
747
//              legendSrcUrl,
748
//              new OpenLayers.Bounds(0, 0, w, h),
749
//              new OpenLayers.Size(w, h),
750
//              imageLayerOptions);
751
//              };
752
            });
753

    
754

    
755
        };
756

    
757
        /**
758
         * merge 2 Url query strings
759
         */
760
        var mergeQueryStrings = function(queryStr1, queryStr2){
761
            if(queryStr1.charAt(queryStr1.length - 1) != '&'){
762
                queryStr1 += '&';
763
            }
764
            if(queryStr2.charAt(0) == '&'){
765
                return queryStr1 + queryStr2.substr(1);
766
            } else {
767
                return queryStr1 + queryStr2;
768
            }
769

    
770
        };
771

    
772
        /**
773
         *
774
         */
775
        var createBaseLayers = function( baseLayerNames, defaultBaseLayerName, customWMSBaseLayerData){
776

    
777
            for(var i = 0; i <  baseLayerNames.length; i++) {
778
                // create the layer
779
                if (baseLayerNames[i] === "custom_wms_base_layer_1"){
780
                    wmsBaseLayer =createWMSLayer(
781
                            customWMSBaseLayerData.name,
782
                            customWMSBaseLayerData.url,
783
                            customWMSBaseLayerData.params,
784
                            customWMSBaseLayerData.projection,
785
                            customWMSBaseLayerData.proj4js_def,
786
                            customWMSBaseLayerData.units,
787
                            customWMSBaseLayerData.max_extent,
788
                            customWMSBaseLayerData.untiled
789
                    );
790
                  wmsBaseLayer.setIsBaseLayer(true);
791
                  baseLayers[i] = wmsBaseLayer;
792
                } else {
793
                    baseLayers[i] = window.CdmOpenLayers.getLayerByName(baseLayerNames[i]);
794
                }
795
                // set default baselayer
796
                if(baseLayerNames[i] === defaultBaseLayerName){
797
                    defaultBaseLayer = baseLayers[i];
798
                }
799

    
800
            }
801
        };
802

    
803
        /**
804
         * returns the intersection of the bounds b1 and b2.
805
         * The b1 and b2 do not intersect b1 will be returned.
806
         *
807
         * @param OpenLayers.Bounds b1
808
         * @param OpenLayers.Bounds b2
809
         *
810
         * @return the bounds of the intersection between both rectangles
811
         */
812
        var intersectionOfBounds = function (b1, b2){
813

    
814
            if(b1.intersectsBounds(b2)){
815

    
816
                var left = Math.max(b1.left, b2.left);
817
                var bottom = Math.max(b1.bottom, b2.bottom);
818
                var right = Math.min(b1.right, b2.right);
819
                var top = Math.min(b1.top, b2.top);
820

    
821
                return new OpenLayers.Bounds(left, bottom, right, top);
822

    
823
            } else {
824
                return b1;
825
            }
826
        };
827

    
828
        /**
829
         *
830
         * @param b OpenLayers.Bounds to crop
831
         * @param aspectRatio as fraction of width/height as float value
832
         *
833
         * @return the bounds cropped to the given aspectRatio
834
         */
835
        var cropBoundsToAspectRatio = function (b, aspectRatio){
836

    
837
            var cropedB = b.clone();
838

    
839
            if(aspectRatio === 1){
840
                return cropedB;
841
            }
842

    
843
            /*
844
             * LonLat:
845
             *   lon {Float} The x-axis coordinate in map units
846
             *   lat {Float} The y-axis coordinate in map units
847
             */
848
            var center = cropedB.getCenterLonLat();
849
            var dist;
850
            if(aspectRatio < 1){
851
                dist = (b.getHeight() / 2) * aspectRatio;
852
                cropedB.top = center.lat + dist;
853
                cropedB.cropedBottom = center.lat - dist;
854
            } else if(aspectRatio > 1){
855
                dist = (b.getWidth() / 2) / aspectRatio;
856
                cropedB.left = center.lon - dist;
857
                cropedB.right = center.lon + dist;
858
            }
859
            return cropedB;
860
        };
861

    
862
        /**
863
         * returns the version number contained in the version string:
864
         *   v1.1 --> 1.1
865
         *   v1.2_dev --> 1.2
866
         */
867
        var mapServerVersionNumber = function() {
868
            var pattern = /v([\d\.]+).*$/;
869
            var result;
870
            if (result = mapserverVersion.match(pattern) !== null) {
871
                return result[0];
872
            } else {
873
                return null;
874
            }
875
        };
876

    
877

    
878

    
879
      /**
880
       * returns the zoom to bounds.
881
       *
882
       * @param bboxString
883
       *     a string representation of the bounds in degree for epsg_4326
884
       *
885
       * @return the bboxstring projected onto the layer and intersected with the maximum extent of the layer
886
       */
887
      var calculateZoomToBounds = function(bboxString){
888
        var zoomToBounds;
889
        if(bboxString) {
890
          zoomToBounds = OpenLayers.Bounds.fromString(bboxString);
891
          if(referenceProjection().proj.projName){
892
            // SpericalMercator is not supporting the full extent -180,-90,180,90
893
            // crop if need to -179, -85, 179, 85
894
            if(zoomToBounds.left < -179){
895
              zoomToBounds.left =  -179;
896
            }
897
            if(zoomToBounds.bottom < -85){
898
              zoomToBounds.bottom =  -85;
899
            }
900
            if(zoomToBounds.right > 179){
901
              zoomToBounds.right =  179;
902
            }
903
            if(zoomToBounds.top > 85){
904
              zoomToBounds.top = 85;
905
            }
906
          }
907
          // transform bounding box given in degree values to the projection of the base layer
908
          zoomToBounds.transform(CdmOpenLayers.projections.epsg_4326, referenceProjection());
909
        } else if(referenceMaxExtent()) {
910
          zoomToBounds = referenceMaxExtent();
911
          // no need to transform since the bounds are obtained from the layer
912
        } else {
913
          // use the more narrow bbox of the SphericalMercator to avoid reprojection problems
914
          // SpericalMercator is not supporting the full extent!
915
          zoomToBounds = CdmOpenLayers.mapExtends.epsg_900913;
916
          // transform bounding box given in degree values to the projection of the base layer
917
          zoomToBounds.transform(CdmOpenLayers.projections.epsg_4326, referenceProjection());
918
        }
919

    
920
        zoomToBounds = intersectionOfBounds(referenceMaxExtent(), zoomToBounds);
921

    
922
        log("zoomBounds calculated: " + zoomToBounds.toString());
923

    
924
        return zoomToBounds;
925
      };
926

    
927
      var log = function(message, addTimeStamp){
928
        var timestamp = '';
929
        if(addTimeStamp === true){
930
          var time = new Date();
931
          timestamp = time.getSeconds() + '.' + time.getMilliseconds() + 's';
932
        }
933
        console.log(timestamp + message);
934
      };
935

    
936
      var makeWMSLayerOptions = function(projection, proj4js_def, maxExtent, units, untiled) {
937
        var wmsOptions = {
938
          isBaseLayer: false,
939
          displayInLayerSwitcher: true
940
        };
941

    
942
        if (projection) {
943
          if (proj4js_def) {
944
            // in case projection has been defined for the layer and if there is also
945
            // a Proj4js.defs, add it!
946
            Proj4js.defs[projection] = proj4js_def;
947
          }
948
          wmsOptions.projection = projection;
949
          if (maxExtent === null) {
950
            maxExtent = CdmOpenLayers.mapExtends.epsg_4326.clone();
951
            maxExtent.transform(CdmOpenLayers.projections.epsg_4326, projection);
952
          }
953
        } else {
954
          // use the projection and maxextent of the base layer
955
          maxExtent = referenceMaxExtent();
956
        }
957

    
958
        if (maxExtent) {
959
          wmsOptions.maxExtent = maxExtent;
960
        }
961

    
962
        if (units) {
963
          wmsOptions.units = units;
964
        }
965

    
966
        if (untiled) {
967
          wmsOptions.singleTile = true;
968
          wmsOptions.ratio = 1;
969
        }
970

    
971
        return wmsOptions;
972
      };
973

    
974
      /**
975
       * Creates a WMS Base layer
976
       * @param String name
977
       *     A name for the layer
978
       * @param String url
979
       *     Base url for the WMS (e.g.  http://wms.jpl.nasa.gov/wms.cgi)
980
       * @param Object params
981
       *     An object with key/value pairs representing the GetMap query string parameters and parameter values.
982
       * @param Object projection
983
       *    A OpenLayers.Projection object
984
       */
985
      var createWMSLayer= function(name, url, params, projection, proj4js_def, units, maxExtent, untiled){
986

    
987
        console.log("creating WMS Layer " + name);
988

    
989
        var wmsOptions = makeWMSLayerOptions(projection, proj4js_def, maxExtent, units, untiled);
990

    
991
        var wmsLayer = new OpenLayers.Layer.WMS(
992
            name,
993
            url,
994
            params,
995
            wmsOptions
996
          );
997

    
998
          if(wmsLayer === null){
999
            console.log("Error creating WMS Layer");
1000
          }
1001

    
1002
          return  wmsLayer;
1003
        };
1004

    
1005
        var layerLoadingControl = function() {
1006

    
1007
          var control = new OpenLayers.Control();
1008

    
1009
          OpenLayers.Util.extend(control, {
1010

    
1011
            LAYERS_LOADING: 0,
1012

    
1013
            updateState: function () {
1014
              if(this.div != null){
1015
                if (this.LAYERS_LOADING > 0) {
1016
                  this.div.style.display = "block";
1017
                } else {
1018
                  this.div.style.display = "none";
1019
                }
1020
              }
1021
            },
1022

    
1023
            updateSize: function () {
1024
              this.div.style.width = this.map.size.w + "px";
1025
              this.div.style.height = this.map.size.h  + "px";
1026
              this.div.style.textAlign = "center";
1027
              this.div.style.lineHeight = this.map.size.h  + "px";
1028
            },
1029

    
1030
            counterIncrease: function (layer) {
1031
              this.control.LAYERS_LOADING++;
1032
              log(' > loading start : ' + this.layer.name + ' ' + this.control.LAYERS_LOADING, true);
1033
              this.control.updateState();
1034
            },
1035

    
1036
            counterDecrease: function (layer) {
1037
              this.control.LAYERS_LOADING--;
1038
              log(' > loading end : ' + this.layer.name + ' ' + this.control.LAYERS_LOADING, true);
1039
              this.control.updateState();
1040
            },
1041

    
1042
            draw: function () {
1043

    
1044
              // call the default draw function to initialize this.div
1045
              OpenLayers.Control.prototype.draw.apply(this, arguments);
1046

    
1047
              this.map.events.register('updatesize', this, function(e){
1048
                  this.updateSize();
1049
                }
1050
              );
1051

    
1052
              var loadingIcon = document.createElement("i");
1053
              var fa_class = document.createAttribute("class");
1054
              // fa-circle-o-notch fa-spin
1055
              // fa-spinner fa-pulse
1056
              // fa-refresh
1057
              fa_class.value = "fa fa-refresh fa-spin fa-5x";
1058
              loadingIcon.attributes.setNamedItem(fa_class);
1059

    
1060
              this.updateSize();
1061

    
1062
              this.div.appendChild(loadingIcon);
1063

    
1064
              this.registerEvents();
1065

    
1066
              return this.div;
1067
            },
1068

    
1069
            registerEvents: function() {
1070

    
1071
              this.map.events.register('preaddlayer', this, function(e){
1072
                console.log(" > preaddlayer " + e.layer.name);
1073
                e.layer.events.register('loadstart', {control: this, layer: e.layer}, this.counterIncrease);
1074
                e.layer.events.register('loadend', {control: this, layer: e.layer}, this.counterDecrease);
1075
              });
1076
            }
1077

    
1078
          });
1079

    
1080
          return control;
1081
        }
1082

    
1083
    }; // end of CdmOpenLayers.Map
1084
})();
1085

    
1086

    
1087

    
1088

    
1089

    
1090

    
1091

    
1092

    
1093

    
(2-2/2)