Project

General

Profile

1
/*
2
Author:       Cameron Shorter cameronAtshorter.net
3
License:      LGPL as per: http://www.gnu.org/copyleft/lesser.html
4

    
5
$Id: MapPaneOL.js 3870 2008-02-26 12:55:14Z ahocevar $
6
*/
7

    
8
// Ensure this object's dependancies are loaded.
9
loadCss("openlayers/style.css");
10
mapbuilder.loadScript(baseDir+"/util/openlayers/OpenLayers.js");
11
mapbuilder.loadScript(baseDir+"/util/Util.js");
12
mapbuilder.loadScript(baseDir+"/widget/WidgetBase.js");
13
mapbuilder.loadScript(baseDir+"/tool/Extent.js");
14
/**
15
 * Widget to render a map from an OGC context document.  The layers are
16
 * rendered using http://openlayers.org .
17
 * @constructor
18
 * @base WidgetBase
19
 * @param widgetNode  The widget's XML object node from the configuration document.
20
 * @param model       The model object that this widget belongs to.
21
 */
22
function MapPaneOL(widgetNode, model) {
23
  WidgetBase.apply(this,new Array(widgetNode, model));
24

    
25
  OpenLayers.ImgPath = config.skinDir + '/images/openlayers/';
26
  OpenLayers.ProxyHost = config.proxyUrl+"/?url=";
27
  
28

    
29
  // replacement for deprecated MapContainerBase
30
  this.containerNodeId = this.htmlTagId;
31
  model.containerModel = this.model;
32

    
33
  //Make sure the Extent is attached to the context and initialized
34
  if(!this.model.extent){
35
    this.model.extent = new Extent (this.model);
36
    this.model.addFirstListener( "loadModel", this.model.extent.firstInit, this.model.extent );
37
  }
38

    
39
  /**
40
   * For tiled wms layers: Overlap of map tiles in pixels. Useful for
41
   * preventing rendering artefacts at tile edges. Recommended values:
42
   * 0-15, default is 0 (no gutter at all).
43
   */
44
  this.tileGutter = this.getProperty("mb:tileGutter", 0);
45
  
46
  /**
47
   * For tiled wms layers: how many rows of tiles should be preloaded
48
   * outside the visible map? Large values mean slow loading, small
49
   * ones mean longer delays when panning. Recommended values: 1-3,
50
   * default is 2.
51
   */
52
  this.tileBuffer = parseInt(this.getProperty("mb:tileBuffer", 2));
53
  
54
  /**
55
   * For tiled wms layers: how many pixels should the size of one tile
56
   * be? Default is 256.
57
   */
58
  this.tileSize = parseInt(this.getProperty("mb:tileSize", 256));
59
  
60
  /**
61
   * For WMS on top of Google Maps you need to reproject the WMS image. This will stretch
62
   * the WMS images to fit the odd sized google tiles. Default is false
63
   */
64
  this.imageReproject = Mapbuilder.parseBoolean(
65
      this.getProperty("mb:imageReproject", false));
66
  
67
  /**
68
   * for untiled wms layers: how many times should the map image be
69
   * larger than the visible map. Large values mean slow loading, small
70
   * ones mean many reloads when panning. Recommended values: 1-3,
71
   * default is 2.
72
   */
73
  this.imageBuffer = parseInt(this.getProperty("mb:imageBuffer", 2));
74
  
75
  /**
76
   * Should layers also be rendered outside the map extent? Default is false.
77
   */
78
  this.displayOutsideMaxExtent = Mapbuilder.parseBoolean(
79
      this.getProperty("mb:displayOutsideMaxExtent", false));
80
  
81
  /**
82
   * Number of layers that are currently being loaded
83
   */
84
  this.loadingLayers = 0;
85

    
86
  /**
87
   * Called after a feature has been added to a WFS.  This function triggers
88
   * the WMS basemaps to be redrawn.  A timestamp param is added to the URL
89
   * to ensure the basemap image is not cached.
90
   * This function is triggered by the refreshWmsLayers event. If this event
91
   * is fired with a <layerId> as param, only that layer will be refreshed.
92
   * @param objRef reference to this widget
93
   */
94
  this.refreshWmsLayers = function(objRef) {
95
    var layerId = objRef.model.getParam("refreshWmsLayers");
96
    var uniqueId = (new Date()).getTime();
97
    var layers = layerId ?
98
        [objRef.getLayer(objRef, layerId)] :
99
        objRef.model.map.layers;
100
    for (var i in layers) {
101
      if (layers[i].CLASS_NAME.indexOf('OpenLayers.Layer.WMS') == 0) {
102
        layers[i].mergeNewParams({uniqueId: uniqueId});
103
      }
104
    }
105
  }
106
  this.model.addListener("refreshWmsLayers",this.refreshWmsLayers,this);
107

    
108
  this.model.addListener("refresh",this.paint, this);
109
  this.model.addFirstListener("newModel", this.clear, this);
110
  this.model.addListener("hidden",this.hidden, this);
111
  this.model.addListener("addLayer",this.addLayer, this);
112
  this.model.addListener("deleteLayer",this.deleteLayer, this);
113
  this.model.addListener("moveLayerUp",this.moveLayerUp, this);
114
  this.model.addListener("moveLayerDown",this.moveLayerDown, this);
115
  this.model.addListener("opacity",this.setOpacity,this);
116
  this.model.addListener("bbox", this.zoomToBbox, this);
117
  //this.model.addListener( "zoomOut", this.zoomOut, this );
118
  //this.model.addListener( "zoomIn", this.zoomIn, this );
119
  // this.model.addListener( "zoomToMaxExtent", this.zoomToMaxExtent, this );
120
 //this.model.addFirstListener("loadModel",this.paint,this);
121

    
122
}
123

    
124
/**
125
 * Render the widget.
126
 * @param objRef Pointer to widget object.
127
 */
128
MapPaneOL.prototype.paint = function(objRef, refresh) {
129
  
130
  // Create an OpenLayers map
131

    
132
  //Test if context exist
133
  if(objRef.model.doc.selectSingleNode("//wmc:OWSContext"))
134
    objRef.context="OWS";
135
  else if(objRef.model.doc.selectSingleNode("//wmc:ViewContext"))
136
    objRef.context="View";
137
  else
138
    alert(mbGetMessage("noContextDefined"));
139

    
140
  var proj=objRef.model.proj;
141

    
142
  //maxExtent
143
  var maxExtent=null;
144
  maxExtent=objRef.widgetNode.selectSingleNode("mb:maxExtent");
145
  maxExtent=(maxExtent)?maxExtent.firstChild.nodeValue.split(" "):null;
146
  // If the maxExtentis not specified in the config
147
  // calculate it from the BBox  in the Context.
148
  if(!maxExtent){
149
    maxExtent=objRef.model.getBoundingBox();
150
  }
151
  maxExtent=(maxExtent)?new OpenLayers.Bounds(maxExtent[0],maxExtent[1],maxExtent[2],maxExtent[3]):null;
152
  if(maxExtent==null)alert(mbGetMessage("noBboxInContext"));
153

    
154
  //maxResolution
155
  var maxResolution=null;
156
  maxResolution=objRef.widgetNode.selectSingleNode("mb:maxResolution");
157
  maxResolution=(maxResolution) ? parseFloat(maxResolution.firstChild.nodeValue) : "auto";
158

    
159
  //minResolution
160
  var minResolution=null;
161
  minResolution=objRef.widgetNode.selectSingleNode("mb:minResolution");
162
  minResolution=(minResolution) ? parseFloat(minResolution.firstChild.nodeValue) : undefined;
163
  
164
  //units
165
  var units = proj.getUnits() == 'meters' ? 'm' : proj.getUnits();
166
  
167
  //resolutions
168
  //TBD: if resolutions is both set here and for the baselayer and they are different weird things may happen
169
  //     this needs to be solved
170
  var resolutions=objRef.widgetNode.selectSingleNode("mb:resolutions");
171
  resolutions = resolutions ? resolutions.firstChild.nodeValue.split(",") : null;
172
  if (resolutions) {
173
    for (var r=0; r<resolutions.length; r++) {
174
      resolutions[r] = parseFloat(resolutions[r]);
175
    }
176
  }
177

    
178
  //fixed scales - overrides resolutions
179
  var scales = objRef.widgetNode.selectSingleNode("mb:scales");
180
  if(scales){
181
    scales = scales.firstChild.nodeValue.split(",");
182
    resolutions = new Array();
183
    for (var s=0; s<scales.length; s++) {
184
      resolutions.push(OpenLayers.Util.getResolutionFromScale(scales[s], units));
185
    }
186
  }
187
  if(resolutions){
188
    objRef.model.extent.setZoomLevels(true,resolutions);
189
  }
190
  else objRef.model.extent.setZoomLevels(false);
191

    
192
  //get the output DIV and set it to context-size
193
  var node = document.getElementById(objRef.containerNodeId);
194
  var fixedSize=null;
195
  fixedSize=objRef.widgetNode.selectSingleNode("mb:fixedSize");
196
  fixedSize=(fixedSize)?fixedSize.firstChild.nodeValue:null;
197
  if(fixedSize=="true"){
198
    node.style.width = objRef.model.getWindowWidth()+"px";
199
    node.style.height = objRef.model.getWindowHeight()+"px";
200
  }
201
  
202
  //default map options
203
  var mapOptions = {
204
        controls:[],
205
        projection: proj,
206
        units: units,
207
        fractionalZoom: true,
208
        maxExtent: maxExtent,
209
        maxResolution: maxResolution,
210
        minResolution: minResolution,
211
        resolutions: resolutions,
212
        theme: null, // we have the theme loaded by Mapbuilder
213
        destroy: function(destroy){
214
                   if (destroy != true) {
215
                     this.mbMapPane.model.setParam("newModel", true);
216
                   } else {
217
                     this.mbMapPane = null;
218
                     this.mbCursor = null;
219
                     OpenLayers.Map.prototype.destroy.apply(this, arguments);
220
                     this.layerContainerDiv = null;
221
                     this.baseLayer = null;
222
                   }}
223
      };
224

    
225
  if (!objRef.model.map) {
226
    objRef.model.map = new OpenLayers.Map(node, mapOptions);
227

    
228
    // Increase hight of Control layers to allow for lots of layers.
229
    objRef.model.map.Z_INDEX_BASE.Control=10000;
230
    var baseLayer = null;
231
    
232
    //If we have an OWSContext and we have a BaseLayer we need to use this layer
233
    //for more information have a look at http://docs.codehaus.org/display/MAP/Using+Google-layers
234
    if(objRef.context=="OWS"&&objRef.model.getBaseLayer()){
235
      var baseLayerNode = objRef.model.getBaseLayer();
236
     
237
      //overrule the SRS in the Context with the one from the BaseLayer
238
      var baseSrs = baseLayerNode.selectSingleNode("ows:TileSet/ows:SRS");
239
      if(baseSrs) objRef.model.setSRS(baseSrs.firstChild.nodeValue);
240
      //overrule the units in the Context with the updated SRS units
241
      units = proj.getUnits() == 'meters' ? 'm' : proj.getUnits();
242
      //overrule the boundingbox in the Context with the maxExtent from the BaseLayer
243
      var maxExtentNode = baseLayerNode.selectSingleNode("ows:TileSet/ows:BoundingBox");
244
      if(maxExtentNode) maxExtent = new OpenLayers.Bounds(maxExtentNode.selectSingleNode('@minx').nodeValue,maxExtentNode.selectSingleNode('@miny').nodeValue,maxExtentNode.selectSingleNode('@maxx').nodeValue,maxExtentNode.selectSingleNode('@maxy').nodeValue);
245
      //overrule resolutions in the Context with the one from BaseLayer
246
      //@TODO: check if the firstChild is really needed
247
      var resolutions =baseLayerNode.selectSingleNode("ows:TileSet/ows:Resolutions");
248
      resolutions = resolutions ? resolutions.firstChild.nodeValue.split(",") : null;
249
      if (resolutions) {
250
        for (var r=0; r<resolutions.length; r++) {
251
           resolutions[r] = parseFloat(resolutions[r]);
252
        }
253
      }
254
      //overrule tileSize in the Context with the one from the BaseLayer
255
      //right now we only support square tiles which are defined by their width:		  
256
      var tileSize =baseLayerNode.selectSingleNode("ows:TileSet/ows:Width");
257
      if(tileSize) objRef.tileSize = parseInt(tileSize.nodeValue);
258
      //check if there's a format defined for the BaseLayer
259
      var format = baseLayerNode.selectSingleNode("ows:TileSet/ows:Format");
260
      if(format) format = format.nodeValue;
261
      
262
      //Initialising the baseLayer
263
      // Test service of the baseLayer
264
      var service=baseLayerNode.selectSingleNode("wmc:Server/@service");
265
      service=(service)?service.nodeValue:"";
266
      // Test title of the baseLayer
267
      var title=baseLayerNode.selectSingleNode("wmc:Title");
268
      title=(title)?title.firstChild.nodeValue:"";
269
      // Get the name of the baseLayer
270
      var baseLayerName = baseLayerNode.selectSingleNode("wmc:Name");
271
      baseLayerName=(baseLayerName)?baseLayerName.firstChild.nodeValue:"";
272
      // get the layer-type of the BaseLayer (this allows specifying if is is a arial,road or hybrid map)
273
      var baseLayerType = baseLayerNode.selectSingleNode("ows:TileSet/ows:Layers");
274
      baseLayerType=(baseLayerType)?baseLayerType.firstChild.nodeValue:"hybrid";
275
      // it might be that the baseLayer is a WMS so we need to fetch the url
276
      var href=baseLayerNode.selectSingleNode("wmc:Server/wmc:OnlineResource/@xlink:href");href=(href)?getNodeValue(href):"";
277
      
278
      var baseLayerOptions = {
279
              units: units,
280
              projection: proj,
281
              maxExtent: maxExtent,
282
             
283
              alpha: false,            //option for png transparency with ie6
284
              isBaseLayer: true,
285
              displayOutsideMaxExtent: objRef.displayOutsideMaxExtent,
286
              ratio: 1
287
              
288
         };
289
         
290
      switch(service){
291
        // WMS Layer (Untiled)
292
        case "OGC":
293
        case "WMS":
294
        case "wms":
295
        case "OGC:WMS":
296
          
297
          baseLayerOptions.ratio = objRef.imageBuffer;
298
    
299
          var params = new Array();
300

    
301
         
302
         baseLayer= new OpenLayers.Layer.WMS(title,href,{
303
              layers: baseLayerName,
304
              format: format
305
              },
306
            baseLayerOptions
307
          );
308
        break;
309
    
310
        // WMS-C Layer (Tiled)
311
        case "WMS-C":
312
        case "OGC:WMS-C":
313
          baseLayerOptions.gutter = objRef.tileGutter;
314
          baseLayerOptions.buffer = objRef.tileBuffer;
315
          baseLayerOptions.tileSize = new OpenLayers.Size(objRef.tileSize, objRef.tileSize);
316
          
317
          baseLayer= new OpenLayers.Layer.WMS(title,href,{
318
              layers: baseLayerName,
319
              format: format
320
            },
321
            baseLayerOptions
322
          );
323
          objRef.model.map.fractionalZoom = false;
324
        break;
325
    
326
        case "GMAP":
327
        case "Google":       
328
          if(maxExtent) baseLayerOptions.maxExtent=maxExtent;
329
          //check if we have spherical projection
330
          var sphericalMercator = (objRef.model.getSRS()=='EPSG:900913')?true:false;
331
          //check if we have a layertype
332
          switch(baseLayerType){
333
            case "aerial":
334
            case "satellite":            
335
              baseLayerType=G_SATELLITE_MAP;
336
            break;
337
            case "road":
338
            case "normal":            
339
              baseLayerType=G_NORMAL_MAP;
340
            break;
341
            default:
342
              baseLayerType=G_HYBRID_MAP;
343
          }
344
          baseLayer = new OpenLayers.Layer.Google( baseLayerName , {type: baseLayerType, minZoomLevel: 0, maxZoomLevel:19, sphericalMercator: sphericalMercator, maxResolution: 156543.0339 }, baseLayerOptions );
345
          objRef.model.map.numZoomLevels = 20;
346
          objRef.model.map.fractionalZoom = false;
347
        break;
348
    
349
        case "YMAP":
350
        case "Yahoo":
351
          //Yahoo-layer doesn't support layerTypes
352
          if(maxExtent) baseLayerOptions.maxExtent=maxExtent;
353
          //check if we have spherical projection
354
          var sphericalMercator = (objRef.model.getSRS()=='EPSG:900913')?true:false;          
355
          baseLayer = new OpenLayers.Layer.Yahoo(  baseLayerName , { maxZoomLevel:21, sphericalMercator: sphericalMercator }, baseLayerOptions );
356
          objRef.model.map.fractionalZoom = false;
357
        break;
358
    
359
        case "VE":
360
        case "Microsoft":
361
          if(maxExtent) baseLayerOptions.maxExtent=maxExtent;
362
          //check if we have spherical projection
363
          var sphericalMercator = (objRef.model.getSRS()=='EPSG:900913')?true:false;
364
          //check if we have a layertype
365
          switch(baseLayerType){
366
            case "aerial":
367
            case "satellite":
368
              baseLayerType=VEMapStyle.Aerial;
369
            break;
370
            case "road":
371
            case "normal":
372
              baseLayerType=VEMapStyle.Road;
373
            break;
374
            default:
375
              baseLayerType=VEMapStyle.Hybrid;
376
          }
377
          baseLayer = new OpenLayers.Layer.VirtualEarth( baseLayerName,{minZoomLevel: 0, maxZoomLevel: 21,type: baseLayerType});
378
          objRef.model.map.fractionalZoom = false;
379
        break;
380
    
381
        case "MultiMap":
382
           if(maxExtent) baseLayerOptions.maxExtent=maxExtent;
383
           //check if we have spherical projection
384
          var sphericalMercator = (objRef.model.getSRS()=='EPSG:900913')?true:false;          
385
          baseLayer = new OpenLayers.Layer.MultiMap( baseLayerName , { maxZoomLevel:21, sphericalMercator: sphericalMercator }, baseLayerOptions );
386
          objRef.model.map.fractionalZoom = false;
387
        break;
388
        default:
389
          alert(mbGetMessage("layerTypeNotSupported", service));
390
        }
391
    }
392
    //Otherwise we will just use an empty WMS layer as BaseLayer
393
    else {
394
      var baseLayerOptions = {
395
              units: units,
396
              projection: proj.srsCode,
397
              maxExtent: maxExtent,
398
              maxResolution: maxResolution,  //"auto" if not defined in the context
399
              minResolution: minResolution,
400
              resolutions: resolutions,
401
              alpha: false,            //option for png transparency with ie6
402
              isBaseLayer: true,
403
              displayOutsideMaxExtent: objRef.displayOutsideMaxExtent,
404
              ratio: 1,
405
              singleTile: true,
406
              visibility: false
407
         };
408
      baseLayer = new OpenLayers.Layer.WMS("baselayer",
409
              config.skinDir+"/images/openlayers/blank.gif", null, baseLayerOptions);
410
      
411
    }
412
    objRef.model.map.addLayer(baseLayer); 
413
  }
414
  else {
415
    objRef.deleteAllLayers(objRef);
416
  }
417
    
418
  var layers = objRef.model.getAllLayers();
419
  if (!objRef.oLlayers){
420
    objRef.oLlayers = {};
421
  }
422

    
423
  for (var i=0;i<=layers.length-1;i++){
424
    objRef.addLayer(objRef,layers[i]);
425
  }
426
  var bbox=objRef.model.getBoundingBox();
427

    
428
  // set objRef as attribute of the OL map, so we have a reference
429
  // to MapPaneOL available when handling OpenLayers events.
430
  objRef.model.map.mbMapPane = objRef;
431

    
432
  // register OpenLayers event to keep the context updated
433
  objRef.model.map.events.register('moveend', objRef.model.map, objRef.updateContext);
434
  // register OpenLayers event to do updates onmouseup
435
  objRef.model.map.events.register('mouseup', objRef.model.map, objRef.updateMouse);
436
  
437
  objRef.model.callListeners("bbox");
438
  
439
}
440

    
441
/**
442
 * remove OpenLayers events and layers
443
 * @param objRef reference to this widget
444
 */
445
MapPaneOL.prototype.clear = function(objRef) {
446
  if (objRef.model.map) {
447
    OpenLayers.Event.stopObservingElement(window);
448
    objRef.model.map.destroy(true);
449
    objRef.model.map = null;
450
    objRef.oLlayers = {};
451
  }
452
}
453

    
454
/**
455
 * Receives a 'loadstart' event from OL layer and notifies the listeners
456
 * @param e OpenLayers event
457
 * @return none
458
 */
459
MapPaneOL.prototype.loadLayerStart = function(e) {
460
  // Fetch layerId from model using the ID of the OL Layer
461
  // Necessary to provide a connection between the OL Layer
462
  var layerId = this.getLayerIdByOlLayer(this, e.object);
463
  //layerId = this.model.getParam(event.object.id);
464

    
465
  this.model.setParam("loadLayerStart", layerId);
466
  //this.model.callListeners("loadLayerStart", layerId);
467

    
468
  // keep the modelStatus updated when an OpenLayers layer starts loading.
469
  ++this.loadingLayers;
470
  var message = mbGetMessage((this.loadingLayers>1) ? "loadingLayers" : "loadingLayer",
471
    this.loadingLayers);
472
  this.model.setParam("modelStatus", message);
473
}
474

    
475
/**
476
 * Receives a 'loadend' event from OL layer and notifies the listeners
477
 * @param e OpenLayers event
478
 * @return none
479
 */
480
MapPaneOL.prototype.loadLayerEnd = function(e) {
481
  // Fetch layerId from model using the ID of the OL Layer
482
  var layerId = this.getLayerIdByOlLayer(this, e.object);
483

    
484
  // Tell the listeners that the layer has finished loading
485
  this.model.setParam("loadLayerEnd", layerId);
486
  //this.model.callListeners("loadLayerEnd", layerId);
487

    
488
  // keep the modelStatus updated when an OpenLayers layer starts loading.
489
   --this.loadingLayers;
490
  var message = this.loadingLayers > 0 ?
491
          mbGetMessage((this.loadingLayers>1) ? "loadingLayers" : "loadingLayer",
492
                  this.loadingLayers) :
493
          null;
494
  this.model.setParam("modelStatus", message);
495
}
496

    
497
/**
498
 * Finds MapBuilder layerId based on OL layer
499
 * @param {object} OL layer
500
 * @return {string} layerId
501
 */
502
MapPaneOL.prototype.getLayerIdByOlLayer = function(objRef, olLayer) {
503
  for (var i in objRef.oLlayers) {
504
    if (objRef.oLlayers[i] == olLayer) {
505
      return i;
506
    }
507
  }
508
  return null;
509
}
510

    
511
/**
512
 * Event handler to keep the Mapbuilder context updated. It also
513
 * sets the map cursor to the previously stored value.
514
 * This is called by OpenLayers.
515
 * @param e OpenLayers event
516
 */
517
MapPaneOL.prototype.updateContext = function(e) {
518
  // get objRef from the event originator object (e.object),
519
  // where it was stored as mbPane property by paint().
520
  var objRef = e.object.mbMapPane;
521

    
522
  var bboxOL = objRef.model.map.getExtent().toBBOX().split(',');
523
  var ul = new Array(bboxOL[0],bboxOL[3]);
524
  var lr = new Array(bboxOL[2],bboxOL[1]);
525

    
526
  if(objRef.model.getWindowWidth()!=e.element.offsetWidth)
527
    objRef.model.setWindowWidth(e.element.offsetWidth);
528
  if(objRef.model.getWindowHeight()!=e.element.offsetHeight)
529
    objRef.model.setWindowHeight(e.element.offsetHeight);	
530

    
531
  var currentAoi = objRef.model.getParam('aoi');
532
  var newAoi = new Array(ul, lr);
533
  if (!currentAoi || currentAoi.toString() != newAoi.toString()) {
534
    objRef.model.setBoundingBox( new Array(ul[0], lr[1], lr[0], ul[1]) );
535
    objRef.model.extent.setSize(objRef.model.map.getResolution());
536
    objRef.model.setParam("aoi", newAoi);
537
  }
538
}
539

    
540
/**
541
 * Restore the map cursor stored by buttons. This has to be done
542
 * in an OpenLayers mouseup event, because the mouseup event
543
 * in OpenLayers resets the cursor to default.
544
 * @param e OpenLayers event
545
 */
546
MapPaneOL.prototype.updateMouse = function(e) {
547
  // get objRef from the event originator object (e.object),
548
  // where it was stored as mbPane property by paint().
549
  var objRef = e.object.mbMapPane;
550

    
551
  // update map pane cursor
552
  if (objRef.model.map.mbCursor) {
553
    objRef.model.map.div.style.cursor = objRef.model.map.mbCursor;
554
  }
555
}
556

    
557
/**
558
 * Zoom to the current Bounding Box.
559
 * @param objRef reference to this widget
560
 */
561
MapPaneOL.prototype.zoomToBbox = function(objRef) {
562
  if (objRef.model.map) {
563
    var bbox = objRef.model.getBoundingBox();
564
    var displayBbox = [];
565
    var extent = objRef.model.map.getExtent();
566
    if (extent) {
567
      displayBbox = extent.toBBOX();
568
    }
569
    // only perform zoom operation if not already at bbox
570
    if (bbox.toString() != displayBbox.toString()) {
571
      objRef.model.map.zoomToExtent(new OpenLayers.Bounds(bbox[0],bbox[1],bbox[2],bbox[3]));
572
    }
573
  }
574
}
575

    
576
/**
577
 * Hide/unhide a layer. Called by Context when the hidden attribute changes.
578
 * @param objRef Pointer to widget object.
579
 * @param layerId Id of the layer to hide/unhide.
580
 */
581
MapPaneOL.prototype.hidden = function(objRef, layerId) {
582
  var vis=objRef.model.getHidden(layerId);
583
  if(vis=="1"){ var hidden=false; }
584
  else {var hidden=true; }
585
  var  tmpLayer=objRef.getLayer(objRef,layerId)
586
  if(tmpLayer)tmpLayer.setVisibility(hidden);
587
}
588

    
589
/**
590
  * Returns OL layer node from LayerMgr
591
  * @param layerId The layer Id (or layerName)
592
  */
593
MapPaneOL.prototype.getLayer = function(objRef,layerId) {
594

    
595
  // If layer cannot be found then layerId might actually be layerName
596
  // We then try to fetch the @id of the layer from the model
597
  if (!objRef.oLlayers[layerId]) {
598
    layerId = objRef.model.getLayerIdByName(layerId) || layerId;
599
  }
600

    
601
  if(objRef.oLlayers[layerId] && objRef.oLlayers[layerId].id) {
602
    return objRef.model.map.getLayer(objRef.oLlayers[layerId].id);
603
  } else {
604
    return false;
605
  }
606
}
607

    
608

    
609
//####################################################
610
/**
611
 * Removes a layer from the output
612
/**
613
 * Removes a layer from the output
614
 * @param objRef Pointer to this object.
615
 * @param layerId the WMS name for the layer to be removed
616
 */
617
MapPaneOL.prototype.deleteLayer = function(objRef, layerId) {
618
  if(objRef.oLlayers[layerId])objRef.model.map.removeLayer(objRef.oLlayers[layerId]);
619
}
620
/**
621
 * Removes all layers from the output
622
 * @param objRef Pointer to this object.
623
 * @param objRef Pointer to this object.
624
 */
625
MapPaneOL.prototype.deleteAllLayers = function(objRef) {
626
  for (var i in objRef.oLlayers) {
627
    var layer = objRef.oLlayers[i];
628
    layer.destroy();
629
  }
630
  objRef.oLlayers = {};
631
}
632

    
633
//#############################################TDO
634
/**
635
 * Moves a layer up in the stack of map layers
636
 * @param objRef Pointer to this object.
637
 * @param layerId the WMS name for the layer to be removed
638
 */
639
MapPaneOL.prototype.moveLayerUp = function(objRef, layerId) {
640
  var map=objRef.model.map;
641
  map.raiseLayer(map.getLayer(objRef.oLlayers[layerId].id), 1);
642
}
643

    
644
/**
645
 * Moves a layer up in the stack of map layers
646
 * @param objRef Pointer to this object.
647
 * @param layerId the WMS name for the layer to be removed
648
 */
649
MapPaneOL.prototype.moveLayerDown = function(objRef, layerId) {
650
  objRef.model.map.raiseLayer(objRef.getLayer(objRef,layerId), -1);
651
}
652
//###############################################
653
/**
654
   * Called when the context's opacity attribute changes.
655
/**
656
   * Called when the context's opacity attribute changes.
657
   * @param objRef This object.
658
   * @param layerId  The id of the layer that was toggled.
659
   */
660
MapPaneOL.prototype.setOpacity=function(objRef, layerId){
661
  var _opacity="1";
662
  _opacity=objRef.model.getOpacity(layerId);
663
  objRef.getLayer(objRef,layerId).setOpacity(_opacity);
664
}
665
/**
666
 * Adds a layer into the output
667
   * @param objRef This object.
668
   * @param layerNode  The node of the layer
669
 */
670
MapPaneOL.prototype.addLayer = function(objRef, layerNode) {
671
  // OpenLayers doesn't contain information about projection, so if the
672
  // baseLayer projection is not standard lat/long, it needs to know
673
  // maxExtent and maxResolution to calculate the zoomLevels.
674
  var layer = layerNode;
675

    
676
  // Test service of the layer
677
  var service=layer.selectSingleNode("wmc:Server/@service");service=(service)?service.nodeValue:"";
678

    
679
  // Test title of the layer
680
  var title=layer.selectSingleNode("wmc:Title");title=(title)?title.firstChild.nodeValue:"";
681

    
682
  // Get the name of the layer
683
  layerName = layer.selectSingleNode("wmc:Name");layerName=(layerName)?layerName.firstChild.nodeValue:"";
684

    
685
  // Get the layerId. Fallback to layerName if non-existent
686
  var layerId;
687
  if (layer.selectSingleNode("@id") && layer.selectSingleNode("@id").nodeValue) {
688
    layerId = layer.selectSingleNode("@id").nodeValue;
689
  } else {
690
    layerId = layerName;
691
  }
692

    
693
  if (objRef.context=="OWS"){
694
    var href=layer.selectSingleNode("wmc:Server/wmc:OnlineResource/@xlink:href");href=(href)?getNodeValue(href):"";
695
  }
696
  else {
697
     if(_SARISSA_IS_SAFARI){
698
     var nodehref=layer.selectSingleNode("wmc:Server/wmc:OnlineResource");
699
     var href=nodehref.attributes[1].nodeValue;
700
     }
701
   else{
702
     if(_SARISSA_IS_OPERA){
703
       var href=layer.selectSingleNode("wmc:Server/wmc:OnlineResource").getAttributeNS ("http://www.w3.org/1999/xlink","href");// for opera
704
     }else{
705
       var href=layer.selectSingleNode("wmc:Server/wmc:OnlineResource").getAttribute("xlink:href");
706
     }
707
    }
708
  }
709

    
710
  // Test format of the layer
711
  var format=layer.selectSingleNode("wmc:FormatList/wmc:Format[@current='1']");
712
  if (!format) {
713
    format = layer.selectSingleNode("wmc:FormatList/wmc:Format");
714
  }
715
  format = format ? getNodeValue(format) : "image/gif";
716

    
717
  // Test visibility of the layer
718
  var vis=layer.selectSingleNode("@hidden");
719
  if (vis) {
720
    if(vis.nodeValue=="1")
721
      vis=false;
722
    else
723
      vis=true;
724
  }
725
  // Test if layer is queryable
726
  var query=layer.selectSingleNode("@queryable");
727
  if (query){
728
    if(query.nodeValue=="1")
729
      query=true;
730
    else
731
      query=false;
732
  }
733

    
734
  // Test if opacity is specified
735
  var opacity=layer.selectSingleNode("@opacity");
736
  if (opacity)
737
    opacity=opacity.nodeValue;
738
  else
739
    opacity=false;
740
  
741
  // Get current style node of the layer
742
  var currentStyle = layer.selectSingleNode('wmc:StyleList/wmc:Style[@current=1]');
743

    
744
  // will be true for IE6, false for later versions of IE
745
  objRef.IE6 = false /*@cc_on || @_jscript_version < 5.7 @*/;
746
  
747
  //default option value for a layer
748
  var layerOptions = {
749
          visibility: vis,
750
          projection: objRef.model.map.baseLayer.projection,
751
          queryable: query,
752
          maxExtent: objRef.model.map.baseLayer.maxExtent,
753
          maxResolution: objRef.model.map.baseLayer.maxResolution,  //"auto" if not defined in the context
754
          minResolution: objRef.model.map.baseLayer.minResolution,  //"auto" if not defined in the context
755
          alpha: format.indexOf("png") != -1 ? objRef.IE6 : false,         //option for png transparency with ie6
756
          isBaseLayer: false,
757
          displayOutsideMaxExtent: objRef.displayOutsideMaxExtent
758
     };
759
     
760
  switch(service){
761
    // WMS Layer (Untiled)
762
    case "OGC":
763
    case "WMS":
764
    case "wms":
765
    case "OGC:WMS":
766
      if(!objRef.model.map.baseLayer){
767
        layerOptions.isBaseLayer=true;
768
      }
769
      else {
770
        //TBD what if we have layers with different projections in the context?
771
        layerOptions.reproject=objRef.imageReproject;
772
        layerOptions.isBaseLayer=false;
773
      }
774

    
775
      layerOptions.ratio = objRef.imageBuffer;
776
      layerOptions.singleTile = true;
777

    
778
      var params = new Array();
779
      params = sld2UrlParam(currentStyle);
780
      if (objRef.model.timestampList && objRef.model.timestampList.getAttribute("layerId") == layerId) { 
781
        var ts = objRef.model.timestampList.childNodes[0];
782

    
783
        objRef.oLlayers[layerId]= new OpenLayers.Layer.WMS(title,href,{
784
            layers: layerName,
785
            // "TRUE" in upper case else the context doc boston.xml
786
            // (i.c. the IONIC WMS/WFS) doesn't work.
787
            // Note that this is in line with the WMS standard (OGC 01-068r2),
788
            // section 6.4.1 Parameter Ordering and Case:
789
            // "Parameter names shall not be case sensitive,
790
            //  but parameter values shall be case sensitive."
791
            transparent: layerOptions.isBaseLayer ? "FALSE" : "TRUE",
792
              "TIME":ts.firstChild.nodeValue,	          
793
            format: format,
794
            sld:params.sld,
795
            sld_body:params.sld_body,
796
            styles:params.styles
797
          },
798
          layerOptions
799
        );      
800
        // Turn on timestamp listenet
801
          this.model.addListener("timestamp",this.timestampListener,this);	      
802
      }
803
      else {
804
        objRef.oLlayers[layerId]= new OpenLayers.Layer.WMS(title,href,{
805
            layers: layerName,
806
            // "TRUE" in upper case else the context doc boston.xml
807
            // (i.c. the IONIC WMS/WFS) doesn't work.
808
            // Note that this is in line with the WMS standard (OGC 01-068r2),
809
            // section 6.4.1 Parameter Ordering and Case:
810
            // "Parameter names shall not be case sensitive,
811
            //  but parameter values shall be case sensitive."
812
            transparent: layerOptions.isBaseLayer ? "FALSE" : "TRUE",
813
            format: format,
814
            sld:params.sld,
815
            sld_body:params.sld_body,
816
            styles:params.styles
817
          },
818
          layerOptions
819
        );
820
      }
821
    break;
822

    
823
    // WMS-C Layer (Tiled)
824
    case "WMS-C":
825
    case "OGC:WMS-C":
826
      if(!objRef.model.map.baseLayer){
827
        layerOptions.isBaseLayer=true;
828
      }
829
      else {
830
        //TBD what if we have layers with different projections in the context?
831
        layerOptions.reproject=objRef.imageReproject;
832
        layerOptions.isBaseLayer=false;
833
      }
834

    
835
      layerOptions.gutter = objRef.tileGutter;
836
      layerOptions.buffer = objRef.tileBuffer;
837
      layerOptions.tileSize = new OpenLayers.Size(objRef.tileSize, objRef.tileSize);
838
      
839
      var params = new Array();
840
      params = sld2UrlParam(currentStyle);
841
      objRef.oLlayers[layerId]= new OpenLayers.Layer.WMS(title,href,{
842
          layers: layerName,
843
          transparent: layerOptions.isBaseLayer ? "FALSE" : "TRUE",
844
          format: format,
845
          sld:params.sld,
846
          sld_body:params.sld_body,
847
          styles:params.styles
848
        },
849
        layerOptions
850
      );
851
      objRef.model.map.fractionalZoom = false;
852
    break;
853

    
854
    // WFS Layer
855
    case "WFS":
856
    case "wfs":
857
    case "OGC:WFS":
858
      style = sld2OlStyle(currentStyle);
859
      if(style){
860
        layerOptions.styleMap=new OpenLayers.StyleMap(style);
861
      }
862
      else{
863
        layerOptions.style=objRef.getWebSafeStyle(objRef, 2*i+1);
864
      }
865
      layerOptions.featureClass=OpenLayers.Feature.WFS;
866

    
867
      objRef.oLlayers[layerId]= new OpenLayers.Layer.WFS(
868
        title,
869
        href,{
870
          typename: layerId,
871
          maxfeatures: 1000},
872
          layerOptions
873
        );
874
    break;
875

    
876
    // GML Layer
877
    case "gml":
878
    case "OGC:GML":
879
      style = sld2OlStyle(currentStyle);
880
      if(style){
881
        layerOptions.styleMap=new OpenLayers.StyleMap(style);
882
      }
883
      else{
884
        layerOptions.style=objRef.getWebSafeStyle(objRef, 2*i+1);
885
      }
886
      objRef.oLlayers[layerId] = new OpenLayers.Layer.GML(title,href,layerOptions);
887

    
888
    break;
889

    
890
     // KML Layer
891
    case "KML":
892
    case "kml":
893
      objRef.oLlayers[layerId]= new OpenLayers.Layer.GML(
894
        title,
895
        href,{
896
          format: OpenLayers.Format.KML
897
          }
898
        );
899
    break;
900
    
901
  // Currently the following layertypes are only supported in a OwsContext doc as a BaseLayer
902
  // for more information see http://docs.codehaus.org/display/MAP/Using+Google-layers
903
   /* case "GMAP":
904
    case "Google":
905
      //the empty baseLayer has to be destroyed when you want to use google
906
      objRef.model.map.baseLayer.destroy();
907
      layerOptions.maxExtent=new OpenLayers.Bounds("-20037508", "-20037508", "20037508", "20037508.34");
908
       objRef.oLlayers[layerId] = new OpenLayers.Layer.Google( "Google Satellite" , {type: G_HYBRID_MAP, maxZoomLevel:18, sphericalMercator: true }, layerOptions );
909
    break;
910

    
911
    case "YMAP":
912
    case "Yahoo":
913
      // <script src="http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=euzuro-openlayers"></script>
914
      layerOptions.isBaseLayer=true;
915
      objRef.oLlayers[layerId] = new OpenLayers.Layer.Yahoo( "Yahoo");
916
    break;
917

    
918
    case "VE":
919
    case "Microsoft":
920
      //<script src='http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js'></script>
921
      layerOptions.isBaseLayer=true;
922
      objRef.oLlayers[layerId] = new OpenLayers.Layer.VirtualEarth( "VE",{minZoomLevel: 0, maxZoomLevel: 18,type: VEMapStyle.Hybrid});
923
    break;
924

    
925
    case "MultiMap":
926
      //<script type="text/javascript" src="http://clients.multimap.com/API/maps/1.1/metacarta_04"></script>
927
      layerOptions.isBaseLayer=true;
928
      objRef.oLlayers[layerId] = new OpenLayers.Layer.MultiMap( "MultiMap");
929
    break;*/
930
    default:
931
      alert(mbGetMessage("layerTypeNotSupported", service));
932
  }
933
  if(opacity && objRef.oLlayers[layerId]){
934
    objRef.oLlayers[layerId].setOpacity(opacity);
935
  }
936
  
937
  //objRef.oLlayers[layerId].events.register('loadstart', objRef, objRef.increaseLoadingLayers);
938
  //objRef.oLlayers[layerId].events.register('loadend', objRef, objRef.decreaseLoadingLayers);
939

    
940
  objRef.oLlayers[layerId].events.register('loadstart', objRef, objRef.loadLayerStart);
941
  objRef.oLlayers[layerId].events.register('loadend', objRef, objRef.loadLayerEnd);
942
  
943
  // Here the OL layer gets added to the OL map
944
  objRef.model.map.addLayer(objRef.oLlayers[layerId]);
945
}
946

    
947
/**
948
 * gets an OpenLayers vector style with web safe colors.
949
 * @param objRef reference to this object
950
 * @param colorNumber number of a color from which to generate websafe color
951
 * @return {OpenLayers.Style} style for OpenLayers vector rendering
952
 */
953
MapPaneOL.prototype.getWebSafeStyle = function(objRef, colorNumber) {
954
  colors=new Array("00","33","66","99","CC","FF");
955
  colorNumber=(colorNumber)?colorNumber:0;
956
  colorNumber=(colorNumber<0)?0:colorNumber;
957
  colorNumber=(colorNumber>215)?215:colorNumber;
958
  i=parseInt(colorNumber/36);
959
  j=parseInt((colorNumber-i*36)/6);
960
  k=parseInt((colorNumber-i*36-j*6));
961
  var color="#"+colors[i]+colors[j]+colors[k];
962
  var defaultStyle = {
963
            fillColor: "#808080",
964
            fillOpacity: 1,
965
            strokeColor: "#000000",
966
            strokeOpacity: 1,
967
            strokeWidth: 1,
968
            pointRadius: 6};
969
  var style=OpenLayers.Util.extend(defaultStyle,OpenLayers.Feature.Vector.style["default"]);
970
  style.fillColor = color;
971
  style.strokeColor = color;
972
  style.map = objRef.model.map;
973
  return style;
974
}
975

    
976
/**
977
   * Called for refreshing one layer.
978
   * @param objRef This object.
979
   * @param layerId  The id of the layer that was toggled.
980
   */
981
MapPaneOL.prototype.refreshLayer = function(objRef, layerId , newParams){
982
  newParams['version'] = Math.random(); //necessary for see change in certain case
983
  objRef.getLayer(objRef,layerId).mergeNewParams(newParams);
984
}
985
  
986
  /**
987
   * Called when the map timestamp is changed so set the layer visiblity.
988
   * @param objRef This object.
989
   * @param timestampIndex  The array index for the layer to be displayed. 
990
   */
991
MapPaneOL.prototype.timestampListener=function(objRef, timestampIndex){
992
  if (window.movieLoop.frameIsLoading == true) {
993
    return;
994
  }
995
  var layerId = objRef.model.timestampList.getAttribute("layerId");
996
  var ts = objRef.model.timestampList.childNodes[timestampIndex];
997

    
998
  if (layerId && ts) {				
999
    var curLayer = objRef.oLlayers[layerId]; //TBD: please check if this still works now we've moved to layerId
1000
    if (!curLayer.grid) {
1001
      return;
1002
    }
1003
    div = curLayer.grid[0][0].imgDiv;
1004
    // Perform URL substitution via regexps
1005
    var oldImageUrl = div.src || div.firstChild.src;
1006
    var newImageUrl = oldImageUrl.replace(/TIME\=.*?\&/,'TIME=' + ts.firstChild.nodeValue + '&');
1007
    if (oldImageUrl == newImageUrl) {
1008
      return;
1009
    }
1010

    
1011
    function imageLoaded() {
1012
      window.movieLoop.frameIsLoading = false;
1013
      if(element.removeEventListener) { // Standard
1014
        element.removeEventListener("load", imageLoaded, false);
1015
      } else if(element.detachEvent) { // IE
1016
        element.detachEvent('onload', imageLoaded);
1017
      }
1018
    }
1019

    
1020
    window.movieLoop.frameIsLoading = true;
1021
    var element = div.nodeName.toUpperCase() == "IMG" ? div : div.firstChild;
1022
    if(element.addEventListener) { // Standard
1023
      element.addEventListener("load", imageLoaded, false);
1024
    } else if(element.attachEvent) { // IE
1025
      element.attachEvent('onload', imageLoaded);
1026
    }
1027
    if (objRef.IE6) {
1028
      OpenLayers.Util.modifyAlphaImageDiv(div,
1029
            null, null, null, newImageUrl);
1030
    } else {
1031
      element.src = newImageUrl;
1032
    }
1033
  }
1034
      
1035
}
(7-7/19)