1
|
/*
|
2
|
Author: Cameron Shorter cameronAtshorter.net
|
3
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
4
|
|
5
|
$Id$
|
6
|
*/
|
7
|
|
8
|
// Ensure this object's dependancies are loaded.
|
9
|
mapbuilder.loadScript(baseDir+"/widget/WidgetBase.js");
|
10
|
mapbuilder.loadScript(baseDir+"/widget/MapContainerBase.js");
|
11
|
|
12
|
/**
|
13
|
* Widget to render a map from an OGC context document. The layers are rendered
|
14
|
* as an array of DHTML layers that contain an <IMG> tag with src attribute set
|
15
|
* to the GetMap request.
|
16
|
* @constructor
|
17
|
* @base WidgetBaseXSL
|
18
|
* @base MapContainerBase
|
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 MapPane(widgetNode, model) {
|
23
|
WidgetBase.apply(this,new Array(widgetNode, model));
|
24
|
MapContainerBase.apply(this,new Array(widgetNode, model));
|
25
|
|
26
|
// Set this.stylesheet
|
27
|
// Defaults to "widget/<widgetName>.xsl" if not defined in config file.
|
28
|
if ( !this.stylesheet ) {
|
29
|
var styleNode = widgetNode.selectSingleNode("mb:stylesheet");
|
30
|
if (styleNode ) {
|
31
|
this.stylesheet = new XslProcessor(styleNode.firstChild.nodeValue,model.namespace);
|
32
|
} else {
|
33
|
this.stylesheet = new XslProcessor(baseDir+"/widget/"+widgetNode.nodeName+".xsl",model.namespace);
|
34
|
}
|
35
|
}
|
36
|
|
37
|
//loading img to be displayed while models load
|
38
|
var loadingSrc = widgetNode.selectSingleNode("mb:loadingSrc");
|
39
|
if (loadingSrc) {
|
40
|
this.loadingSrc = config.skinDir + loadingSrc.firstChild.nodeValue;
|
41
|
} else {
|
42
|
this.loadingSrc = config.skinDir + "/images/Loading.gif";
|
43
|
}
|
44
|
|
45
|
// Set stylesheet parameters for all the child nodes from the config file
|
46
|
for (var j=0;j<widgetNode.childNodes.length;j++) {
|
47
|
if (widgetNode.childNodes[j].firstChild
|
48
|
&& widgetNode.childNodes[j].firstChild.nodeValue)
|
49
|
{
|
50
|
this.stylesheet.setParameter(
|
51
|
widgetNode.childNodes[j].nodeName,
|
52
|
widgetNode.childNodes[j].firstChild.nodeValue);
|
53
|
}
|
54
|
}
|
55
|
|
56
|
//all stylesheets will have these properties available
|
57
|
this.stylesheet.setParameter("modelId", this.model.id );
|
58
|
this.stylesheet.setParameter("modelTitle", this.model.title );
|
59
|
this.stylesheet.setParameter("widgetId", this.id );
|
60
|
this.stylesheet.setParameter("skinDir", config.skinDir );
|
61
|
this.stylesheet.setParameter("lang", config.lang );
|
62
|
|
63
|
|
64
|
/**
|
65
|
* Called when the context's hidden attribute changes.
|
66
|
* @param objRef This object.
|
67
|
* @param layerName The name of the layer that was toggled.
|
68
|
*/
|
69
|
this.hiddenListener=function(objRef, layerName){
|
70
|
var vis="visible";
|
71
|
if(objRef.model.getHidden(layerName)=="1") {
|
72
|
vis="hidden";
|
73
|
}
|
74
|
var layerId = objRef.model.id + "_" + objRef.id + "_" + layerName;
|
75
|
var layer = document.getElementById(layerId);
|
76
|
if (layer) {
|
77
|
layer.style.visibility=vis;
|
78
|
imgId = "real"+layer.imgId;
|
79
|
img = document.getElementById(imgId); // Hack to make sure that the child element is toggled in IE
|
80
|
if(img) img.style.visibility=vis;
|
81
|
}
|
82
|
}
|
83
|
this.model.addListener("hidden",this.hiddenListener,this);
|
84
|
|
85
|
/**
|
86
|
* Called after a feature has been added to a WFS. This function triggers
|
87
|
* the WMS basemaps to be redrawn. A timestamp param is added to the URL
|
88
|
* to ensure the basemap image is not cached.
|
89
|
*/
|
90
|
this.refreshWmsLayers=function(objRef){
|
91
|
objRef.d=new Date();
|
92
|
objRef.stylesheet.setParameter("uniqueId",objRef.d.getTime());
|
93
|
objRef.paint(objRef);
|
94
|
}
|
95
|
this.model.addListener("refreshWmsLayers",this.refreshWmsLayers,this);
|
96
|
|
97
|
this.model.addListener("refresh",this.paint, this);
|
98
|
this.model.addListener("addLayer",this.addLayer, this);
|
99
|
this.model.addListener("deleteLayer",this.deleteLayer, this);
|
100
|
this.model.addListener("moveLayerUp",this.moveLayerUp, this);
|
101
|
this.model.addListener("moveLayerDown",this.moveLayerDown, this);
|
102
|
}
|
103
|
|
104
|
/**
|
105
|
* Render the widget.
|
106
|
* @param objRef Pointer to widget object.
|
107
|
*/
|
108
|
MapPane.prototype.paint = function(objRef, refresh) {
|
109
|
|
110
|
if (objRef.model.doc && objRef.node && (objRef.autoRefresh||refresh) ) {
|
111
|
//if (objRef.debug) alert("source:"+Sarissa.serialize(objRef.model.doc));
|
112
|
|
113
|
objRef.stylesheet.setParameter("width", objRef.model.getWindowWidth());
|
114
|
objRef.stylesheet.setParameter("height", objRef.model.getWindowHeight());
|
115
|
objRef.stylesheet.setParameter("bbox", objRef.model.getBoundingBox().join(","));
|
116
|
objRef.stylesheet.setParameter("srs", objRef.model.getSRS());
|
117
|
|
118
|
//confirm inputs
|
119
|
if (objRef.debug) alert("painting:"+Sarissa.serialize(objRef.model.doc));
|
120
|
if (objRef.debug) alert("stylesheet:"+Sarissa.serialize(objRef.stylesheet.xslDom));
|
121
|
|
122
|
//process the doc with the stylesheet
|
123
|
var tempDom = objRef.stylesheet.transformNodeToObject(objRef.model.doc);
|
124
|
var tempNodeList = tempDom.selectNodes("//img");
|
125
|
|
126
|
//debug output
|
127
|
if (objRef.debug) {
|
128
|
alert("painting:"+objRef.id+":"+s);
|
129
|
if (config.serializeUrl) postLoad(config.serializeUrl, s);
|
130
|
}
|
131
|
|
132
|
//create a DIV to hold all the individual image DIVs
|
133
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
134
|
if (!outputNode) {
|
135
|
outputNode = document.createElement("div");
|
136
|
outputNode.setAttribute("id", objRef.outputNodeId);
|
137
|
outputNode.style.position = "absolute";
|
138
|
objRef.node.appendChild(outputNode);
|
139
|
outputNode.style.left='0px';
|
140
|
outputNode.style.top='0px';
|
141
|
}
|
142
|
|
143
|
//loop through all layers and create an array of IMG objects for preloading
|
144
|
// the WMS getMap calls
|
145
|
var layers = objRef.model.getAllLayers();
|
146
|
if (!objRef.imageStack) objRef.imageStack = new Array(layers.length);
|
147
|
objRef.firstImageLoaded = false;
|
148
|
|
149
|
objRef.layerCount = layers.length;
|
150
|
|
151
|
for (var i=0;i<layers.length;i++){
|
152
|
if (!objRef.imageStack[i]) {
|
153
|
objRef.imageStack[i] = new Image();
|
154
|
objRef.imageStack[i].objRef = objRef;
|
155
|
}
|
156
|
//var newSrc = tempNode.firstChild.childNodes[i].firstChild.getAttribute("src");
|
157
|
var newSrc = tempNodeList[i].getAttribute("src");
|
158
|
objRef.loadImgDiv(layers[i],newSrc,objRef.imageStack[i]);
|
159
|
}
|
160
|
var message = "loading " + objRef.layerCount + " map layer" + ((objRef.layerCount>1)?"s":"");
|
161
|
objRef.model.setParam("modelStatus", message);
|
162
|
}
|
163
|
}
|
164
|
|
165
|
/**
|
166
|
* Returns an ID for the image DIV given a layer name
|
167
|
* @param layerName the name of the WMS layer
|
168
|
*/
|
169
|
MapPane.prototype.getLayerDivId = function(layerName) {
|
170
|
return this.model.id +"_"+ this.id +"_"+ layerName; //TBD: add in timestamps
|
171
|
}
|
172
|
|
173
|
/**
|
174
|
* Adds a layer into the output
|
175
|
* @param layerName the WMS anme for the layer to be removed
|
176
|
*/
|
177
|
MapPane.prototype.addLayer = function(objRef, layerNode) {
|
178
|
|
179
|
++objRef.layerCount;
|
180
|
var message = "loading " + objRef.layerCount + " map layer" + ((objRef.layerCount>1)?"s":"");
|
181
|
objRef.model.setParam("modelStatus", message);
|
182
|
|
183
|
//process the doc with the stylesheet
|
184
|
objRef.stylesheet.setParameter("width", objRef.model.getWindowWidth());
|
185
|
objRef.stylesheet.setParameter("height", objRef.model.getWindowHeight());
|
186
|
objRef.stylesheet.setParameter("bbox", objRef.model.getBoundingBox().join(","));
|
187
|
objRef.stylesheet.setParameter("srs", objRef.model.getSRS());
|
188
|
var s = objRef.stylesheet.transformNodeToString(layerNode);
|
189
|
var tempNode = document.createElement("div");
|
190
|
tempNode.innerHTML = s;
|
191
|
var newSrc = tempNode.firstChild.firstChild.getAttribute("src");
|
192
|
|
193
|
objRef.imageStack.push(new Image());
|
194
|
objRef.imageStack[objRef.imageStack.length-1].objRef = objRef;
|
195
|
objRef.firstImageLoaded = true;
|
196
|
objRef.loadImgDiv(layerNode,newSrc,objRef.imageStack[objRef.imageStack.length-1]);
|
197
|
}
|
198
|
|
199
|
/**
|
200
|
* Removes a layer from the output
|
201
|
* @param layerName the WMS anme for the layer to be removed
|
202
|
*/
|
203
|
MapPane.prototype.deleteLayer = function(objRef, layerName) {
|
204
|
var imgDivId = objRef.getLayerDivId(layerName);
|
205
|
var imgDiv = document.getElementById(imgDivId);
|
206
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
207
|
outputNode.removeChild(imgDiv);
|
208
|
}
|
209
|
|
210
|
/**
|
211
|
* Moves a layer up in the stack of map layers
|
212
|
* @param layerName the WMS anme for the layer to be removed
|
213
|
*/
|
214
|
MapPane.prototype.moveLayerUp = function(objRef, layerName) {
|
215
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
216
|
var imgDivId = objRef.getLayerDivId(layerName);
|
217
|
var movedNode = document.getElementById(imgDivId);
|
218
|
var sibNode = movedNode.nextSibling;
|
219
|
if (!sibNode) {
|
220
|
alert("can't move node past beginning of list:"+layerName);
|
221
|
return;
|
222
|
}
|
223
|
outputNode.insertBefore(sibNode,movedNode);
|
224
|
}
|
225
|
|
226
|
/**
|
227
|
* Moves a layer up in the stack of map layers
|
228
|
* @param layerName the WMS anme for the layer to be removed
|
229
|
*/
|
230
|
MapPane.prototype.moveLayerDown = function(objRef, layerName) {
|
231
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
232
|
var imgDivId = objRef.getLayerDivId(layerName);
|
233
|
var movedNode = document.getElementById(imgDivId);
|
234
|
var sibNode = movedNode.previousSibling;
|
235
|
if (!sibNode) {
|
236
|
alert("can't move node past end of list:"+layerName);
|
237
|
return;
|
238
|
}
|
239
|
outputNode.insertBefore(movedNode,sibNode);
|
240
|
}
|
241
|
|
242
|
/**
|
243
|
* sets up the image div to be loaded. Images are preloaded in the imageStack
|
244
|
* array and replaced in the document DOM in the onload handler
|
245
|
* @param layerNode the context layer to be loaded
|
246
|
* @param newSrc the new URL to be used for the image
|
247
|
* @param newImg an HTML IMG object to pre-load the image in
|
248
|
*/
|
249
|
MapPane.prototype.loadImgDiv = function(layerNode,newSrc,newImg) {
|
250
|
var outputNode = document.getElementById( this.outputNodeId );
|
251
|
var layerName = layerNode.selectSingleNode("wmc:Name").firstChild.nodeValue;
|
252
|
var layerHidden = (layerNode.getAttribute("hidden")==1)?true:false;
|
253
|
var imageFormat = "image/gif";
|
254
|
var imageFormatNode = layerNode.selectSingleNode("wmc:FormatList/wmc:Format[@current='1']");
|
255
|
if (imageFormatNode) imageFormat = imageFormatNode.firstChild.nodeValue;
|
256
|
|
257
|
//make sure there is an image DIV in the output node for this layer
|
258
|
var imgDivId = this.getLayerDivId(layerName);
|
259
|
var imgDiv = document.getElementById(imgDivId);
|
260
|
if (!imgDiv) {
|
261
|
imgDiv = document.createElement("div");
|
262
|
imgDiv.setAttribute("id", imgDivId);
|
263
|
imgDiv.style.position = "absolute";
|
264
|
imgDiv.style.visibility = (layerHidden)?"hidden":"visible";
|
265
|
imgDiv.style.top = '0px';
|
266
|
imgDiv.style.left = '0px';
|
267
|
imgDiv.imgId = Math.random().toString();
|
268
|
var domImg = document.createElement("img");
|
269
|
domImg.id = "real"+imgDiv.imgId;
|
270
|
//domImg.src = this.loadingSrc;
|
271
|
domImg.src = config.skinDir+"/images/Spacer.gif";
|
272
|
domImg.layerHidden = layerHidden;
|
273
|
imgDiv.appendChild(domImg);
|
274
|
outputNode.appendChild(imgDiv);
|
275
|
}
|
276
|
|
277
|
// preload image
|
278
|
newImg.id = imgDiv.imgId;
|
279
|
newImg.hidden = layerHidden;
|
280
|
newImg.title = layerNode.selectSingleNode("wmc:Title").firstChild.nodeValue;
|
281
|
newImg.fixPng = false;
|
282
|
if (_SARISSA_IS_IE && imageFormat=="image/png") newImg.fixPng = true;
|
283
|
newImg.onload = MapImgLoadHandler;
|
284
|
newImg.onerror = MapImgErrorHandler;
|
285
|
newImg.onfail = MapImgFailHandler;
|
286
|
newImg.src = newSrc;
|
287
|
}
|
288
|
|
289
|
/**
|
290
|
* image onload handler function.
|
291
|
* Replaces the source with the new one and fixes the displacement to
|
292
|
* compensate the container main div displacement to result in in a zero displacement.
|
293
|
* The first image to be returned will hide all other layers and re-position them
|
294
|
* and they are made visible when their onload event fires.
|
295
|
*/
|
296
|
function MapImgLoadHandler() {
|
297
|
var oldImg = document.getElementById("real"+this.id );
|
298
|
|
299
|
if (!this.objRef.firstImageLoaded) {
|
300
|
this.objRef.firstImageLoaded = true;
|
301
|
var outputNode = document.getElementById( this.objRef.outputNodeId );
|
302
|
var siblingImageDivs = outputNode.childNodes;
|
303
|
for (var i=0; i<siblingImageDivs.length ;++i) {
|
304
|
var sibImg = siblingImageDivs[i].firstChild;
|
305
|
sibImg.parentNode.style.visibility = "hidden";
|
306
|
sibImg.style.visibility = "hidden";//Make sure for IE that the child node is hidden as well
|
307
|
if (_SARISSA_IS_IE) sibImg.src = config.skinDir+"/images/Spacer.gif";
|
308
|
}
|
309
|
if (_SARISSA_IS_IE) siblingImageDivs[0].firstChild.parentNode.parentNode.style.visibility = "hidden";
|
310
|
outputNode.style.left='0px';
|
311
|
outputNode.style.top='0px';
|
312
|
}
|
313
|
|
314
|
--this.objRef.layerCount;
|
315
|
if (this.objRef.layerCount > 0) {
|
316
|
var message = "loading " + this.objRef.layerCount + " map layers"
|
317
|
this.objRef.model.setParam("modelStatus", message);
|
318
|
} else {
|
319
|
this.objRef.model.setParam("modelStatus");
|
320
|
}
|
321
|
var legendText = document.getElementById( this.title + "_legendText" );
|
322
|
legendText.style.textDecoration = "none";
|
323
|
|
324
|
if (_SARISSA_IS_IE) oldImg.parentNode.parentNode.style.visibility = "visible";
|
325
|
if (this.fixPng) {
|
326
|
var vis = oldImg.layerHidden?"hidden":"visible";
|
327
|
oldImg.outerHTML = fixPNG(this,"real"+this.id);
|
328
|
if (!this.hidden) {
|
329
|
fixImg = document.getElementById("real"+this.id); // The result of fixPng is a span, so we need to set that particular element visible
|
330
|
fixImg.style.visibility = "visible"
|
331
|
}
|
332
|
} else {
|
333
|
oldImg.src = this.src;
|
334
|
oldImg.width = this.objRef.model.getWindowWidth();
|
335
|
oldImg.height = this.objRef.model.getWindowHeight();
|
336
|
if (!this.hidden) {
|
337
|
oldImg.parentNode.style.visibility = "visible";
|
338
|
oldImg.style.visibility = "visible"; //Make sure for IE that the child node is visible as well
|
339
|
}
|
340
|
}
|
341
|
}
|
342
|
|
343
|
function MapImgFailHandler() {
|
344
|
--this.objRef.layerCount;
|
345
|
if (this.objRef.layerCount > 0) {
|
346
|
var message = "loading " + this.objRef.layerCount + " map layer" + ((this.objRef.layerCount>1)?"s":"");
|
347
|
this.objRef.model.setParam("modelStatus", message);
|
348
|
} else {
|
349
|
this.objRef.model.setParam("modelStatus");
|
350
|
}
|
351
|
var legendText = document.getElementById( this.title + "_legendText" );
|
352
|
legendText.style.textDecoration = "line-through";
|
353
|
}
|
354
|
|
355
|
function MapImgErrorHandler() {
|
356
|
--this.objRef.layerCount;
|
357
|
if (this.objRef.layerCount > 0) {
|
358
|
var message = "loading " + this.objRef.layerCount + " map layer" + ((this.objRef.layerCount>1)?"s":"");
|
359
|
this.objRef.model.setParam("modelStatus", message);
|
360
|
} else {
|
361
|
this.objRef.model.setParam("modelStatus");
|
362
|
}
|
363
|
var legendText = document.getElementById( this.title + "_legendText" );
|
364
|
legendText.style.textDecoration = "line-through";
|
365
|
}
|
366
|
|