PageRenderTime 41ms CodeModel.GetById 8ms app.highlight 27ms RepoModel.GetById 2ms app.codeStats 0ms

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

http://gmaps-utility-library-flash.googlecode.com/
ActionScript | 430 lines | 275 code | 34 blank | 121 comment | 91 complexity | be83d3ba2faffd5fcad91e30e872bed5 MD5 | raw file
  1/*
  2 * ArcGIS for Google Maps Flash API
  3 *
  4 * License http://www.apache.org/licenses/LICENSE-2.0
  5 */ /**
  6 * @author nianwei at gmail dot com
  7 */
  8package com.google.maps.extras.arcgislink {
  9
 10  import com.google.maps.*;
 11  import com.google.maps.extras.arcgislink.json.*;
 12  import com.google.maps.interfaces.IOverlay;
 13  import com.google.maps.overlays.*;
 14  
 15  import flash.events.*;
 16  import flash.geom.Point;
 17  import flash.net.*;
 18  import flash.utils.*;
 19
 20  // import mx.rpc.events.*;
 21  // import mx.rpc.http.*;
 22
 23  /**
 24   * Utility tools
 25   */
 26  public class ArcGISUtil {
 27    public function ArcGISUtil() {
 28
 29    }
 30
 31    /**
 32     * Helper method to convert an {@link ArcGISEnvelope} object to <code>GLatLngBounds</code>
 33     * @param {Envelope} extent
 34     * @return {GLatLngBounds} gLatLngBounds
 35     */
 36    internal static function fromEnvelopeToLatLngBounds( /*Envelope*/ extent:*):LatLngBounds {
 37      var sr:SpatialReference=SpatialReferences.getSpatialReference(extent.spatialReference.wkid);
 38      sr=sr || SpatialReferences.WGS84;
 39      var sw:Array=sr.reverse([extent.xmin, extent.ymin]);
 40      var ne:Array=sr.reverse([extent.xmax, extent.ymax]);
 41      return new LatLngBounds(new LatLng(sw[1], sw[0]), new LatLng(ne[1], ne[0]));
 42    }
 43
 44    internal static function fromLatLngBoundsToEnvelope(gLatLngBounds:LatLngBounds, spatialReference:SpatialReference=null):* {
 45      spatialReference=spatialReference || SpatialReferences.WGS84;
 46      var sw:Array=spatialReference.forward([gLatLngBounds.getSouthWest().lng(), gLatLngBounds.getSouthWest().lat()]);
 47      var ne:Array=spatialReference.forward([gLatLngBounds.getNorthEast().lng(), gLatLngBounds.getNorthEast().lat()]);
 48      return {xmin: sw[0], ymin: sw[1], xmax: ne[0], ymax: ne[1], spatialReference: {wkid: spatialReference.wkid}};
 49    }
 50
 51    internal static function fromLatLngToPoint(gLatLng:LatLng, sr:SpatialReference=null):* {
 52      sr=sr || SpatialReferences.WGS84;
 53      var p:Array=sr.forward([gLatLng.lng(), gLatLng.lat()]);
 54      return {x: p[0], y: p[1], spatialReference: {wkid: sr.wkid}};
 55    }
 56
 57    internal static function fromPointToLatLng(point:*, opt_sr:*=null):LatLng {
 58      var srid:*=point.spatialReference || opt_sr;
 59      var sr:SpatialReference=srid ? SpatialReferences.getSpatialReference(srid.wkid) : SpatialReferences.WGS84;
 60      sr=sr || SpatialReferences.WGS84;
 61      if (isNaN(point.x) || isNaN(point.y)) {
 62        return null;
 63      }
 64
 65      var p:Array=sr.reverse([point.x, point.y]);
 66      return new LatLng(p[1], p[0]);
 67    }
 68
 69    /**
 70     * Add a ArcGIS Server resource to map. if it is cached, it will be added as a map type, if dynamic, it will be added as overlay.
 71     * @param map
 72     * @param url
 73     * @param opt_callback
 74     *
 75     */
 76    public static function addArcGISMap(map:Map, url:String, opt_callback:Function=null):void {
 77      var service:MapService=new MapService(url);
 78      service.addEventListener(ServiceEvent.LOAD, function(evt:Event):void {
 79          if (service.singleFusedMapCache) {
 80            var tile:ArcGISTileLayer=new ArcGISTileLayer(service);
 81            var type:ArcGISMapType=new ArcGISMapType([tile], new ArcGISMapTypeOptions({name: tile.getName().replace(/ /g, '\n')}));
 82            map.addMapType(type);
 83            if (opt_callback != null) {
 84              opt_callback.call(null, type);
 85            }
 86          } else {
 87            var ov:ArcGISMapOverlay=new ArcGISMapOverlay(service);
 88            map.addOverlay(ov);
 89            if (opt_callback != null) {
 90              opt_callback.call(null, ov);
 91            }
 92          }
 93        });
 94    }
 95
 96    /**
 97     * Enable wheel zoom as alternative to Map.enableScrollWheelZoom because the later passed zoom=0 to Projection.
 98     */
 99    internal static function enableScrollWheelZoom(map:com.google.maps.Map):void {
100      map.getDisplayObject().addEventListener(MouseEvent.MOUSE_WHEEL, function(evt:MouseEvent):void {
101          var p:flash.geom.Point=new flash.geom.Point(evt.localX, evt.localY);
102          var latlng:LatLng;
103          var c:flash.geom.Point=new flash.geom.Point(map.width / 2, map.height / 2);
104          var z:Number=map.getZoom();
105          if (evt.delta > 0) {
106            z=Math.min(z + 1, map.getMaxZoomLevel());
107            latlng=map.fromViewportToLatLng(new flash.geom.Point((p.x + c.x) / 2, (p.y + c.y) / 2));
108          } else {
109            z=Math.max(z - 1, map.getMinZoomLevel());
110            latlng=map.fromViewportToLatLng(new flash.geom.Point(c.x * 2 - p.x, c.y * 2 - p.y));
111          }
112          map.setCenter(latlng, z);
113        });
114    }
115
116    internal static var ArcGISConfig:*={maxPolyPoints: 3000, style: {icon: null, strokeStyle: {thickness: 3, color: 0xffff00, alpha: 0.5, pixelHinting: true}, fillStyle: {color: 0xFFFF00, alpha: 0.5}
117
118        }};
119
120    /**
121     * Convert a {@link ArcGISFeature} or {@link ArcGISIdentifyResult} or {@link ArcGISFindResult} to core Google Maps API
122     * overlays such as  {@link ArcGISGMarker},
123     * {@link ArcGISGPolyline}, or {@link ArcGISGPolygon}s.
124     * Note ArcGIS Geometry may have multiple parts, but the coresponding GOverlay
125     * does not  support multi-parts, so the result is an array.
126     * <ul><li><code>feature</code>: an object returned by ArcGIS Server with at least <code>geometry</code> property of type {@link ArcGISGeometry}.
127     *  if it contains a name-value pair "attributes" property, it will be attached to the result overlays.
128     * <li><code>opt_sr</code>: optional {@link ArcGISSpatialReference}. Can be object literal.
129     * <li><code>opt_agsStyle</code> {@link ArcGISStyleOptions}. default is {@link ArcGISConfig}.style.
130     * <li><code>opt_displayName</code> optional field name used for title of feature.
131     * @param {Feature} feature
132     * @param {ArcGISSpatialReference} opt_sr
133     * @param {overlayOptions} opt_agsStyle
134     * @param {String} opt_displayName
135     * @return {GOverlay[]}
136     */
137
138    internal static function fromGeometryToOverlays(geom:*, opt_sr:SpatialReference=null, overlayOptions:OverlayOptions=null, title:String=''):Array {
139      var ovs:Array=[];
140      var sr:SpatialReference=null;
141      var ov:IOverlay=null;
142      overlayOptions=overlayOptions || new OverlayOptions();
143      if (opt_sr) {
144        sr=opt_sr;
145      } else {
146        sr=SpatialReferences.getSpatialReference(geom.spatialReference.wkid);
147      }
148      if (sr === null) {
149        return ovs;
150      }
151
152      var x:String, i:int, ic:int, j:int, jc:int, parts:Array, part:Array, lnglat:Array, glatlngs:Array;
153
154      if (geom.x) {
155        //point
156        lnglat=sr.reverse([geom.x, geom.y]);
157        if (!overlayOptions.marker) {
158          overlayOptions.marker=new MarkerOptions({tooltip: title});
159        } else if (!overlayOptions.marker.tooltip) {
160          overlayOptions.marker.tooltip=title;
161        }
162        ov=new Marker(new LatLng(lnglat[1], lnglat[0]), overlayOptions.marker);
163        ovs.push(ov);
164      } else {
165        //mulpt, line and poly
166        parts=geom.points || geom.paths || geom.rings;
167        if (!parts) {
168          return ovs;
169        }
170        for (i=0, ic=parts.length; i < ic; i++) {
171          part=parts[i];
172          if (geom.points) {
173            // multipoint
174            lnglat=sr.reverse(part);
175            ov=new Marker(new LatLng(lnglat[1], lnglat[0]), overlayOptions.marker);
176            ovs.push(ov);
177          } else {
178            if (part.length > ArcGISConfig.maxPolyPoints) {
179              // TODO: do a simple point reduction 
180              continue;
181            }
182            glatlngs=[];
183            for (j=0, jc=part.length; j < jc; j++) {
184              lnglat=sr.reverse(part[j]);
185              glatlngs.push(new LatLng(lnglat[1], lnglat[0]));
186            }
187            if (geom.paths) {
188                ov=new Polyline(glatlngs, overlayOptions.polyline); //new PolylineOptions({strokeStyle: style.strokeStyle}));
189                ovs.push(ov);
190            } else if (geom.rings) {
191              overlayOptions.polygon=overlayOptions.polygon || new PolygonOptions();
192              overlayOptions.polygon.tooltip=title;
193              if (ov == null) {
194                ov=new Polygon(glatlngs, overlayOptions.polygon); //new PolygonOptions({strokeStyle: style.strokeStyle, fillStyle: style.fillStyle, tooltip: title})); //, style.outlineColor, style.outlineWeight, style.outlineOpacity, style.fillColor, style.fillOpacity);
195                ovs.push(ov);
196              } else {
197                (ov as Polygon).setPolyline(i, glatlngs);
198              }
199            }
200          }
201
202        }
203      }
204
205      return ovs;
206    }
207
208    internal static function fromOverlaysToGeometry(ovs:Array, opt_sr:SpatialReference=null):* {
209      var sr:SpatialReference=null;
210      if (opt_sr) {
211        sr=opt_sr;
212      } else {
213        sr=SpatialReferences.WGS84;
214      }
215      var ov:*;
216      if (!ovs || ovs.length == 0)
217        return null;
218      ov=ovs[0];
219      var x:String, i:int, ic:int, j:int, jc:int, parts:Array, part:Array, ll:LatLng, lnglat:Array;
220      if (ovs.length == 1 && (ov is LatLng || ov is Marker)) {
221        ll=(ov is LatLng ? ov as LatLng : (ov as Marker).getLatLng());
222        lnglat=sr.forward([ll.lng(), ll.lat()]);
223        return {x: lnglat[0], y: lnglat[1], spatialReference: {wkid: sr.wkid}};
224      }
225      parts=[];
226      if (ov is LatLng) {
227        for (i=0; i < ovs.length; i++) {
228          ll=ovs[i] as LatLng;
229          parts.push(sr.forward([ll.lng(), ll.lat()]));
230        }
231        return {points: parts, spatialReference: {wkid: sr.wkid}};
232      } else if (ov is Marker) {
233        for (i=0; i < ovs.length; i++) {
234          ll=(ovs[i] as Marker).getLatLng();
235          parts.push(sr.forward([ll.lng(), ll.lat()]));
236        }
237        return {points: parts, spatialReference: {wkid: sr.wkid}};
238      } else if (ov is Polyline || ov is Polygon) {
239        for (i=0; i < ovs.length; i++) {
240          part=[];
241          //var line:Polyline = ovs[i] as Polyline;
242          ov=ovs[i];
243          for (j=0; j < ov.getVertexCount(); j++) {
244            ll=ov.getVertex(j);
245            part.push(sr.forward([ll.lng(), ll.lat()]));
246          }
247          parts.push(part);
248        }
249        if (ov is Polyline) {
250          return {paths: parts, spatialReference: {wkid: sr.wkid}};
251        } else {
252          return {rings: parts, spatialReference: {wkid: sr.wkid}};
253        }
254      }
255    }
256
257    internal static function restRequest(url:String, params:Object, thisObj:IEventDispatcher, sucessFn:Function, failFn:Function=null):void {
258      var full:String=url + (url.indexOf('?') === -1 ? '?' : '&');
259      /*
260         var service:HTTPService=new HTTPService();
261         service.url=url;
262         service.addEventListener(FaultEvent.FAULT, function(evt:FaultEvent):void {
263         var err:ServiceError=new ServiceError({code: -1, message: evt.toString(), details: []});
264         if (thisObj != null) {
265         thisObj.dispatchEvent(new ServiceEvent(ServiceEvent.ERROR, err));
266         }
267         if (failFn != null) {
268         failFn(thisObj, err);
269         }
270         });
271         service.addEventListener(ResultEvent.RESULT, function(evt:ResultEvent):void {
272         var jsons:String=evt.result as String;
273         var d:JSONDecoder=new JSONDecoder(jsons, false); // false strict to allow NAN in geocode results
274         var json:Object=d.getValue();
275         if (json.error) {
276         var err:ServiceError=new ServiceError(json.error);
277         thisObj.dispatchEvent(new ServiceEvent(ServiceEvent.ERROR, err));
278         if (failFn != null) {
279         failFn.call(thisObj, err);
280         }
281         } else if (sucessFn != null) {
282         sucessFn.call(thisObj, json);
283         }
284         });
285         service.send(params);
286       */
287      var variables:URLVariables=new URLVariables();
288      if (params) {
289        for (var x:String in params) {
290          if (params.hasOwnProperty(x)) {
291            //full+=(x + '=' + escape(params[x]) + '&');
292            variables[x]=params[x];
293          }
294        }
295      }
296
297      var loader:URLLoader=new URLLoader();
298      var request:URLRequest=new URLRequest(full);
299      request.method=URLRequestMethod.GET; //.POST;  
300      request.data=variables;
301
302      loader.addEventListener(Event.COMPLETE, function(evt:Event):void {
303          var jsons:String=evt.target.data as String;
304          var d:JSONDecoder=new JSONDecoder(jsons, false); // false strict to allow NAN in geocode results
305          var json:Object=d.getValue();
306          if (json.error) {
307            var err:ServiceError=new ServiceError(json.error);
308            thisObj.dispatchEvent(new ServiceEvent(ServiceEvent.ERROR, err));
309            if (failFn != null) {
310              failFn.call(thisObj, err);
311            }
312          } else if (sucessFn != null) {
313            sucessFn.call(thisObj, json);
314          }
315
316
317        });
318      loader.addEventListener(IOErrorEvent.IO_ERROR, function(evt:IOErrorEvent):void {
319          var err:ServiceError=new ServiceError({code: -1, message: evt.toString(), details: []});
320          if (thisObj != null) {
321            thisObj.dispatchEvent(new ServiceEvent(ServiceEvent.ERROR, err));
322          }
323          if (failFn != null) {
324            failFn(thisObj, err);
325          }
326
327        });
328      loader.load(request);
329
330    }
331
332    /**
333     * Extract the substring from full string, between start string and end string
334     * @param {Object} full
335     * @param {Object} start
336     * @param {Object} end
337     */
338    internal static function extractString(full:String, start:String, end:String):String {
339      var i:int=(start === '') ? 0 : full.indexOf(start);
340      var e:int=end === '' ? full.length : full.indexOf(end, i + start.length);
341      return full.substring(i + start.length, e);
342    }
343
344    internal static function augmentObject(src:*, dest:*, force:Boolean=false):Object {
345      if (src && dest) {
346        var p:String;
347        // used to count/check if it is a dyna class 
348        // with properties that can be looped with for.. in
349        // In AS3, for..in can not be used to loop properties of a class instance except those 
350        // dynamic added. That makes converting parameter classes into REST request harder.
351        var i:int=0;
352        for (p in src) {
353          i++;
354          if (src.hasOwnProperty(p)) {
355            if (force || !(p in dest) || (p in dest && !dest[p])) {
356              dest[p]=src[p];
357            }
358          }
359        }
360        if (i == 0) {
361          var varList:XMLList=flash.utils.describeType(src)..variable;
362          for (i=0; i < varList.length(); i++) {
363            p=varList[i].@name;
364            if (src[p]) {
365              dest[p]=src[p];
366            }
367          }
368        }
369      }
370      return dest;
371    }
372
373    internal static function isString(o:*):Boolean {
374      return o && o is String;
375    }
376
377    internal static function isArray(o:*):Boolean {
378      return o && o is Array;
379    }
380
381    public static function getAttributeValue(attrs:*, name:String):* {
382      if (attrs[name])
383        return attrs[name];
384      for (var x:String in attrs) {
385        if (x.toUpperCase() == name.toUpperCase()) {
386          return attrs[x];
387        }
388      }
389      return null;
390    }
391
392    internal static function fromGeometryToJSON(geom:Object, opt_includeSR:Boolean=false):String {
393      /*function fromPointsToJSON(pts) {
394         var arr = [];
395         for (var i = 0, c = pts.length; i < c; i++) {
396         arr.push('[' + pts[i][0] + ',' + pts[i][1] + ']');
397         }
398         return '[' + arr.join(',') + ']';
399         }
400         function fromLinesToJSON(lines) {
401         var arr = [];
402         for (var i = 0, c = lines.length; i < c; i++) {
403         arr.push(fromPointsToJSON(lines[i]));
404         }
405         return '[' + arr.join(',') + ']';
406         }
407
408         var json = '{';
409         if (geom.x) {
410         json += 'x:' + geom.x + ',y:' + geom.y;
411         } else if (geom.xmin) {
412         json += 'xmin:' + geom.xmin + ',ymin:' + geom.ymin + ',xmax:' + geom.xmax + ',ymax:' + geom.ymax;
413         } else if (geom.points) {
414         json += 'points:' + fromPointsToJSON(geom.points);
415         } else if (geom.paths) {
416         json += 'paths:' + fromLinesToJSON(geom.paths);
417         } else if (geom.rings) {
418         json += 'rings:' + fromLinesToJSON(geom.rings);
419         }
420         if (opt_includeSR && geom.spatialReference) {
421         json += ',spatialReference:{wkid:' + geom.spatialReference.wkid + '}';
422         }
423         json += '}';
424         return json;
425       */
426      var e:JSONEncoder=new JSONEncoder(geom);
427      return e.getString();
428    }
429  }
430}