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