1
|
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
|
2
|
* full list of contributors). Published under the 2-clause BSD license.
|
3
|
* See license.txt in the OpenLayers distribution or repository for the
|
4
|
* full text of the license. */
|
5
|
|
6
|
/**
|
7
|
* @requires OpenLayers/Layer/Grid.js
|
8
|
* @requires OpenLayers/Format/ArcXML.js
|
9
|
* @requires OpenLayers/Request.js
|
10
|
*/
|
11
|
|
12
|
/**
|
13
|
* Class: OpenLayers.Layer.ArcIMS
|
14
|
* Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS
|
15
|
* Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS>
|
16
|
* constructor.
|
17
|
*
|
18
|
* Inherits from:
|
19
|
* - <OpenLayers.Layer.Grid>
|
20
|
*/
|
21
|
OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
|
22
|
|
23
|
/**
|
24
|
* Constant: DEFAULT_PARAMS
|
25
|
* {Object} Default query string parameters.
|
26
|
*/
|
27
|
DEFAULT_PARAMS: {
|
28
|
ClientVersion: "9.2",
|
29
|
ServiceName: ''
|
30
|
},
|
31
|
|
32
|
/**
|
33
|
* APIProperty: featureCoordSys
|
34
|
* {String} Code for feature coordinate system. Default is "4326".
|
35
|
*/
|
36
|
featureCoordSys: "4326",
|
37
|
|
38
|
/**
|
39
|
* APIProperty: filterCoordSys
|
40
|
* {String} Code for filter coordinate system. Default is "4326".
|
41
|
*/
|
42
|
filterCoordSys: "4326",
|
43
|
|
44
|
/**
|
45
|
* APIProperty: layers
|
46
|
* {Array} An array of objects with layer properties.
|
47
|
*/
|
48
|
layers: null,
|
49
|
|
50
|
/**
|
51
|
* APIProperty: async
|
52
|
* {Boolean} Request images asynchronously. Default is true.
|
53
|
*/
|
54
|
async: true,
|
55
|
|
56
|
/**
|
57
|
* APIProperty: name
|
58
|
* {String} Layer name. Default is "ArcIMS".
|
59
|
*/
|
60
|
name: "ArcIMS",
|
61
|
|
62
|
/**
|
63
|
* APIProperty: isBaseLayer
|
64
|
* {Boolean} The layer is a base layer. Default is true.
|
65
|
*/
|
66
|
isBaseLayer: true,
|
67
|
|
68
|
/**
|
69
|
* Constant: DEFAULT_OPTIONS
|
70
|
* {Object} Default layers properties.
|
71
|
*/
|
72
|
DEFAULT_OPTIONS: {
|
73
|
tileSize: new OpenLayers.Size(512, 512),
|
74
|
featureCoordSys: "4326",
|
75
|
filterCoordSys: "4326",
|
76
|
layers: null,
|
77
|
isBaseLayer: true,
|
78
|
async: true,
|
79
|
name: "ArcIMS"
|
80
|
},
|
81
|
|
82
|
/**
|
83
|
* Constructor: OpenLayers.Layer.ArcIMS
|
84
|
* Create a new ArcIMS layer object.
|
85
|
*
|
86
|
* Example:
|
87
|
* (code)
|
88
|
* var arcims = new OpenLayers.Layer.ArcIMS(
|
89
|
* "Global Sample",
|
90
|
* "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap",
|
91
|
* {
|
92
|
* service: "OpenLayers_Sample",
|
93
|
* layers: [
|
94
|
* // layers to manipulate
|
95
|
* {id: "1", visible: true}
|
96
|
* ]
|
97
|
* }
|
98
|
* );
|
99
|
* (end)
|
100
|
*
|
101
|
* Parameters:
|
102
|
* name - {String} A name for the layer
|
103
|
* url - {String} Base url for the ArcIMS server
|
104
|
* options - {Object} Optional object with properties to be set on the
|
105
|
* layer.
|
106
|
*/
|
107
|
initialize: function(name, url, options) {
|
108
|
|
109
|
this.tileSize = new OpenLayers.Size(512, 512);
|
110
|
|
111
|
// parameters
|
112
|
this.params = OpenLayers.Util.applyDefaults(
|
113
|
{ServiceName: options.serviceName},
|
114
|
this.DEFAULT_PARAMS
|
115
|
);
|
116
|
this.options = OpenLayers.Util.applyDefaults(
|
117
|
options, this.DEFAULT_OPTIONS
|
118
|
);
|
119
|
|
120
|
OpenLayers.Layer.Grid.prototype.initialize.apply(
|
121
|
this, [name, url, this.params, options]
|
122
|
);
|
123
|
|
124
|
//layer is transparent
|
125
|
if (this.transparent) {
|
126
|
|
127
|
// unless explicitly set in options, make layer an overlay
|
128
|
if (!this.isBaseLayer) {
|
129
|
this.isBaseLayer = false;
|
130
|
}
|
131
|
|
132
|
// jpegs can never be transparent, so intelligently switch the
|
133
|
// format, depending on the browser's capabilities
|
134
|
if (this.format == "image/jpeg") {
|
135
|
this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png";
|
136
|
}
|
137
|
}
|
138
|
|
139
|
// create an empty layer list if no layers specified in the options
|
140
|
if (this.options.layers === null) {
|
141
|
this.options.layers = [];
|
142
|
}
|
143
|
},
|
144
|
|
145
|
/**
|
146
|
* Method: getURL
|
147
|
* Return an image url this layer.
|
148
|
*
|
149
|
* Parameters:
|
150
|
* bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
|
151
|
* request.
|
152
|
*
|
153
|
* Returns:
|
154
|
* {String} A string with the map image's url.
|
155
|
*/
|
156
|
getURL: function(bounds) {
|
157
|
var url = "";
|
158
|
bounds = this.adjustBounds(bounds);
|
159
|
|
160
|
// create an arcxml request to generate the image
|
161
|
var axlReq = new OpenLayers.Format.ArcXML(
|
162
|
OpenLayers.Util.extend(this.options, {
|
163
|
requesttype: "image",
|
164
|
envelope: bounds.toArray(),
|
165
|
tileSize: this.tileSize
|
166
|
})
|
167
|
);
|
168
|
|
169
|
// create a synchronous ajax request to get an arcims image
|
170
|
var req = new OpenLayers.Request.POST({
|
171
|
url: this.getFullRequestString(),
|
172
|
data: axlReq.write(),
|
173
|
async: false
|
174
|
});
|
175
|
|
176
|
// if the response exists
|
177
|
if (req != null) {
|
178
|
var doc = req.responseXML;
|
179
|
|
180
|
if (!doc || !doc.documentElement) {
|
181
|
doc = req.responseText;
|
182
|
}
|
183
|
|
184
|
// create a new arcxml format to read the response
|
185
|
var axlResp = new OpenLayers.Format.ArcXML();
|
186
|
var arcxml = axlResp.read(doc);
|
187
|
url = this.getUrlOrImage(arcxml.image.output);
|
188
|
}
|
189
|
|
190
|
return url;
|
191
|
},
|
192
|
|
193
|
|
194
|
/**
|
195
|
* Method: getURLasync
|
196
|
* Get an image url this layer asynchronously, and execute a callback
|
197
|
* when the image url is generated.
|
198
|
*
|
199
|
* Parameters:
|
200
|
* bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
|
201
|
* request.
|
202
|
* callback - {Function} Function to call when image url is retrieved.
|
203
|
* scope - {Object} The scope of the callback method.
|
204
|
*/
|
205
|
getURLasync: function(bounds, callback, scope) {
|
206
|
bounds = this.adjustBounds(bounds);
|
207
|
|
208
|
// create an arcxml request to generate the image
|
209
|
var axlReq = new OpenLayers.Format.ArcXML(
|
210
|
OpenLayers.Util.extend(this.options, {
|
211
|
requesttype: "image",
|
212
|
envelope: bounds.toArray(),
|
213
|
tileSize: this.tileSize
|
214
|
})
|
215
|
);
|
216
|
|
217
|
// create an asynchronous ajax request to get an arcims image
|
218
|
OpenLayers.Request.POST({
|
219
|
url: this.getFullRequestString(),
|
220
|
async: true,
|
221
|
data: axlReq.write(),
|
222
|
callback: function(req) {
|
223
|
// process the response from ArcIMS, and call the callback function
|
224
|
// to set the image URL
|
225
|
var doc = req.responseXML;
|
226
|
if (!doc || !doc.documentElement) {
|
227
|
doc = req.responseText;
|
228
|
}
|
229
|
|
230
|
// create a new arcxml format to read the response
|
231
|
var axlResp = new OpenLayers.Format.ArcXML();
|
232
|
var arcxml = axlResp.read(doc);
|
233
|
|
234
|
callback.call(scope, this.getUrlOrImage(arcxml.image.output));
|
235
|
},
|
236
|
scope: this
|
237
|
});
|
238
|
},
|
239
|
|
240
|
/**
|
241
|
* Method: getUrlOrImage
|
242
|
* Extract a url or image from the ArcXML image output.
|
243
|
*
|
244
|
* Parameters:
|
245
|
* output - {Object} The image.output property of the object returned from
|
246
|
* the ArcXML format read method.
|
247
|
*
|
248
|
* Returns:
|
249
|
* {String} A URL for an image (potentially with the data protocol).
|
250
|
*/
|
251
|
getUrlOrImage: function(output) {
|
252
|
var ret = "";
|
253
|
if(output.url) {
|
254
|
// If the image response output url is a string, then the image
|
255
|
// data is not inline.
|
256
|
ret = output.url;
|
257
|
} else if(output.data) {
|
258
|
// The image data is inline and base64 encoded, create a data
|
259
|
// url for the image. This will only work for small images,
|
260
|
// due to browser url length limits.
|
261
|
ret = "data:image/" + output.type +
|
262
|
";base64," + output.data;
|
263
|
}
|
264
|
return ret;
|
265
|
},
|
266
|
|
267
|
/**
|
268
|
* Method: setLayerQuery
|
269
|
* Set the query definition on this layer. Query definitions are used to
|
270
|
* render parts of the spatial data in an image, and can be used to
|
271
|
* filter features or layers in the ArcIMS service.
|
272
|
*
|
273
|
* Parameters:
|
274
|
* id - {String} The ArcIMS layer ID.
|
275
|
* querydef - {Object} The query definition to apply to this layer.
|
276
|
*/
|
277
|
setLayerQuery: function(id, querydef) {
|
278
|
// find the matching layer, if it exists
|
279
|
for (var lyr = 0; lyr < this.options.layers.length; lyr++) {
|
280
|
if (id == this.options.layers[lyr].id) {
|
281
|
// replace this layer definition
|
282
|
this.options.layers[lyr].query = querydef;
|
283
|
return;
|
284
|
}
|
285
|
}
|
286
|
|
287
|
// no layer found, create a new definition
|
288
|
this.options.layers.push({id: id, visible: true, query: querydef});
|
289
|
},
|
290
|
|
291
|
/**
|
292
|
* Method: getFeatureInfo
|
293
|
* Get feature information from ArcIMS. Using the applied geometry, apply
|
294
|
* the options to the query (buffer, area/envelope intersection), and
|
295
|
* query the ArcIMS service.
|
296
|
*
|
297
|
* A note about accuracy:
|
298
|
* ArcIMS interprets the accuracy attribute in feature requests to be
|
299
|
* something like the 'modulus' operator on feature coordinates,
|
300
|
* applied to the database geometry of the feature. It doesn't round,
|
301
|
* so your feature coordinates may be up to (1 x accuracy) offset from
|
302
|
* the actual feature coordinates. If the accuracy of the layer is not
|
303
|
* specified, the accuracy will be computed to be approximately 1
|
304
|
* feature coordinate per screen pixel.
|
305
|
*
|
306
|
* Parameters:
|
307
|
* geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The
|
308
|
* geometry to use when making the query. This should be a closed
|
309
|
* polygon for behavior approximating a free selection.
|
310
|
* layer - {Object} The ArcIMS layer definition. This is an anonymous object
|
311
|
* that looks like:
|
312
|
* (code)
|
313
|
* {
|
314
|
* id: "ArcXML layer ID", // the ArcXML layer ID
|
315
|
* query: {
|
316
|
* where: "STATE = 'PA'", // the where clause of the query
|
317
|
* accuracy: 100 // the accuracy of the returned feature
|
318
|
* }
|
319
|
* }
|
320
|
* (end)
|
321
|
* options - {Object} Object with non-default properties to set on the layer.
|
322
|
* Supported properties are buffer, callback, scope, and any other
|
323
|
* properties applicable to the ArcXML format. Set the 'callback' and
|
324
|
* 'scope' for an object and function to recieve the parsed features
|
325
|
* from ArcIMS.
|
326
|
*/
|
327
|
getFeatureInfo: function(geometry, layer, options) {
|
328
|
// set the buffer to 1 unit (dd/m/ft?) by default
|
329
|
var buffer = options.buffer || 1;
|
330
|
// empty callback by default
|
331
|
var callback = options.callback || function() {};
|
332
|
// default scope is window (global)
|
333
|
var scope = options.scope || window;
|
334
|
|
335
|
// apply these option to the request options
|
336
|
var requestOptions = {};
|
337
|
OpenLayers.Util.extend(requestOptions, this.options);
|
338
|
|
339
|
// this is a feature request
|
340
|
requestOptions.requesttype = "feature";
|
341
|
|
342
|
if (geometry instanceof OpenLayers.LonLat) {
|
343
|
// create an envelope if the geometry is really a lon/lat
|
344
|
requestOptions.polygon = null;
|
345
|
requestOptions.envelope = [
|
346
|
geometry.lon - buffer,
|
347
|
geometry.lat - buffer,
|
348
|
geometry.lon + buffer,
|
349
|
geometry.lat + buffer
|
350
|
];
|
351
|
} else if (geometry instanceof OpenLayers.Geometry.Polygon) {
|
352
|
// use the polygon assigned, and empty the envelope
|
353
|
requestOptions.envelope = null;
|
354
|
requestOptions.polygon = geometry;
|
355
|
}
|
356
|
|
357
|
// create an arcxml request to get feature requests
|
358
|
var arcxml = new OpenLayers.Format.ArcXML(requestOptions);
|
359
|
|
360
|
// apply any get feature options to the arcxml request
|
361
|
OpenLayers.Util.extend(arcxml.request.get_feature, options);
|
362
|
|
363
|
arcxml.request.get_feature.layer = layer.id;
|
364
|
if (typeof layer.query.accuracy == "number") {
|
365
|
// set the accuracy if it was specified
|
366
|
arcxml.request.get_feature.query.accuracy = layer.query.accuracy;
|
367
|
} else {
|
368
|
// guess that the accuracy is 1 per screen pixel
|
369
|
var mapCenter = this.map.getCenter();
|
370
|
var viewPx = this.map.getViewPortPxFromLonLat(mapCenter);
|
371
|
viewPx.x++;
|
372
|
var mapOffCenter = this.map.getLonLatFromPixel(viewPx);
|
373
|
arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon;
|
374
|
}
|
375
|
|
376
|
// set the get_feature query to be the same as the layer passed in
|
377
|
arcxml.request.get_feature.query.where = layer.query.where;
|
378
|
|
379
|
// use area_intersection
|
380
|
arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection";
|
381
|
|
382
|
// create a new asynchronous request to get the feature info
|
383
|
OpenLayers.Request.POST({
|
384
|
url: this.getFullRequestString({'CustomService': 'Query'}),
|
385
|
data: arcxml.write(),
|
386
|
callback: function(request) {
|
387
|
// parse the arcxml response
|
388
|
var response = arcxml.parseResponse(request.responseText);
|
389
|
|
390
|
if (!arcxml.iserror()) {
|
391
|
// if the arcxml is not an error, call the callback with the features parsed
|
392
|
callback.call(scope, response.features);
|
393
|
} else {
|
394
|
// if the arcxml is an error, return null features selected
|
395
|
callback.call(scope, null);
|
396
|
}
|
397
|
}
|
398
|
});
|
399
|
},
|
400
|
|
401
|
/**
|
402
|
* Method: clone
|
403
|
* Create a clone of this layer
|
404
|
*
|
405
|
* Returns:
|
406
|
* {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer
|
407
|
*/
|
408
|
clone: function (obj) {
|
409
|
|
410
|
if (obj == null) {
|
411
|
obj = new OpenLayers.Layer.ArcIMS(this.name,
|
412
|
this.url,
|
413
|
this.getOptions());
|
414
|
}
|
415
|
|
416
|
//get all additions from superclasses
|
417
|
obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
|
418
|
|
419
|
// copy/set any non-init, non-simple values here
|
420
|
|
421
|
return obj;
|
422
|
},
|
423
|
|
424
|
CLASS_NAME: "OpenLayers.Layer.ArcIMS"
|
425
|
});
|