Project

General

Profile

Download (14.3 KB) Statistics
| Branch: | Tag: | Revision:
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
});
(3-3/31)