Project

General

Profile

1
/*
2
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
3
$Id$
4
*/
5

    
6
/**
7
 * Stores a Web Map Context (WMC) document as defined by the Open GIS Consortium
8
 * http://opengis.org and extensions the the WMC.  
9
 *
10
 * Listeners supported by this model:
11
 * "refresh" called when window parameters (width/height, bbox) are changed
12
 * "hidden" called when visibilty of a layer is changed
13
 *
14
 * @constructor
15
 * @base ModelBase
16
 * @author Cameron Shorter
17
 * @param modelNode Pointer to the xml node for this model from the config file.
18
 * @param parent    The parent model for the object.
19
  * 
20
 */
21
function Context(modelNode, parent) {
22
  // Inherit the ModelBase functions and parameters
23
  ModelBase.apply(this, new Array(modelNode, parent));
24

    
25
  this.namespace = "xmlns:mb='http://mapbuilder.sourceforge.net/mapbuilder' xmlns:wmc='http://www.opengis.net/context' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'";
26

    
27
  /**
28
   * Change a Layer's visibility.
29
   * @param layerName  The name of the layer that is to be changed
30
   * @param hidden     String with the value to be set; 1=hidden, 0=visible.
31
   */
32
  this.setHidden=function(layerName, hidden){
33
    // Set the hidden attribute in the Context
34
    var hiddenValue = "0";
35
    if (hidden) hiddenValue = "1";
36
      
37
    var layer=this.doc.selectSingleNode("/wmc:ViewContext/wmc:LayerList/wmc:Layer[wmc:Name='"+layerName+"']");
38
    if (layer) layer.setAttribute("hidden", hiddenValue);
39
    // Call the listeners
40
    this.callListeners("hidden", layerName);
41
  }
42

    
43
  /**
44
   * Get the layer's visiblity attribute value.
45
   * @param layerName  The name of the layer that is to be changed
46
   * @return hidden  String with the value; 1=hidden, 0=visible.
47
   */
48
  this.getHidden=function(layerName){
49
    var hidden=1;
50
    var layer=this.doc.selectSingleNode("/wmc:ViewContext/wmc:LayerList/wmc:Layer[wmc:Name='"+layerName+"']");
51
    if (layer) hidden = layer.getAttribute("hidden");
52
    return hidden;
53
  }
54

    
55
  /**
56
   * Get the BoundingBox value from the Context document.
57
   * @return BoundingBox array with the sequence (xmin,ymin,xmax,ymax).
58
   */
59
  this.getBoundingBox=function() {
60
    var boundingBox=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:BoundingBox");
61
    bbox = new Array();
62
    bbox[0]=parseFloat(boundingBox.getAttribute("minx"));
63
    bbox[1]=parseFloat(boundingBox.getAttribute("miny"));
64
    bbox[2]=parseFloat(boundingBox.getAttribute("maxx"));
65
    bbox[3]=parseFloat(boundingBox.getAttribute("maxy"));
66
    return bbox;
67
  }
68

    
69
  /**
70
   * Set the BoundingBox element and call the refresh listeners
71
   * @param boundingBox array in the sequence (xmin, ymin, xmax, ymax).
72
   */
73
  this.setBoundingBox=function(boundingBox) {
74
    // Set BoundingBox in context
75
    //bbox=this.doc.documentElement.getElementsByTagName("BoundingBox").item(0);
76
    var bbox=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:BoundingBox");
77
    bbox.setAttribute("minx", boundingBox[0]);
78
    bbox.setAttribute("miny", boundingBox[1]);
79
    bbox.setAttribute("maxx", boundingBox[2]);
80
    bbox.setAttribute("maxy", boundingBox[3]);
81
    // Call the listeners
82
    this.callListeners("bbox", boundingBox);
83
  }
84

    
85
  /**
86
   * Set the BoundingBox element and call the refresh listeners
87
   * @param boundingBox array in the sequence (xmin, ymin, xmax, ymax).
88
   */
89
  this.initBbox=function(objRef) {
90
    // Set BoundingBox in context from URL CGI params
91
    if (window.cgiArgs["bbox"]) {     //set as minx,miny,maxx,maxy
92
      var bbox = window.cgiArgs["bbox"].split(',');
93
      var ul = new Array(parseFloat(bbox[0]),parseFloat(bbox[3]));
94
      var lr = new Array(parseFloat(bbox[2]),parseFloat(bbox[1]));
95
      objRef.extent.zoomToBox(ul, lr);
96
    }
97
  }
98
  //PGC this.addListener( "loadModel", this.initBbox, this );
99
  this.addListener( "contextLoaded", this.initBbox, this );
100

    
101
  /**
102
   * Set the aoi param and call the refresh listeners
103
   * @param boundingBox array in the sequence (xmin, ymin, xmax, ymax).
104
   */
105
  this.initAoi=function(objRef) {
106
    // Set AOI of context from URL CGI params
107
    if (window.cgiArgs["aoi"]) {      //set as ul,lr point arrays
108
      var aoi = window.cgiArgs["aoi"].split(',');
109
      objRef.setParam("aoi",new Array(new Array(aoi[0],aoi[3]),new Array(aoi[2],aoi[1])));
110
    }
111
  }
112
  this.addListener( "loadModel", this.initAoi, this );
113
  //MA this.addListener( "contextLoaded", this.initAoi, this );
114

    
115
  /**
116
   * Set the Spacial Reference System for the context document.
117
   * @param srs The Spatial Reference System.
118
   */
119
  this.setSRS=function(srs) {
120
    var bbox=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:BoundingBox");
121
    bbox.setAttribute("SRS",srs);
122
    this.callListeners("srs");
123
  }
124

    
125
  /**
126
   * Get the Spacial Reference System from the context document.
127
   * @return srs The Spatial Reference System.
128
   */
129
  this.getSRS=function() {
130
    var bbox=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:BoundingBox");
131
    srs=bbox.getAttribute("SRS");
132
    return srs;
133
  }
134

    
135
  /**
136
   * Get the Window width.
137
   * @return width The width of map window from the context document
138
   */
139
  this.getWindowWidth=function() {
140
    var win=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Window");
141
    return win.getAttribute("width");
142
  }
143

    
144
  /**
145
   * Set the Window width.
146
   * @param width The width of map window (therefore of map layer images).
147
   */
148
  this.setWindowWidth=function(width) {
149
    var win=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Window");
150
    win.setAttribute("width", width);
151
    this.callListeners("resize");
152
  }
153

    
154
  /**
155
   * Get the Window height.
156
   * @return height The height of map window from the context document.
157
   */
158
  this.getWindowHeight=function() {
159
    var win=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Window");
160
    return win.getAttribute("height");
161
  }
162

    
163
  /**
164
   * Set the Window height.
165
   * @param height The height of map window to set in the context document
166
   */
167
  this.setWindowHeight=function(height) {
168
    var win=this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Window");
169
    win.setAttribute("height", height);
170
    this.callListeners("resize");
171
  }
172

    
173
  /**
174
   * Returns the serverUrl for the layer passed in as the feature argument.
175
   * @param requestName ignored for context docs (only GetMap supported)
176
   * @param method ignored for context docs (only GET supported)
177
   * @param feature the Layer node from the context doc
178
   * @return URL for the GetMap request 
179
   */
180
  this.getServerUrl = function(requestName, method, feature) {
181
    return feature.selectSingleNode("wmc:Server/wmc:OnlineResource").getAttribute("xlink:href");
182
  }
183

    
184
  /**
185
   * Returns the WMS version for the layer passed in as the feature argument
186
   * @param feature the Layer node from the context doc
187
   * @return the WMS GetMap version for the Layer.
188
   */
189
  this.getVersion = function(feature) {  
190
    return feature.selectSingleNode("wmc:Server").getAttribute("version");
191
  }
192

    
193
  /**
194
   * Get HTTP method for the specified feature
195
   * @param feature the Layer node from the context doc
196
   * @return the HTTP method to get the feature with
197
   */
198
  this.getMethod = function(feature) {
199
    return feature.selectSingleNode("wmc:Server/wmc:OnlineResource").getAttribute("wmc:method");
200
  }
201

    
202
  /**
203
   * Method to get a list of queryable layers
204
   * @return the list with queryable layers
205
   */
206
  this.getQueryableLayers = function() {
207
    var listNodeArray = this.doc.selectNodes("/wmc:ViewContext/wmc:LayerList/wmc:Layer[attribute::queryable='1']/wmc:Name");
208
    return listNodeArray;
209
  }
210

    
211
  /**
212
   * Method to get a list of all layers in the context doc
213
   * TBD: merge this with above, passing queryable as an optional boolean param?
214
   * @return the list with all layers
215
   */
216
  this.getAllLayers = function() {
217
    var listNodeArray = this.doc.selectNodes("/wmc:ViewContext/wmc:LayerList/wmc:Layer");
218
    return listNodeArray;
219
  }
220

    
221
  /**
222
   * Method to get a layer with the specified name in the context doc
223
   * @param layerName the layer to be returned
224
   * @return the list with all layers
225
   */
226
  this.getLayer = function(layerName) {
227
    var layer = this.doc.selectSingleNode("/wmc:ViewContext/wmc:LayerList/wmc:Layer[wmc:Name='"+layerName+"']");
228
    //TBD: add in time stamp
229
    return layer;
230
  }
231

    
232
  /**
233
   * Method to add a Layer to the LayerList
234
   * @param layerNode the Layer node from another context doc or capabiltiies doc
235
   */
236
  this.addLayer = function(objRef, layerNode) {
237
    var parentNode = objRef.doc.selectSingleNode("/wmc:ViewContext/wmc:LayerList");
238
    parentNode.appendChild(layerNode.cloneNode(true));
239
    objRef.modified = true;
240
    //objRef.callListeners("refresh");
241
  }
242
  this.addFirstListener( "addLayer", this.addLayer, this );
243

    
244
  /**
245
   * Method to remove a Layer from the LayerList
246
   * @param layerName the Layer to be deleted
247
   */
248
  this.deleteLayer = function(objRef, layerName) {
249
    var deletedNode = objRef.getLayer(layerName);
250
    if (!deletedNode) {
251
      alert("node note found; unable to delete node:"+layerName);
252
      return;
253
    }
254
    deletedNode.parentNode.removeChild(deletedNode);
255
    objRef.modified = true;
256
  }
257
  this.addFirstListener( "deleteLayer", this.deleteLayer, this );
258

    
259
  /**
260
   * Method to move a Layer in the LayerList up
261
   * @param layerName the layer to be moved
262
   */
263
  this.moveLayerUp = function(objRef, layerName) {
264
    var movedNode = objRef.getLayer(layerName);
265
    var sibNode = movedNode.selectSingleNode("following-sibling::*");
266
    if (!sibNode) {
267
      alert("can't move node past beginning of list:"+layerName);
268
      return;
269
    }
270
    movedNode.parentNode.insertBefore(sibNode,movedNode);
271
    objRef.modified = true;
272
  }
273
  this.addFirstListener( "moveLayerUp", this.moveLayerUp, this );
274

    
275
  /**
276
   * Method to move a Layer in the LayerList down
277
   * @param layerName the layer to be moved
278
   */
279
  this.moveLayerDown = function(objRef, layerName) {
280
    var movedNode = objRef.getLayer(layerName);
281
    var listNodeArray = movedNode.selectNodes("preceding-sibling::*");  //preceding-sibling axis contains all previous siblings
282
    var sibNode = listNodeArray[listNodeArray.length-1];
283
    if (!sibNode) {
284
      alert("can't move node past beginning of list:"+layerName);
285
      return;
286
    }
287
    movedNode.parentNode.insertBefore(movedNode,sibNode);
288
    objRef.modified = true;
289
  }
290
  this.addFirstListener( "moveLayerDown", this.moveLayerDown, this );
291

    
292
  /**
293
   * Adds a node to the Context document extension element.  The extension element
294
   * will be created if it doesn't already exist.  
295
   * @param extensionNode the node to be appended in the extension element.
296
   * @return the ndoe added to the extension element
297
   */
298
  this.setExtension = function(extensionNode) {
299
    var extension = this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Extension");
300
    if (!extension) {
301
      var general = this.doc.selectSingleNode("/wmc:ViewContext/wmc:General");
302
      var newChild = createElementWithNS(this.doc,"Extension",'http://www.opengis.net/context');
303
      extension = general.appendChild(newChild);
304
    }
305
    return extension.appendChild(extensionNode);
306
  }
307

    
308
  /**
309
   * Returns the contents of the extension element
310
   * @return the contents of the extension element
311
   */
312
  this.getExtension = function() {
313
    return this.doc.selectSingleNode("/wmc:ViewContext/wmc:General/wmc:Extension");
314
  }
315

    
316
  /**
317
   * Parses a Dimension element from the Context document as a loadModel listener.
318
   * This results in an XML structure with one element for each GetMap time value 
319
   * parameter and added to the Context extrension element.
320
   * @param objRef a pointer to this object 
321
   */
322
  this.initTimeExtent = function( objRef ) {
323
    //only the first one selected is used as the timestamp source
324
    //var extentNode = objRef.doc.selectSingleNode("//wmc:Layer/wmc:Dimension[@name='time']");
325
    //TBD: how to deal with multiple time dimensions in one context doc, or caps doc?
326
    var timeNodes = objRef.doc.selectNodes("//wmc:Dimension[@name='time']");
327
    for (var i=0; i<timeNodes.length; ++i) {
328
      var extentNode = timeNodes[i];
329
      objRef.timestampList = createElementWithNS(objRef.doc,"TimestampList",mbNsUrl);
330
      var layerName = extentNode.parentNode.parentNode.selectSingleNode("wmc:Name").firstChild.nodeValue;
331
      objRef.timestampList.setAttribute("layerName", layerName);
332
      //alert("found time dimension, extent:"+extentNode.firstChild.nodeValue);
333
      var times = extentNode.firstChild.nodeValue.split(",");   //comma separated list of arguments
334
      for (var j=0; j<times.length; ++j) {
335
        var params = times[j].split("/");     // parses start/end/period
336
        if (params.length==3) {
337
          var start = setISODate(params[0]);
338
          var stop = setISODate(params[1]);
339
          var period = params[2];
340
          var parts = period.match(/^P((\d*)Y)?((\d*)M)?((\d*)D)?T?((\d*)H)?((\d*)M)?((.*)S)?/);
341
          for (var i=1; i<parts.length; ++i) {
342
            if (!parts[i]) parts[i]=0;
343
          }
344
          //alert("start time:"+start.toString());
345
          do {
346
            var timestamp = createElementWithNS(objRef.doc,"Timestamp",mbNsUrl);
347
            timestamp.appendChild(objRef.doc.createTextNode(getISODate(start)));
348
            objRef.timestampList.appendChild(timestamp);
349

    
350
            start.setFullYear(start.getFullYear()+parseInt(parts[2],10));
351
            start.setMonth(start.getMonth()+parseInt(parts[4],10));
352
            start.setDate(start.getDate()+parseInt(parts[6],10));
353
            start.setHours(start.getHours()+parseInt(parts[8],10));
354
            start.setMinutes(start.getMinutes()+parseInt(parts[10],10));
355
            start.setSeconds(start.getSeconds()+parseFloat(parts[12]));
356
            //alert("time:"+start.toString());
357
          } while(start.getTime() <= stop.getTime());
358

    
359
        } else {
360
          //output single date value
361
          var timestamp = createElementWithNS(objRef.doc,"Timestamp",mbNsUrl);
362
          timestamp.appendChild(objRef.doc.createTextNode(times[j]));
363
          objRef.timestampList.appendChild(timestamp);
364
        }
365
      }
366
     objRef.setExtension(objRef.timestampList);  
367
    }
368
  }
369
  this.addFirstListener( "loadModel", this.initTimeExtent, this );
370

    
371
  /**
372
   * Returns the current timestamp value.
373
   * @param layerName the name of the Layer from which the timestamp list was generated
374
   * @return the current timestamp value.
375
   */
376
  this.getCurrentTimestamp = function( layerName ) {
377
    var index = this.getParam("timestamp");
378
    return this.timestampList.childNodes[index].firstChild.nodeValue;
379
  }
380
}
381

    
(2-2/18)