Wednesday, September 26, 2007

Cool usage of AWX

Check out Andrew Trice's post on AWX usage. Pretty cool !

Trace AWX errors

We use Flex logging capabilities to report debug, info and error information:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
layout="absolute"
>
<mx:TraceTarget/>
<framework:Framework
username="foo"
password="bar"
authenticationError="trace(event.getError())"/>
</mx:Application>

Tuesday, September 25, 2007

I get a blank map first time through...


If you are using Flex Builder
, make sure that you set the output folder of the project to a web application folder. Remember, your api key is tied to a URL. To get to this setting, use File -> Properties -> Flex Build Path.

WMS basemap layer

You can subclass BaseMapLayer to create a WMS basemap layer:

package com.esri.aws.awx.map.layers
{
import com.esri.aws.awx.geom.Extent;

import flash.geom.Point;
import flash.utils.getTimer;

public class WMSGroupLayer extends BaseMapLayer
{
public var service : String = "WMS";
public var version : String = "1.1.1";
public var request : String = "GetMap";
public var format : String = "image/png";
public var wmsLayers : String;
public var serviceName : String;
public var wmtVersion : String;
public var styles : String;
public var srs : String;
public var dataSource:String;
public var proxyURL : String;

public function WMSGroupLayer()
{
super();
mapOversizeBuffer = 0;
}

override protected function getMap():void
{
m_lastMap = buildGeoLoader();

var scalarPt:Point = getScalar();
var width:Number = Math.floor(map.rotatedWidth * scalarPt.x);
var height:Number = Math.floor(map.rotatedHeight * scalarPt.y);

m_lastMap.startTime = getTimer();
m_lastMap.mapHeight = height;
m_lastMap.mapWidth = width;
m_lastMap.center = map.center;
m_lastMap.mapRotation = map.mapRotation;
m_lastMap.scale = map.scale;
m_lastMap.projectionID = map.projectionID;

var extent : Extent = map.extent;

var index : int = dataSource.indexOf( "?");
var prefix : String = index == -1 ? "?" : "&";

var url : String = dataSource;
url += prefix + "SERVICE="+service;
url += "&VERSION="+version;
url += "&REQUEST="+request;
if( serviceName != null)
{
url += "&SERVICENAME="+serviceName;
}
if( wmtVersion != null)
{
url += "&WMTVER="+wmtVersion;
}
if( wmsLayers != null)
{
url += "&LAYERS="+wmsLayers;
}
if( styles != null)
{
url += "&STYLES="+styles;
}
if( srs != null)
{
url += "&SRS="+srs;
}
url += "&FORMAT="+format;
url += "&WIDTH="+width;
url += "&HEIGHT="+height;
url += "&BBOX="+extent.minX+","+extent.minY+","+extent.maxX+","+extent.maxY;

if( proxyURL != null)
{
url = proxyURL + "?" + escape( url);
}

// trace( url );

centerMap(m_lastMap);

m_lastMap.load( url);
}
}
}

Here is how you use it in MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:layers="com.esri.aws.awx.map.layers.*"
layout="absolute"
>
<framework:Framework apiKey="XXXXXX"/>
<map:Map id="map" centerLat="40.708512143644064" centerLon="-74.01304349200724" scale="200000">
<map:basemaps>
<layers:WMSGroupLayer
dataSource="http://gisdata.usgs.net/servlet/com.esri.wms.Esrimap"
serviceName="USGS_WMS_LANDSAT7"
wmtVersion="1.1.0"
wmsLayers="LANDSAT_LZ77"
srs="EPSG:4326"
/>
</map:basemaps>
</map:Map>
</mx:Application>

Friday, September 21, 2007

Presenting at Adobe MAX 2007

Will be in Chicago at Adobe MAX 2007, and presenting on:

  • Monday, October 1 4:30 pm - 5:30 pm

  • Tuesday, October 2 9:15 am - 10:15 am


Hope to see you there.

Thursday, September 20, 2007

Current US precipitation

You can take advantage of AWS data sources, in this case Precipitation.US, to view dynamic data.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:layers="com.esri.aws.awx.map.layers.*"
xmlns:services="com.esri.aws.services.*"
layout="absolute"
>
<framework:Framework apiKey="19640523">
<services:MapImageActivator/>
</framework:Framework>
<map:Map centerLat="35" centerLon="-93" scale="20000000">
<map:basemaps>
<layers:MapImageGroupLayer dataSource="ArcWeb:MX.Precipitation.US">
<layers:layerVisibilities>
<layers:LayerVisibility name="U.S. States" visible="false"/>
</layers:layerVisibilities>
</layers:MapImageGroupLayer>
</map:basemaps>
</map:Map>
</mx:Application>

AWX2 beta users count keeps growing

As of today, the number of AWX2 beta users have reached a cool 883 !

AWX2 blog reference

Mapperz posted comments about AWX2. Thanks.

Tuesday, September 18, 2007

Hey ArcIMS users....

You can use an ArcIMS datasource as a basemap, as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:layers="com.esri.aws.awx.map.layers.*"
layout="absolute"
>
<framework:Framework apiKey="19640523"/>
<map:Map>
<map:basemaps>
<layers:ArcIMSGroupLayer id="world"
serviceHost="http://www.geographynetwork.com"
serviceName="ESRI_World"
/>
</map:basemaps>
</map:Map>
</mx:Application>

Don't forget to place a crossdomain.xml file at the base of your ArcIMS host. Check out the Geography Network cross domain file as a sample.

Monday, September 17, 2007

How to create a dashed line ?

This code is based on the great work from Eli. You can download all the source code from here. So... in mxml it will look like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:layers="com.esri.aws.awx.map.layers.*"
xmlns:style="com.esri.aws.awx.map.layers.overlays.style.*"
xmlns:overlays="com.esri.aws.awx.map.layers.overlays.*"
xmlns:geom="flash.geom.*"
>
<framework:Framework/>
<map:Map>
<map:basemaps>
<layers:PolylineLayer>
<layers:style>
<style:StrokeStyle>
<style:stroke>
<mx:Stroke color="0xFF0000" alpha="0.5" weight="5" caps="round"/>
</style:stroke>
<style:pattern>
<mx:Number>10</mx:Number>
<mx:Number>10</mx:Number>
</style:pattern>
</style:StrokeStyle>
</layers:style>
<overlays:Polyline>
<overlays:coords>
<geom:Point y="0" x="0"/>
<geom:Point y="45" x="-90"/>
<geom:Point y="-45" x="-90"/>
</overlays:coords>
</overlays:Polyline>
</layers:PolylineLayer>
</map:basemaps>
</map:Map>
</mx:Application>

Thursday, September 13, 2007

Map distance measuring tool

Following the previous post, here is an example on how you will be able to use in the upcoming beta3 the polyline mouse handler to create a distance measuring tool.

&lt;?xml version="1.0" encoding="utf-8"?>
&lt;mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:utils="com.esri.aws.awx.utils.*"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
layout="absolute"
>
&lt;mx:Script>
&lt;![CDATA[
import com.esri.aws.awx.utils.Utils;
import com.esri.aws.awx.map.layers.overlays.Polyline;
import com.esri.aws.awx.events.OverlayEvent;
import com.esri.aws.awx.map.handlers.PolylineMouseHandler;
import com.esri.aws.awx.map.handlers.IMouseHandler;

private var m_mouseHandler : IMouseHandler;

private function doMeasure() : void
{
m_mouseHandler = map.mouseHandler;
var mouseHandler : PolylineMouseHandler = new PolylineMouseHandler( map.polylineLayer);
mouseHandler.addEventListener(OverlayEvent.OVERLAY_CHANGED, function(event : OverlayEvent) : void
{
var polyline : Polyline = event.overlayObject as Polyline;
var coords : Array = polyline.coords;
var td : Number = 0.0;
for( var i:int = 0, j:int=1; j&lt;coords.length; i++, j++)
{
var p1 : Point = coords[i] as Point;
var p2 : Point = coords[j] as Point;
td += Utils.distVincenty(p1.y, p1.x, p2.y, p2.x);
}
distance.text = td.toFixed(2);
});
mouseHandler.addEventListener(OverlayEvent.OVERLAY_CREATED, function(event : OverlayEvent) : void
{
map.mouseHandler = m_mouseHandler;
});
map.mouseHandler = mouseHandler;
distance.text = "0";
}
]]>
&lt;/mx:Script>
&lt;framework:Framework apiKey="19640523"/>
&lt;mx:Panel title="Measure Tool" width="100%" height="100%">
&lt;map:Map id="map"/>
&lt;mx:ControlBar>
&lt;mx:Button label="Measure" click="doMeasure()"/>
&lt;mx:Button label="Clear" click="map.polylineLayer.removeAllOverlays()"/>
&lt;mx:Label text="Meters:"/>
&lt;mx:Label id="distance" text="0"/>
&lt;/mx:ControlBar>
&lt;/mx:Panel>
&lt;/mx:Application>

Distance between two Latitude/Longitude points

So when I asked my friend Kerry (who BTW is the king when it comes to map projections) how to calculate the distance between two lat/lon points ? he pointed me to this link. He followed by saying "This is a good start, but what I have implemented in Java, takes care of all the 'weird' conditions!". This is why he is the king :-). So you can find the AS3 implementation here. And here is a simple MXML calculator.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import com.esri.aws.awx.utils.Utils;
private function onClick() : void
{
var lat1n : Number = Utils.parseDeg(lat1.text);
var lon1n : Number = Utils.parseDeg(lon1.text);

var lat2n : Number = Utils.parseDeg(lat2.text);
var lon2n : Number = Utils.parseDeg(lon2.text);

var dist : Number = Utils.distVincenty( lat1n, lon1n, lat2n, lon2n);
distLabel.text = dist.toFixed(2) + " meter(s)"
}
]]>
</mx:Script>
<mx:Form width="100%" height="100%">
<mx:FormHeading label="Geodesic Distance Calculator"/>
<mx:FormItem label="lat 1:">
<mx:TextInput id="lat1" width="200" text="53 09 02N"/>
</mx:FormItem>
<mx:FormItem label="lon 1:">
<mx:TextInput id="lon1" width="200" text="001 50 40W"/>
</mx:FormItem>
<mx:FormItem label="lat 2:">
<mx:TextInput id="lat2" width="200" text="52 12 19N"/>
</mx:FormItem>
<mx:FormItem label="lon 2:">
<mx:TextInput id="lon2" width="200" text="000 08 33W"/>
</mx:FormItem>
<mx:FormItem label="dist">
<mx:Label id="distLabel"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button
label="Calculate"
click="onClick()"/>
</mx:FormItem>
</mx:Form>
</mx:Application>

Wednesday, September 12, 2007

LiveHTTPHeaders

Following the last post, AWX can connect directly to a resource such as ArcIMS or even ArcGIS to get maps. The best way that I found out to see what crossdomain.xml the player is requesting, is to run the application in Firefox and watch the HTTP traffic using LiveHTTPHeaders.

Tuesday, September 11, 2007

I do not get a map...

Make sure that you have a crossdomain.xml file at the base of you web server that is hosting ArcIMS, ArcGIS or any host that you are trying to access data from that is not the host from which the swf was downloaded from. In such a way, that if you type http://your-host-name-info/crossdomain.xml in a web browser, you should get:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false"/>
</cross-domain-policy>

If you cannot create that file on that host, then use/create a proxy with a crossdomain file.

How to turn off layer visibility ?


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:layers="com.esri.aws.awx.map.layers.*"
layout="absolute"
>
<mx:Script>
<![CDATA[
import com.esri.aws.awx.map.layers.LayerVisibility;
private function onClick() : void
{
world.layerVisibilities = [
new LayerVisibility("Major Rivers", false)
];
}
]]>
</mx:Script>
<framework:Framework apiKey="19640523"/>
<mx:Panel width="100%" height="100%">
<map:Map>
<map:basemaps>
<layers:ArcIMSGroupLayer id="world"
serviceHost="http://www.geographynetwork.com"
serviceName="ESRI_World"
autoLoadLayerVisibilities="true"
/>
</map:basemaps>
</map:Map>
<mx:ControlBar>
<mx:Button label="Turn Off Major Rivers" click="onClick()"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>

How to add a polygon to the map ?


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:map="com.esri.aws.awx.map.*"
creationComplete="onCreationComplete()"
layout="absolute"
>
<mx:Script>
<![CDATA[
import flash.geom.Point;
import com.esri.aws.awx.map.layers.overlays.Polygon;
import com.esri.aws.awx.geom.PolygonShape;

private function onCreationComplete() : void
{
var coords : Array = [
new Point( 0, 0),
new Point( -97.06138,32.837),
new Point( 0, 32.832),
new Point( 0, 0)
];
var polygonShape : PolygonShape = new PolygonShape( coords);
var polygon : Polygon = new Polygon( polygonShape);
map.polygonLayer.addOverlay( polygon);
}
]]>
</mx:Script>
<framework:Framework/>
<map:Map id="map"/>
</mx:Application>

Wednesday, September 5, 2007

How to create geographic circles ?

In the current beta-2 version of AWX, you can create geographical circles using the Circle and CircleShape classes. In the beta-3 version, you will be able to do:

<map:Map>
<map:basemaps>
<layers:PolygonLayer>
<overlays:Circle centerLat="0" centerLon="0" radius="500000" units="meters"/>
<overlays:Circle centerLat="45" centerLon="-80" radius="500" units="kilometers"/>
<overlays:Circle centerLat="60" centerLon="80" radius="500" units="miles"/>
</layers:PolygonLayer>
</map:basemaps>
</map:Map>

Framework start event

Wait for the framework start event to lookup services registered by the activator.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:services="com.esri.aws.services.*"
layout="absolute"
>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import com.esri.aws.services.IRouteFinder;
import flash.utils.getQualifiedClassName;
import com.esri.aws.osgi.framework.IServiceReference;
import com.esri.aws.osgi.framework.Framework;
import com.esri.aws.osgi.framework.IBundleContext;

private function frameworkStartHandler() : void
{
var context : IBundleContext = Framework.getInstance().systemContext;
var ref : IServiceReference = context.getServiceReference( getQualifiedClassName(IRouteFinder));
if( ref != null)
{
var routeFinder : IRouteFinder = context.getService( ref) as IRouteFinder;
trace( routeFinder);
}
else
{
Alert.show( "No IRouteFinder Reference");
}
}
]]>
</mx:Script>
<framework:Framework apiKey="19640523" frameworkStart="frameworkStartHandler()">
<services:RouteFinderActivator/>
</framework:Framework>
</mx:Application>

How to reverse geocode a location ?


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:map="com.esri.aws.awx.map.*"
xmlns:framework="com.esri.aws.osgi.framework.*"
xmlns:services="com.esri.aws.services.*"
xmlns:awx="com.esri.aws.awx.*"
implements="mx.rpc.IResponder"
initialize="initializeHandler()"
layout="absolute">
<mx:Script><![CDATA[
import mx.logging.targets.TraceTarget;
import mx.logging.Log;
import com.esri.aws.services.GeocodeCandidate;
import com.esri.aws.awx.map.handlers.ReverseGeocodeMouseHandler;
import com.esri.aws.services.FindActivator;
import com.esri.aws.services.GeocodeInfo;
import com.esri.awx.RevGeoMouseHandler;

private function initializeHandler() : void
{
map.mouseHandler = new ReverseGeocodeMouseHandler(this);
}

public function result(data:Object):void
{
var geocodeInfo:GeocodeInfo = data as GeocodeInfo;
for each ( var candidate : GeocodeCandidate in geocodeInfo.candidates)
{
trace( candidate.desc1 );
}
}

public function fault(info:Object):void
{
trace( info);
}
]]></mx:Script>
<framework:Framework apiKey="19640523">
<services:FindActivator/>
</framework:Framework>
<map:Map id="map" centerLon="-96.8577" centerLat="38.9762" scale="26000000"/>
</mx:Application>