PageRenderTime 39ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/google/maps/extras/arcgislink/MapService.as

http://gmaps-utility-library-flash.googlecode.com/
ActionScript | 429 lines | 271 code | 43 blank | 115 comment | 69 complexity | 6dbad68d13169ec144390ea5eb5d473d MD5 | raw file
  1. /*
  2. * ArcGIS for Google Maps Flash API
  3. *
  4. * License http://www.apache.org/licenses/LICENSE-2.0
  5. */
  6. /**
  7. * @author nianwei at gmail dot com
  8. */
  9. package com.google.maps.extras.arcgislink {
  10. import com.google.maps.*;
  11. import flash.events.*;
  12. /**
  13. * This class is the core class for all map service operations.
  14. * It represents an Server map service and serve as the underline resource
  15. * represented by ArcGISTileLayer and ArcGISMapOverlay.
  16. * It is constructed asynchronously so it should be used <b>after</b>
  17. * it is loaded, either by handle its "load" event, or used in a callback function
  18. * passed in the constructor.
  19. * <br/>For more info see <a href = 'http://resources.esri.com/help/9.3/arcgisserver/apis/rest/mapserver.html'>Map Service</a>
  20. * <p>Creates a ArcGISMapService objects that can be used by UI components.
  21. * <ul><li> <code> url</code> (required) is the URL of the map servive, e.g. <code>
  22. * http://server.arcgisonline.com//rest/services/ESRI_StreetMap_World_2D/MapServer</code>.
  23. * <li> <code>opt_service</code> optional parameter of type ArcGISMapServiceOptions
  24. * <ul/> Note the spatial reference of the map service must already exists
  25. * in the ArcGISSpatialReferences if actual coordinates transformation is needed.
  26. * @name ArcGISMapService
  27. * @class @param {String} url
  28. * @param {ArcGISMapServiceOptions} opt_service
  29. * @property {String} [url] map service URL
  30. * @property {String} [name] map service Name, taken as part of URL.
  31. * @property {String} [serviceDescription] serviceDescription
  32. * @property {String} [mapName] map frame Name inside the map document
  33. * @property {String} [description] description
  34. * @property {String} [copyrightText] copyrightText
  35. * @property {Boolean} [singleFusedMapCache] if map cache is singleFused
  36. * @property {TileInfo} [tileInfo] See {@link ArcGISTileInfo}
  37. * @property {Envelope} [initialExtent] initialExtent, see {@link ArcGISEnvelope}
  38. * @property {Envelope} [fullExtent] fullExtent, see {@link ArcGISEnvelope}
  39. * @property {String} [units] unit
  40. * @property {Object} [documentInfo] Object with the folloing properties: <code>Title, Author,Comments,Subject,Category,Keywords</code>
  41. */
  42. public dynamic class MapService implements IEventDispatcher {
  43. public var url:String;
  44. public var name:String;
  45. public var copyrightText:String;
  46. public var documentInfo:*;
  47. public var fullExtent:*; // maybe should be envelope, but object literal for now
  48. public var initialExtent:*;
  49. public var mapName:String;
  50. public var serviceDescription:String;
  51. public var singleFusedMapCache:Boolean;
  52. public var units:String;
  53. private var loaded_:Boolean;
  54. private var correct_:Boolean;
  55. public function MapService(url:String, opt_service:MapServiceOptions=null) {
  56. dispatcher_=new EventDispatcher(this);
  57. opt_service=opt_service || new MapServiceOptions();
  58. this.url=url;
  59. var tks:Array=url.split("/");
  60. this.name=opt_service.name || tks[tks.length - 2].replace(/_/g, ' ');
  61. var me:MapService=this;
  62. this.loaded_=false;
  63. this.correct_=false;
  64. ArcGISUtil.restRequest(url, {f: 'json'}, this, function(json:Object):void {
  65. me.init_(json, opt_service);
  66. });
  67. }
  68. /**
  69. * initialize an Map Service from the meta data information.
  70. * The <code>json</code> parameter is the json object returned by Map Service.
  71. * @private
  72. * @param {Object} json
  73. * @param {ArcGISMapServiceOptions} opt_service
  74. */
  75. public function init_(json:Object, opt_service:Object):void {
  76. var me:MapService=this;
  77. function doneLoad(json:Object):void {
  78. me.loaded_=true;
  79. for (var i:int=0, c:int=me.layers_.length; i < c; i++) {
  80. var layer:Layer=me.layers_[i];
  81. if (layer.subLayerIds) {
  82. layer.subLayers=[];
  83. for (var j:int=0, jc:int=layer.subLayerIds.length; j < jc; j++) {
  84. var subLayer:Layer=me.getLayer(layer.subLayerIds[j]);
  85. layer.subLayers.push(subLayer);
  86. subLayer.parentLayer=layer;
  87. }
  88. }
  89. }
  90. // some bad services will have an initial extent outside fullextent;
  91. me.initialExtent.xmin=Math.max(me.initialExtent.xmin, me.fullExtent.xmin);
  92. me.initialExtent.ymin=Math.max(me.initialExtent.ymin, me.fullExtent.ymin);
  93. me.initialExtent.xmax=Math.min(me.initialExtent.xmax, me.fullExtent.xmax);
  94. me.initialExtent.ymax=Math.min(me.initialExtent.ymax, me.fullExtent.ymax);
  95. /**
  96. * This event is fired when the service and it's service info is loaded.
  97. * @name ArcGISMapService#load
  98. * @param {ArcGISMapService} service
  99. * @event
  100. */
  101. me.dispatchEvent(new ServiceEvent(ServiceEvent.LOAD, me));
  102. }
  103. if (json.error) {
  104. this.correct_=false;
  105. } else {
  106. this.correct_=true;
  107. ArcGISUtil.augmentObject(json, this);
  108. var layers:Array=[];
  109. var ids:Array=[];
  110. for (var i:int=0, c:int=json.layers.length; i < c; i++) {
  111. var info:Object=json.layers[i];
  112. var layer:Layer=new Layer(this.url + '/' + info.id, new LayerOptions({initLoad: false}));
  113. ArcGISUtil.augmentObject(info, layer);
  114. layer.visible=info.defaultVisibility;
  115. layers.push(layer);
  116. ids.push(info.id);
  117. }
  118. this.layers_=layers;
  119. delete this.layers;
  120. this.spatialReference_=SpatialReferences.getSpatialReference(json.spatialReference.wkid);
  121. if (!this.spatialReference_) {
  122. var bbox:*=json.fullExtent;
  123. var params:* = {f: 'json', bbox: '' + bbox.xmin + ',' + bbox.ymin + ',' + bbox.xmax + ',' + bbox.ymax, size: '1,1', imageSR: 4326, layers: 'hide:' + ids.join(',')};
  124. if (json.spatialReference.wkid){
  125. params.bboxSR = json.spatialReference.wkid;
  126. }
  127. ArcGISUtil.restRequest(this.url + '/export', params, this, function(image:*):void {
  128. var sr:FlatSpatialReference=new FlatSpatialReference({wkid: json.spatialReference.wkid, latlng: image.extent, coords: json.fullExtent});
  129. SpatialReferences.addSpatialReference(json.spatialReference.wkid, sr);
  130. me.spatialReference_=sr;
  131. doneLoad(json);
  132. });
  133. } else {
  134. doneLoad(json);
  135. }
  136. }
  137. }
  138. ;
  139. /**
  140. * If this map service has finished loading from server.
  141. * @return {Boolean}
  142. */
  143. public function hasLoaded():Boolean {
  144. return this.loaded_;
  145. }
  146. /**
  147. * Get the Spatial Reference of this map service that can convert between LatLng and Coordinates
  148. * Note, if the actual spatial reference is not aleady added via {@link ArcGISSpatialReferences}, it will return an object literal with <b>wkid info only</b>.
  149. * @return {ArcGISSpatialReference}
  150. */
  151. public function getSpatialReference():SpatialReference {
  152. return this.spatialReference_;
  153. }
  154. /**
  155. * Get the Array of {@link ArcGISLayer}[] for this map service
  156. * @return {Layer[]}
  157. */
  158. public function getLayers():Array {
  159. return this.layers_;
  160. }
  161. /**
  162. * Get a map layer by it's name(String) or id (Number), return {@link ArcGISLayer}.
  163. * @param {String|Number} nameOrId
  164. * @return {Layer}
  165. */
  166. public function getLayer(nameOrId:Object):Layer {
  167. var layers:Array=this.layers_;
  168. if (layers) {
  169. for (var i:int=0, c:int=layers.length; i < c; i++) {
  170. if (nameOrId === layers[i].id) {
  171. return layers[i];
  172. }
  173. if (nameOrId is String && layers[i].name.toLowerCase() === nameOrId.toLowerCase()) {
  174. return layers[i];
  175. }
  176. }
  177. }
  178. return null;
  179. }
  180. /**
  181. * Get layer id or array of ids from a layer name or array of names.
  182. * @param {String|String[]} names
  183. * @return {Number|Number[]}
  184. */
  185. public function getLayerIdsByName(names:Array):Array {
  186. var layer:Layer;
  187. var ids:Array=[];
  188. for (var i:int=0, c:int=names.length; i < c; i++) {
  189. layer=this.getLayer(names[i]);
  190. ids.push(layer ? layer.id : -1);
  191. }
  192. return ids;
  193. }
  194. /**
  195. * Export an image with given parameters.
  196. * For more info see <a href = 'http://resources.esri.com/help/9.3/arcgisserver/apis/rest/export.html'>Export Operation</a>.
  197. * <br/> The <code>params</code> is an instance of {@link ArcGISExportMapParameters}.
  198. * The following properties will be set automatically if not specified:...
  199. * <br/> The <code>callback</code> is the callback function with argument of
  200. * an instance of {@link ArcGISMapImage}.
  201. * @param {ExportMapOptions} params
  202. * @param {Function} callback
  203. */
  204. public function exportMap(params:ImageParameters, callbackFn:Function=null, failedFn:Function=null):void {
  205. if (!params) {
  206. return;
  207. }
  208. // note: dynamic map may overlay on top of maptypes with different projection
  209. var ps:*={f: params.f, size: '' + params.width + ',' + params.height, dpi: params.dpi || 96, format: params.format||ArcGISConstants.IMAGE_FORMAT_PNG, transparent: params.transparent === false ? false : true};
  210. var sr:SpatialReference=params.imageSpatialReference || SpatialReferences.WEB_MERCATOR;
  211. // although AGS support different imageSR & bboxSR, we only use one here.
  212. ps.imageSR=sr.wkid;
  213. var inSr:SpatialReference=sr; //SpatialReferences.WGS84
  214. ps.bboxSR=inSr.wkid; //sr.wkid;
  215. var bbox:*=ArcGISUtil.fromLatLngBoundsToEnvelope(params.bounds, inSr);
  216. ps.bbox='' + bbox.xmin + ',' + bbox.ymin + ',' + bbox.xmax + ',' + bbox.ymax;
  217. var vlayers:Array=[];
  218. var layerDefs:Array=[];
  219. var changed:Boolean=false;
  220. var layer:Layer;
  221. // a special behavior of REST: if partial group then parent must be off
  222. var i:int, c:int;
  223. for (i=0, c=this.layers_.length; i < c; i++) {
  224. layer=this.layers_[i];
  225. if (layer.subLayers) {
  226. for (var j:int=0, jc:int=layer.subLayers.length; j < jc; j++) {
  227. if (layer.subLayers[j].visible === false) {
  228. layer.visible=false;
  229. break;
  230. }
  231. }
  232. }
  233. }
  234. for (i=0, c=this.layers_.length; i < c; i++) {
  235. layer=this.layers_[i];
  236. if (layer.visible !== layer.defaultVisibility) {
  237. changed=true;
  238. }
  239. if (layer.visible === true) {
  240. vlayers.push(layer.id);
  241. }
  242. if (layer.definition) {
  243. layerDefs.push(layer.id + ':' + layer.definition);
  244. }
  245. }
  246. if (params.layerIds != null && params.layerOption != null) {
  247. ps.layers=params.layerOption + ':' + params.layerIds.join(',');
  248. } else if (changed === true) {
  249. ps.layers=ArcGISConstants.LAYER_OPTION_SHOW + ':' + vlayers.join(',');
  250. }
  251. if (params.layerDefinitions != null) {
  252. ps.layerDef=params.layerDefinitions.join(';');
  253. } else if (layerDefs.length > 0) {
  254. ps.layerDefs=layerDefs.join(';');
  255. }
  256. var me:MapService=this;
  257. if (vlayers.length === 0) {
  258. // avoid an error:{"error":{"code":400,"message":"","details":["Invalid layer ID specified."]}
  259. var res:MapImage=new MapImage({});
  260. if (callbackFn != null) {
  261. callbackFn.call(me, res);
  262. }
  263. me.dispatchEvent(new ServiceEvent(ServiceEvent.EXPORTMAP_COMPLETE, res));
  264. return;
  265. } else {
  266. this.dispatchEvent(new ServiceEvent(ServiceEvent.EXPORTMAP_START, params));
  267. ArcGISUtil.restRequest(this.url + '/export', ps, this, function(json:*):void {
  268. var res:MapImage=new MapImage(json);
  269. if (callbackFn != null) {
  270. callbackFn.call(me, res);
  271. }
  272. me.dispatchEvent(new ServiceEvent(ServiceEvent.EXPORTMAP_COMPLETE, res));
  273. }, failedFn);
  274. }
  275. }
  276. /**
  277. * Identify features on a particular ArcGISGeographic location, using {@link ArcGISIdenitfyParameters} and
  278. * process {@link ArcGISIdentifyResults} using the <code>callback</code> function.
  279. * For more info see <a
  280. * href = 'http://resources.esri.com/help/9.3/arcgisserver/apis/rest/identify.html'>Identify Operation</a>.
  281. * @param {IdentifyParameters} params
  282. * @param {Function} callback
  283. */
  284. public function identify(iparams:IdentifyParameters, callbackFn:Function=null, failedFn:Function=null, ovOpts:OverlayOptions=null):void {
  285. if (!iparams) {
  286. return;
  287. }
  288. var sr:SpatialReference=iparams.sr || SpatialReferences.WGS84;
  289. var params:*={f: iparams.f || 'json', returnGeometry: iparams.returnGeometry, tolerance: iparams.tolerance, sr: sr.wkid};
  290. var ovs:Array;
  291. var geom:*;
  292. if (iparams.geometry is LatLng) {
  293. ovs=[iparams.geometry];
  294. } else {
  295. ovs=iparams.geometry;
  296. }
  297. geom=ArcGISUtil.fromOverlaysToGeometry(ovs, sr);
  298. params.geometry=ArcGISUtil.fromGeometryToJSON(geom);
  299. if (geom.x) {
  300. params.geometryType=ArcGISConstants.GEOMETRY_POINT;
  301. } else if (geom.points) {
  302. params.geometryType=ArcGISConstants.GEOMETRY_MULTIPOINT;
  303. } else if (geom.rings) {
  304. params.geometryType=ArcGISConstants.GEOMETRY_POLYGON;
  305. } else if (geom.paths) {
  306. params.geometryType=ArcGISConstants.GEOMETRY_POLYLINE;
  307. }
  308. params.mapExtent=ArcGISUtil.fromGeometryToJSON(ArcGISUtil.fromLatLngBoundsToEnvelope(iparams.bounds, sr));
  309. params.imageDisplay='' + iparams.width + ',' + iparams.height + ',' + (iparams.dpi || 96);
  310. params.layers=iparams.layerOption || 'all' + ':' + iparams.layerIds.join(',');
  311. var me:MapService=this;
  312. ArcGISUtil.restRequest(this.url + '/identify', params, this, function(json:*):void {
  313. var res:IdentifyResults=new IdentifyResults(json);
  314. if (callbackFn != null) {
  315. callbackFn.call(me, res);
  316. }
  317. me.dispatchEvent(new ServiceEvent(ServiceEvent.IDENTIFY_COMPLETE, res));
  318. }, failedFn);
  319. }
  320. /**
  321. * Find features using the {@link ArcGISFindParameters} and process {@link ArcGISFindResults}
  322. * using the <code>callback</code> function.
  323. * For more info see <a
  324. * href = 'http://resources.esri.com/help/9.3/arcgisserver/apis/rest/find.html'>Find Operation</a>.
  325. * @param {FindParameters} params
  326. * @param {Function} callback
  327. */
  328. public function find(fparams:FindParameters, callbackFn:Function=null, failedFn:Function=null, ovOpts:OverlayOptions=null):void {
  329. if (!fparams) {
  330. return;
  331. }
  332. var params:*={f: 'json', searchText: fparams.searchText, sr: SpatialReferences.WGS84.wkid, contains: fparams.contains === false ? false : true, returnGeometry: fparams.returnGeometry === false ? false : true};
  333. if (fparams.layerIds && fparams.layerIds.length > 0) {
  334. params.layers=fparams.layerIds.join(',');
  335. }
  336. if (fparams.searchFields && fparams.searchFields.length > 0) {
  337. params.searchFields=fparams.searchFields.join(',');
  338. }
  339. var me:MapService=this;
  340. ArcGISUtil.restRequest(this.url + '/find', params, this, function(json:*):void {
  341. var res:FindResults=new FindResults(json);
  342. if (callbackFn != null) {
  343. callbackFn.call(me, res);
  344. }
  345. me.dispatchEvent(new ServiceEvent(ServiceEvent.FIND_COMPLETE, res));
  346. }, failedFn);
  347. }
  348. /**
  349. * Query a layer with given id or name using the {@link ArcGISQueryParameters} and process {@link ArcGISResultSet}
  350. * using the <code>callback</code> function.
  351. * See {@link ArcGISLayer}.
  352. * For more info see <a href = 'http://resources.esri.com/help/9.3/arcgisserver/apis/rest/query.html'>Query Layer Operation</a>.
  353. * @param {Number|String} layerNameOrId
  354. * @param {QueryParameters} params
  355. * @param {Function} callback
  356. */
  357. public function queryLayer(layerNameOrId:String, params:QueryParameters, callback:Function=null, failedFn:Function=null):void {
  358. var layer:Layer=this.getLayer(layerNameOrId);
  359. if (layer) {
  360. layer.query(params, callback, failedFn);
  361. } else {
  362. this.dispatchEvent(new ServiceEvent(ServiceEvent.ERROR,
  363. new ServiceError(
  364. {message:"Can not find Layer:"+layerNameOrId}
  365. )));
  366. }
  367. }
  368. private var dispatcher_:EventDispatcher;
  369. public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void {
  370. dispatcher_.addEventListener(type, listener, useCapture, priority);
  371. }
  372. public function dispatchEvent(evt:Event):Boolean {
  373. return dispatcher_.dispatchEvent(evt);
  374. }
  375. public function hasEventListener(type:String):Boolean {
  376. return dispatcher_.hasEventListener(type);
  377. }
  378. public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void {
  379. dispatcher_.removeEventListener(type, listener, useCapture);
  380. }
  381. public function willTrigger(type:String):Boolean {
  382. return dispatcher_.willTrigger(type);
  383. }
  384. }
  385. }