Sunday, February 3, 2008

Tracking the mouse on the map

This is done by setting the mouseHandler property on a map instance to an implementation of the IMouseHandler interface. The IMouseHandler interface has the classic mouseUp, mouseDown, mouseMove abstract functions. In addition, there are two abstract functions; set map() and cleanup(). The cleanup method is called on any previously set handler before a new mouse handler is set. A map reference is "injected" (a al IoC) onto the mouse handler when it is assigned to the map using the setter function. AWX provided a base implementation (BaseMouseHandler) that has a protected helper function to convert a stage mouse location to a GeoPoint. Another provided implementation, BaseOverlayMouseHandler associates a mouse handler with a map layer. This class can be used to draw overlays on map using the mouse such as redlines and rubberband rectangles. The following implementation enables a user to draw a geodesic circle on the map. You can see it in action here. Select the "Draw Circle" from the context menu to draw a circle. Download the full source code from here.

package com.esri.sample
{
import com.esri.aws.awx.geom.CircleShape;
import com.esri.aws.awx.geom.GeoPoint;
import com.esri.aws.awx.map.handlers.BaseOverlayMouseHandler;
import com.esri.aws.awx.map.layers.OverlayLayer;
import com.esri.aws.awx.map.layers.overlays.Circle;
import com.esri.aws.awx.map.layers.overlays.style.IStyle;
import com.esri.aws.awx.map.layers.overlays.style.PolygonStyle;
import com.esri.aws.awx.map.projection.ProjUtils;

import flash.events.Event;
import flash.events.MouseEvent;

[Event(name="complete", type="flash.events.Event")]

public class CircleMouseHandler extends BaseOverlayMouseHandler
{
private var m_down : Boolean = false;
private var m_center : GeoPoint;
private var m_shape : CircleShape;
private var m_circle : Circle;

public function CircleMouseHandler(
overlayLayer : OverlayLayer
)
{
super(
overlayLayer,
new PolygonStyle,
false
);
}

override public function onMouseDown(event:MouseEvent):void
{
m_down = true;
m_center = stage2GeoPoint( event );
if( m_center )
{
m_shape = new CircleShape( m_center, 1, CircleShape.METERS);
m_circle = new Circle( m_shape, style );
overlayLayer.addOverlay( m_circle );
event.updateAfterEvent();
}
else
{
m_down = false;
m_circle = null;
}
}

override public function onMouseMove(event:MouseEvent):void
{
if(m_down)
{
var geoPoint : GeoPoint = stage2GeoPoint(event);
if( geoPoint )
{
m_shape.radius = geodeticInverse(m_center, geoPoint, ProjUtils.EARTH_RADIUS );
m_circle.invalidateDisplayList();
event.updateAfterEvent();
}
}
}

override public function onMouseUp(event:MouseEvent):void
{
m_down = false;
if( m_circle )
{
if( applyToMap == false)
{
overlayLayer.removeOverlay( m_circle);
}
event.updateAfterEvent();
dispatchEvent( new Event(Event.COMPLETE));
}
}

private function geodeticInverse(
fPt:GeoPoint,
tPt:GeoPoint,
earthRadius:Number
) : Number
{
var lam1:Number = ProjUtils.DDToRad(fPt.x), phi1:Number=ProjUtils.DDToRad(fPt.y);
var lam2:Number = ProjUtils.DDToRad(tPt.x), phi2:Number=ProjUtils.DDToRad(tPt.y);
var d_lam:Number = ProjUtils.Angle180(lam2 - lam1);

var cos_phi1:Number = ProjUtils.AngleIsHalfPi(Math.abs(phi1)) ? 0.0 : Math.cos(phi1);
var sin_phi1:Number = Math.sin(phi1);
var cos_phi2:Number = ProjUtils.AngleIsHalfPi(Math.abs(phi2)) ? 0.0 : Math.cos(phi2);
var sin_phi2:Number = Math.sin(phi2);

var cos_dlam:Number = ProjUtils.AngleIsHalfPi(Math.abs(d_lam)) ? 0.0 : Math.cos(d_lam);
var sin_dlam:Number = ProjUtils.AngleIsZero(Math.abs(d_lam)-Math.PI) ? 0.0 : Math.sin(d_lam);

var sigma:Number = Math.acos(sin_phi1*sin_phi2 + cos_phi1*cos_phi2*cos_dlam);
var distance:Number = sigma * earthRadius;
return distance;
}
}
}

1 comment:

Unknown said...

You have posted the source program to track mouse movements. I am searching for a tool that will help me doing this task. I am not a technical person so it will be difficult for me to work using this code.
tracking mouse