git-svn-id: http://svn.openlayers.org/trunk/openlayers@11575 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
450 lines
15 KiB
JavaScript
450 lines
15 KiB
JavaScript
/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
|
|
* full list of contributors). Published under the Clear BSD license.
|
|
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
|
* full text of the license. */
|
|
|
|
/**
|
|
* @requires OpenLayers/Layer/Grid.js
|
|
* @requires OpenLayers/Tile/Image.js
|
|
* @requires OpenLayers/Format/ArcXML.js
|
|
* @requires OpenLayers/Request.js
|
|
*/
|
|
|
|
/**
|
|
* Class: OpenLayers.Layer.ArcIMS
|
|
* Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS
|
|
* Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS>
|
|
* constructor.
|
|
*
|
|
* Inherits from:
|
|
* - <OpenLayers.Layer.Grid>
|
|
*/
|
|
OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
|
|
|
|
/**
|
|
* Constant: DEFAULT_PARAMS
|
|
* {Object} Default query string parameters.
|
|
*/
|
|
DEFAULT_PARAMS: {
|
|
ClientVersion: "9.2",
|
|
ServiceName: ''
|
|
},
|
|
|
|
/**
|
|
* APIProperty: tileSize
|
|
* {<OpenLayers.Size>} Size for tiles. Default is 512x512.
|
|
*/
|
|
tileSize: null,
|
|
|
|
/**
|
|
* APIProperty: featureCoordSys
|
|
* {String} Code for feature coordinate system. Default is "4326".
|
|
*/
|
|
featureCoordSys: "4326",
|
|
|
|
/**
|
|
* APIProperty: filterCoordSys
|
|
* {String} Code for filter coordinate system. Default is "4326".
|
|
*/
|
|
filterCoordSys: "4326",
|
|
|
|
/**
|
|
* APIProperty: layers
|
|
* {Array} An array of objects with layer properties.
|
|
*/
|
|
layers: null,
|
|
|
|
/**
|
|
* APIProperty: async
|
|
* {Boolean} Request images asynchronously. Default is true.
|
|
*/
|
|
async: true,
|
|
|
|
/**
|
|
* APIProperty: name
|
|
* {String} Layer name. Default is "ArcIMS".
|
|
*/
|
|
name: "ArcIMS",
|
|
|
|
/**
|
|
* APIProperty: isBaseLayer
|
|
* {Boolean} The layer is a base layer. Default is true.
|
|
*/
|
|
isBaseLayer: true,
|
|
|
|
/**
|
|
* Constant: DEFAULT_OPTIONS
|
|
* {Object} Default layers properties.
|
|
*/
|
|
DEFAULT_OPTIONS: {
|
|
tileSize: new OpenLayers.Size(512, 512),
|
|
featureCoordSys: "4326",
|
|
filterCoordSys: "4326",
|
|
layers: null,
|
|
isBaseLayer: true,
|
|
async: true,
|
|
name: "ArcIMS"
|
|
},
|
|
|
|
/**
|
|
* Constructor: OpenLayers.Layer.ArcIMS
|
|
* Create a new ArcIMS layer object.
|
|
*
|
|
* Example:
|
|
* (code)
|
|
* var arcims = new OpenLayers.Layer.ArcIMS(
|
|
* "Global Sample",
|
|
* "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap",
|
|
* {
|
|
* service: "OpenLayers_Sample",
|
|
* layers: [
|
|
* // layers to manipulate
|
|
* {id: "1", visible: true}
|
|
* ]
|
|
* }
|
|
* );
|
|
* (end)
|
|
*
|
|
* Parameters:
|
|
* name - {String} A name for the layer
|
|
* url - {String} Base url for the ArcIMS server
|
|
* options - {Object} Optional object with properties to be set on the
|
|
* layer.
|
|
*/
|
|
initialize: function(name, url, options) {
|
|
|
|
this.tileSize = new OpenLayers.Size(512, 512);
|
|
|
|
// parameters
|
|
this.params = OpenLayers.Util.applyDefaults(
|
|
{ServiceName: options.serviceName},
|
|
this.DEFAULT_PARAMS
|
|
);
|
|
this.options = OpenLayers.Util.applyDefaults(
|
|
options, this.DEFAULT_OPTIONS
|
|
);
|
|
|
|
OpenLayers.Layer.Grid.prototype.initialize.apply(
|
|
this, [name, url, this.params, options]
|
|
);
|
|
|
|
//layer is transparent
|
|
if (this.transparent) {
|
|
|
|
// unless explicitly set in options, make layer an overlay
|
|
if (!this.isBaseLayer) {
|
|
this.isBaseLayer = false;
|
|
}
|
|
|
|
// jpegs can never be transparent, so intelligently switch the
|
|
// format, depending on the browser's capabilities
|
|
if (this.format == "image/jpeg") {
|
|
this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png";
|
|
}
|
|
}
|
|
|
|
// create an empty layer list if no layers specified in the options
|
|
if (this.options.layers === null) {
|
|
this.options.layers = [];
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Method: destroy
|
|
* Destroy this layer
|
|
*/
|
|
destroy: function() {
|
|
// for now, nothing special to do here.
|
|
OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
|
|
},
|
|
|
|
|
|
/**
|
|
* Method: getURL
|
|
* Return an image url this layer.
|
|
*
|
|
* Parameters:
|
|
* bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
|
|
* request.
|
|
*
|
|
* Returns:
|
|
* {String} A string with the map image's url.
|
|
*/
|
|
getURL: function(bounds) {
|
|
var url = "";
|
|
bounds = this.adjustBounds(bounds);
|
|
|
|
// create an arcxml request to generate the image
|
|
var axlReq = new OpenLayers.Format.ArcXML(
|
|
OpenLayers.Util.extend(this.options, {
|
|
requesttype: "image",
|
|
envelope: bounds.toArray(),
|
|
tileSize: this.tileSize
|
|
})
|
|
);
|
|
|
|
// create a synchronous ajax request to get an arcims image
|
|
var req = new OpenLayers.Request.POST({
|
|
url: this.getFullRequestString(),
|
|
data: axlReq.write(),
|
|
async: false
|
|
});
|
|
|
|
// if the response exists
|
|
if (req != null) {
|
|
var doc = req.responseXML;
|
|
|
|
if (!doc || !doc.documentElement) {
|
|
doc = req.responseText;
|
|
}
|
|
|
|
// create a new arcxml format to read the response
|
|
var axlResp = new OpenLayers.Format.ArcXML();
|
|
var arcxml = axlResp.read(doc);
|
|
url = this.getUrlOrImage(arcxml.image.output);
|
|
}
|
|
|
|
return url;
|
|
},
|
|
|
|
|
|
/**
|
|
* Method: getURLasync
|
|
* Get an image url this layer asynchronously, and execute a callback
|
|
* when the image url is generated.
|
|
*
|
|
* Parameters:
|
|
* bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
|
|
* request.
|
|
* scope - {Object} The scope of the callback method.
|
|
* prop - {String} The name of the property in the scoped object to
|
|
* recieve the image url.
|
|
* callback - {Function} Function to call when image url is retrieved.
|
|
*/
|
|
getURLasync: function(bounds, scope, prop, callback) {
|
|
bounds = this.adjustBounds(bounds);
|
|
|
|
// create an arcxml request to generate the image
|
|
var axlReq = new OpenLayers.Format.ArcXML(
|
|
OpenLayers.Util.extend(this.options, {
|
|
requesttype: "image",
|
|
envelope: bounds.toArray(),
|
|
tileSize: this.tileSize
|
|
})
|
|
);
|
|
|
|
// create an asynchronous ajax request to get an arcims image
|
|
OpenLayers.Request.POST({
|
|
url: this.getFullRequestString(),
|
|
async: true,
|
|
data: axlReq.write(),
|
|
callback: function(req) {
|
|
// process the response from ArcIMS, and call the callback function
|
|
// to set the image URL
|
|
var doc = req.responseXML;
|
|
if (!doc || !doc.documentElement) {
|
|
doc = req.responseText;
|
|
}
|
|
|
|
// create a new arcxml format to read the response
|
|
var axlResp = new OpenLayers.Format.ArcXML();
|
|
var arcxml = axlResp.read(doc);
|
|
|
|
scope[prop] = this.getUrlOrImage(arcxml.image.output);
|
|
|
|
// call the callback function to recieve the updated property on the
|
|
// scoped object
|
|
callback.apply(scope);
|
|
},
|
|
scope: this
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Method: getUrlOrImage
|
|
* Extract a url or image from the ArcXML image output.
|
|
*
|
|
* Parameters:
|
|
* output - {Object} The image.output property of the object returned from
|
|
* the ArcXML format read method.
|
|
*
|
|
* Returns:
|
|
* {String} A URL for an image (potentially with the data protocol).
|
|
*/
|
|
getUrlOrImage: function(output) {
|
|
var ret = "";
|
|
if(output.url) {
|
|
// If the image response output url is a string, then the image
|
|
// data is not inline.
|
|
ret = output.url;
|
|
} else if(output.data) {
|
|
// The image data is inline and base64 encoded, create a data
|
|
// url for the image. This will only work for small images,
|
|
// due to browser url length limits.
|
|
ret = "data:image/" + output.type +
|
|
";base64," + output.data;
|
|
}
|
|
return ret;
|
|
},
|
|
|
|
/**
|
|
* Method: setLayerQuery
|
|
* Set the query definition on this layer. Query definitions are used to
|
|
* render parts of the spatial data in an image, and can be used to
|
|
* filter features or layers in the ArcIMS service.
|
|
*
|
|
* Parameters:
|
|
* id - {String} The ArcIMS layer ID.
|
|
* queryDef - {Object} The query definition to apply to this layer.
|
|
*/
|
|
setLayerQuery: function(id, querydef) {
|
|
// find the matching layer, if it exists
|
|
for (var lyr = 0; lyr < this.options.layers.length; lyr++) {
|
|
if (id == this.options.layers[lyr].id) {
|
|
// replace this layer definition
|
|
this.options.layers[lyr].query = querydef;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// no layer found, create a new definition
|
|
this.options.layers.push({id: id, visible: true, query: querydef});
|
|
},
|
|
|
|
/**
|
|
* Method: getFeatureInfo
|
|
* Get feature information from ArcIMS. Using the applied geometry, apply
|
|
* the options to the query (buffer, area/envelope intersection), and
|
|
* query the ArcIMS service.
|
|
*
|
|
* A note about accuracy:
|
|
* ArcIMS interprets the accuracy attribute in feature requests to be
|
|
* something like the 'modulus' operator on feature coordinates,
|
|
* applied to the database geometry of the feature. It doesn't round,
|
|
* so your feature coordinates may be up to (1 x accuracy) offset from
|
|
* the actual feature coordinates. If the accuracy of the layer is not
|
|
* specified, the accuracy will be computed to be approximately 1
|
|
* feature coordinate per screen pixel.
|
|
*
|
|
* Parameters:
|
|
* geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The
|
|
* geometry to use when making the query. This should be a closed
|
|
* polygon for behavior approximating a free selection.
|
|
* layer - {Object} The ArcIMS layer definition. This is an anonymous object
|
|
* that looks like:
|
|
* (code)
|
|
* {
|
|
* id: "ArcXML layer ID", // the ArcXML layer ID
|
|
* query: {
|
|
* where: "STATE = 'PA'", // the where clause of the query
|
|
* accuracy: 100 // the accuracy of the returned feature
|
|
* }
|
|
* }
|
|
* (end)
|
|
* options - {Object} Object with non-default properties to set on the layer.
|
|
* Supported properties are buffer, callback, scope, and any other
|
|
* properties applicable to the ArcXML format. Set the 'callback' and
|
|
* 'scope' for an object and function to recieve the parsed features
|
|
* from ArcIMS.
|
|
*/
|
|
getFeatureInfo: function(geometry, layer, options) {
|
|
// set the buffer to 1 unit (dd/m/ft?) by default
|
|
var buffer = options.buffer || 1;
|
|
// empty callback by default
|
|
var callback = options.callback || function() {};
|
|
// default scope is window (global)
|
|
var scope = options.scope || window;
|
|
|
|
// apply these option to the request options
|
|
var requestOptions = {};
|
|
OpenLayers.Util.extend(requestOptions, this.options);
|
|
|
|
// this is a feature request
|
|
requestOptions.requesttype = "feature";
|
|
|
|
if (geometry instanceof OpenLayers.LonLat) {
|
|
// create an envelope if the geometry is really a lon/lat
|
|
requestOptions.polygon = null;
|
|
requestOptions.envelope = [
|
|
geometry.lon - buffer,
|
|
geometry.lat - buffer,
|
|
geometry.lon + buffer,
|
|
geometry.lat + buffer
|
|
];
|
|
} else if (geometry instanceof OpenLayers.Geometry.Polygon) {
|
|
// use the polygon assigned, and empty the envelope
|
|
requestOptions.envelope = null;
|
|
requestOptions.polygon = geometry;
|
|
}
|
|
|
|
// create an arcxml request to get feature requests
|
|
var arcxml = new OpenLayers.Format.ArcXML(requestOptions);
|
|
|
|
// apply any get feature options to the arcxml request
|
|
OpenLayers.Util.extend(arcxml.request.get_feature, options);
|
|
|
|
arcxml.request.get_feature.layer = layer.id;
|
|
if (typeof layer.query.accuracy == "number") {
|
|
// set the accuracy if it was specified
|
|
arcxml.request.get_feature.query.accuracy = layer.query.accuracy;
|
|
} else {
|
|
// guess that the accuracy is 1 per screen pixel
|
|
var mapCenter = this.map.getCenter();
|
|
var viewPx = this.map.getViewPortPxFromLonLat(mapCenter);
|
|
viewPx.x++;
|
|
var mapOffCenter = this.map.getLonLatFromPixel(viewPx);
|
|
arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon;
|
|
}
|
|
|
|
// set the get_feature query to be the same as the layer passed in
|
|
arcxml.request.get_feature.query.where = layer.query.where;
|
|
|
|
// use area_intersection
|
|
arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection";
|
|
|
|
// create a new asynchronous request to get the feature info
|
|
OpenLayers.Request.POST({
|
|
url: this.getFullRequestString({'CustomService': 'Query'}),
|
|
data: arcxml.write(),
|
|
callback: function(request) {
|
|
// parse the arcxml response
|
|
var response = arcxml.parseResponse(request.responseText);
|
|
|
|
if (!arcxml.iserror()) {
|
|
// if the arcxml is not an error, call the callback with the features parsed
|
|
callback.call(scope, response.features);
|
|
} else {
|
|
// if the arcxml is an error, return null features selected
|
|
callback.call(scope, null);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Method: clone
|
|
* Create a clone of this layer
|
|
*
|
|
* Returns:
|
|
* {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer
|
|
*/
|
|
clone: function (obj) {
|
|
|
|
if (obj == null) {
|
|
obj = new OpenLayers.Layer.ArcIMS(this.name,
|
|
this.url,
|
|
this.getOptions());
|
|
}
|
|
|
|
//get all additions from superclasses
|
|
obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
|
|
|
|
// copy/set any non-init, non-simple values here
|
|
|
|
return obj;
|
|
},
|
|
|
|
CLASS_NAME: "OpenLayers.Layer.ArcIMS"
|
|
});
|