Select to view content in your preferred language

Tween a Graphic by MapPoint

1394
5
Jump to solution
01-02-2013 04:44 AM
AhmedFarghali
Emerging Contributor
Hi,

I want to tween a Graphic Object over a PolyLine. I tried TweenLite and Spark.Animate, but the problem is that they uses Point "Screen point", and when I convert the Graphic mapPoint to Point, it gives a strange behavior, probably because of the differences characteristics, besides it's not a good practice.

and thanks in advance,
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
IvanBespalov
Frequent Contributor
Ahmed, your code compilation faults 😞

Another view to your task realization.
1 - Use ESRI geometries = no conversion between Point and MapPoint
2 - Create/Generate additioanal points for tracking.
3 - Quickly replace points of the object to move it without delay ~ animation.

try it
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"        xmlns:s="library://ns.adobe.com/flex/spark"        xmlns:mx="library://ns.adobe.com/flex/mx"        xmlns:esri="http://www.esri.com/2008/ags"       creationComplete="onCreationComplete(event)">    <s:layout>   <s:VerticalLayout gap="10"         paddingBottom="20"         paddingLeft="20"         paddingRight="20"         paddingTop="20"/>  </s:layout>  <fx:Script>   <![CDATA[    import com.esri.ags.Graphic;    import com.esri.ags.events.PanEvent;    import com.esri.ags.geometry.Polyline;    import com.esri.ags.symbols.SimpleMarkerSymbol;    import com.esri.ags.tasks.supportClasses.DensifyParameters;        import mx.events.FlexEvent;    import mx.rpc.AsyncResponder;    import mx.rpc.Fault;        private var points:Array = new Array();        private var moveObj:Graphic;        private var moveIndex:int;          private var timer:Timer;        protected function onCreationComplete(event:FlexEvent):void    {     initMovingGraphic();     createTrackPoints();     initTimer();    }        private function initMovingGraphic():void    {     moveObj = new Graphic(new MapPoint(-13629302.512116898, 4545949.1442212695, map.spatialReference))     moveObj.symbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 9);     trackLayer.add(moveObj);    }        private function initTimer():void    {     timer = new Timer(20);     timer.addEventListener(TimerEvent.TIMER, onTimerTick);    }        private function createTrackPoints():void    {     var densifyParams:DensifyParameters = new DensifyParameters();     densifyParams.geometries = [trackLine];     densifyParams.maxSegmentLength = 5;          geometryService.densify(densifyParams, new AsyncResponder(onDensifyResult, onDensifyFault));    }        protected function onDensifyResult(result:Array, token:Object = null):void    {     points = new Array();     var resultLine:Polyline = result[0];     for each(var pt:MapPoint in resultLine.paths[0] )     {      points.push(pt);     }    }        protected function onDensifyFault(fault:Fault, token:Object = null):void    {     trace("densify faults " + fault.faultString + " " + fault.message.toString());    }        protected function onMoveClick(event:MouseEvent):void    {     timer.stop();     moveIndex = 0;     timer.start();    }        protected function onTimerTick(event:TimerEvent):void    {     moveObj.geometry = points[moveIndex];     moveIndex++;    }     protected function onPauseResumeClick(event:MouseEvent):void    {     if (timer.running)     {      timer.stop();      btnPauseResume.label = "Resume";     }     else     {      timer.start();      btnPauseResume.label = "Pause";     }    }     private var mustResumeTracking:Boolean = false;        protected function onMapPanStart(event:PanEvent):void    {     if (timer.running)     {      timer.stop();      mustResumeTracking = true;     }    }     protected function onMapPanEnd(event:PanEvent):void    {     if (mustResumeTracking)     {      timer.start();      mustResumeTracking = false;     }    }    ]]>  </fx:Script>    <fx:Declarations>   <esri:Extent id="initialExtent"       xmin="-13635000"        ymin="4541000"        xmax="-13625000"        ymax="4547000">    <esri:SpatialReference wkid="102100"/>   </esri:Extent>   <esri:GeometryService id="geometryService"          url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer" />  </fx:Declarations>    <esri:Map id="map"      extent="{initialExtent}"      panStart="onMapPanStart(event)"      panEnd="onMapPanEnd(event)">      <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>      <esri:GraphicsLayer>        <esri:Graphic>     <esri:geometry>      <esri:Polyline id="trackLine" spatialReference="{new SpatialReference(102100)}">       <fx:Array>        <fx:Array>         <esri:MapPoint x="-13629302.512116898" y="4545949.1442212695"/>         <esri:MapPoint x="-13628433.040920155" y="4546016.026621019"/>         <esri:MapPoint x="-13628327.940006264" y="4544449.067541175"/>         <esri:MapPoint x="-13626541.2244701" y="4544582.832340674"/>         <esri:MapPoint x="-13626665.434641063" y="4546379.102505373"/>        </fx:Array>       </fx:Array>      </esri:Polyline>     </esri:geometry>     <esri:symbol>      <esri:SimpleLineSymbol width="3" color="0xFF0000"/>     </esri:symbol>    </esri:Graphic>        </esri:GraphicsLayer>      <esri:GraphicsLayer id="trackLayer" />    </esri:Map>    <s:HGroup gap="20"       width="100%">      <s:Button label="Move"       click="onMoveClick(event)"/>      <s:Button id="btnPauseResume"        label="Pause"       click="onPauseResumeClick(event)"/>     </s:HGroup>   </s:Application>


Good luck

View solution in original post

0 Kudos
5 Replies
IvanBespalov
Frequent Contributor
If you want to animate com.esri.ags.Graphic just set it as target for spark.effects.AnimateFilter

Take a look on deaclarations tag and on  onGridSingleClick() function code in sources of this sample.


UPD:
Use case: Just click on any places on map, make > 1 clicks. Each click result is MapPoint.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      xmlns:esri="http://www.esri.com/2008/ags">
 
 <s:layout>
  <s:VerticalLayout gap="10"
        paddingBottom="20"
        paddingLeft="20"
        paddingRight="20"
        paddingTop="20"/>
 </s:layout>
 <fx:Script>
  <![CDATA[
   import com.esri.ags.Graphic;
   import com.esri.ags.events.MapMouseEvent;
   import com.esri.ags.geometry.MapPoint;
   import com.esri.ags.geometry.Polyline;
   
   import mx.collections.ArrayCollection;
   
   import spark.filters.GlowFilter;
   
   private var _polyline:Polyline;
   private var _points:Array = new Array();
   
   private var _isPolyline:Boolean = true;
   
   protected function onMapClick(event:MapMouseEvent):void
   {
    if (event)
    {
     _points.push(event.mapPoint);
    }
    if (_isPolyline) // if checkbox selected
    {
     if (!_polyline)
     {
      _polyline = new Polyline();
      _polyline.spatialReference = map.spatialReference;
     }
     
     if (_points.length > 1)
     {
      _polyline.paths = [ _points ];
      
      animationFilter.stop();
      gLayer.clear();
      
      var gr:Graphic = new Graphic(_polyline, sls);
      gLayer.add(gr);
      
      animationFilter.target = gr;
      animationFilter.play();
     }
    }
    else
    {
     animationFilter.stop();
     gLayer.clear();
     for each (var pt:MapPoint in _points)
     {
      var graphic:Graphic = new Graphic(pt, sms); 
      gLayer.add(graphic);
     }
     animationFilter.targets = ArrayCollection(gLayer.graphicProvider).toArray();
     animationFilter.play();
    }
   }
   
   protected function onClearClick(event:MouseEvent):void
   {
    animationFilter.stop();
    gLayer.clear();
    _polyline = null;
    _points = new Array();
   }
   
   protected function onSelectionChange(event:Event):void
   {
    _isPolyline = box.selected;
    onMapClick(null);
   }
   
  ]]>
 </fx:Script>
 
 <fx:Declarations>
  <s:AnimateFilter id="animationFilter"
       repeatCount="0"
       duration="500"
       repeatBehavior="reverse"
       bitmapFilter="{new spark.filters.GlowFilter()}">
   <s:SimpleMotionPath property="color" 
        valueFrom="0x00FF00" 
        valueTo="0x0000FF"/>
   <s:SimpleMotionPath property="blurX" 
        valueFrom="6" 
        valueTo="18"/>
   <s:SimpleMotionPath property="blurY" 
        valueFrom="6" 
        valueTo="18"/>
  </s:AnimateFilter>
  <esri:Extent id="initialExtent"
      xmin="-13635000" 
      ymin="4541000" 
      xmax="-13625000" 
      ymax="4547000">
   <esri:SpatialReference wkid="102100"/>
  </esri:Extent>
  <esri:SimpleLineSymbol id="sls" 
          width="3" 
          color="0xFF0000"/>
  <esri:SimpleMarkerSymbol id="sms"
         color="0xFF0000" />
 </fx:Declarations>
 
 <s:CheckBox id="box" 
    label="Line / Point"
    selected="true"
    change="onSelectionChange(event)" />
 
 <esri:Map id="map"
     extent="{initialExtent}"
     mapMouseDown="onMapClick(event)">
  <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
  <esri:GraphicsLayer id="gLayer" />
 </esri:Map>
 
 <s:Button label="Clear"
     click="onClearClick(event)"/>
 
</s:Application>
0 Kudos
AhmedFarghali
Emerging Contributor
Thanks mate,
but thats not exactly what I meant to do.
here is a modification of your code, with what I want, while running, if I pan or zoom (changing the extent), the Object moves on wrong path, because of the conversion from mapPoint to Screen Point ... something I have to do in the reDraw() function of the extentExchange event, but what ... ?!

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      xmlns:esri="http://www.esri.com/2008/ags"
      creationComplete="initial();">
 
 <s:layout>
  <s:VerticalLayout gap="10"
        paddingBottom="20"
        paddingLeft="20"
        paddingRight="20"
        paddingTop="20"/>
 </s:layout>
 <fx:Script>
  <![CDATA[
   import com.esri.ags.Graphic;
   import com.esri.ags.events.MapMouseEvent;
   import com.esri.ags.geometry.Polyline;
   import com.esri.ags.symbols.PictureMarkerSymbol;
   import com.esri.ags.symbols.SimpleMarkerSymbol;
   import com.esri.ags.symbols.Symbol;
   
   private var _polyline:Polyline;
   private var _points:Array = new Array();
   private var movObj:Graphic;
   
   var movIdx:Number = 0;
   var onMov:Boolean = false;
   
   protected function initial():void
   {
    pictureMarker.height=20;
    pictureMarker.width=40;
    
    movObj = new Graphic(new MapPoint(-13629302.512116898, 4545949.1442212695, new SpatialReference(102100)))
    movObj.symbol = new SimpleMarkerSymbol("circle",9);
    trkLyr.add(movObj);
   }
   
   protected function onMoveClick(event:MouseEvent):void
   {
    movIdx = 0;
    for each(var pnt:MapPoint in trackLine.paths[0] )
    {
     pnt.spatialReference = map.spatialReference;
     var p:Point = map.toScreen(pnt);
     _points.push(p);
    }  
    
    animation.target = movObj;
    playBack();
   }
   
   protected function playBack():void {
    if(movIdx < _points.length-1)
     onMov=true;
    else {
     onMov=false;
     movIdx = 0;
     _points = new Array();
    }
    if(onMov) {
     setSegmentPath(_points[movIdx].x,_points[movIdx].y,_points[movIdx+1].x,_points[movIdx+1].y);
     animation.play();
    }
   }
   
   protected function setSegmentPath(xstart:Number, ystart:Number, xend:Number, yend:Number):void
   {
    sX.valueFrom = xstart;
    sY.valueFrom = ystart;
    
    sX.valueTo = xend;
    sY.valueTo = yend;
    animation.motionPaths.pop();
    animation.motionPaths.push(sX,sY);
   }

   protected function reDraw():void {
    //Somthing I should do here
   }
   
   protected function goOn():void {
    movIdx++;
    playBack();
   }
   
  ]]>
 </fx:Script>
 
 <fx:Declarations>
  <s:Animate id="animation"
       repeatCount="1"
       duration="5000"
       effectEnd="goOn()">
   <s:SimpleMotionPath id="sX" property="x" />
   <s:SimpleMotionPath id="sY" property="y" />
   
  </s:Animate>
  <esri:Extent id="initialExtent"
      xmin="-13635000" 
      ymin="4541000" 
      xmax="-13625000" 
      ymax="4547000">
   <esri:SpatialReference wkid="102100"/>
  </esri:Extent>
  <esri:SimpleLineSymbol id="sls" 
          width="6" 
          color="0xFF00FF"/>
 </fx:Declarations>
 
 <!--mapMouseDown="onMapClick(event)"-->
 <esri:Map id="map"
     extent="{initialExtent}">
     <!--extentChange="reDraw()"-->
     
  <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
  <esri:GraphicsLayer id="gLayer" >
   <esri:Graphic id="track">
    <esri:geometry>
     <esri:Polyline id="trackLine" spatialReference="{new SpatialReference(102100)}">
      <fx:Array>
       <fx:Array>
        <esri:MapPoint x="-13629302.512116898" y="4545949.1442212695"/>
        <esri:MapPoint x="-13628433.040920155" y="4546016.026621019"/>
        <esri:MapPoint x="-13628327.940006264" y="4544449.067541175"/>
        <esri:MapPoint x="-13626541.2244701" y="4544582.832340674"/>
        <esri:MapPoint x="-13626665.434641063" y="4546379.102505373"/>
       </fx:Array>
      </fx:Array>
     </esri:Polyline>
    </esri:geometry>
    <esri:symbol>
     <esri:SimpleLineSymbol width="3" color="0xFF0000"/>
    </esri:symbol>
   </esri:Graphic> 
  </esri:GraphicsLayer>
  <esri:GraphicsLayer id="trkLyr" >
   
  </esri:GraphicsLayer>
 </esri:Map>
 
 <s:Button label="Move"
     click="onMoveClick(event)"/>
 
</s:Application>
0 Kudos
IvanBespalov
Frequent Contributor
Ahmed, your code compilation faults 😞

Another view to your task realization.
1 - Use ESRI geometries = no conversion between Point and MapPoint
2 - Create/Generate additioanal points for tracking.
3 - Quickly replace points of the object to move it without delay ~ animation.

try it
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"        xmlns:s="library://ns.adobe.com/flex/spark"        xmlns:mx="library://ns.adobe.com/flex/mx"        xmlns:esri="http://www.esri.com/2008/ags"       creationComplete="onCreationComplete(event)">    <s:layout>   <s:VerticalLayout gap="10"         paddingBottom="20"         paddingLeft="20"         paddingRight="20"         paddingTop="20"/>  </s:layout>  <fx:Script>   <![CDATA[    import com.esri.ags.Graphic;    import com.esri.ags.events.PanEvent;    import com.esri.ags.geometry.Polyline;    import com.esri.ags.symbols.SimpleMarkerSymbol;    import com.esri.ags.tasks.supportClasses.DensifyParameters;        import mx.events.FlexEvent;    import mx.rpc.AsyncResponder;    import mx.rpc.Fault;        private var points:Array = new Array();        private var moveObj:Graphic;        private var moveIndex:int;          private var timer:Timer;        protected function onCreationComplete(event:FlexEvent):void    {     initMovingGraphic();     createTrackPoints();     initTimer();    }        private function initMovingGraphic():void    {     moveObj = new Graphic(new MapPoint(-13629302.512116898, 4545949.1442212695, map.spatialReference))     moveObj.symbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 9);     trackLayer.add(moveObj);    }        private function initTimer():void    {     timer = new Timer(20);     timer.addEventListener(TimerEvent.TIMER, onTimerTick);    }        private function createTrackPoints():void    {     var densifyParams:DensifyParameters = new DensifyParameters();     densifyParams.geometries = [trackLine];     densifyParams.maxSegmentLength = 5;          geometryService.densify(densifyParams, new AsyncResponder(onDensifyResult, onDensifyFault));    }        protected function onDensifyResult(result:Array, token:Object = null):void    {     points = new Array();     var resultLine:Polyline = result[0];     for each(var pt:MapPoint in resultLine.paths[0] )     {      points.push(pt);     }    }        protected function onDensifyFault(fault:Fault, token:Object = null):void    {     trace("densify faults " + fault.faultString + " " + fault.message.toString());    }        protected function onMoveClick(event:MouseEvent):void    {     timer.stop();     moveIndex = 0;     timer.start();    }        protected function onTimerTick(event:TimerEvent):void    {     moveObj.geometry = points[moveIndex];     moveIndex++;    }     protected function onPauseResumeClick(event:MouseEvent):void    {     if (timer.running)     {      timer.stop();      btnPauseResume.label = "Resume";     }     else     {      timer.start();      btnPauseResume.label = "Pause";     }    }     private var mustResumeTracking:Boolean = false;        protected function onMapPanStart(event:PanEvent):void    {     if (timer.running)     {      timer.stop();      mustResumeTracking = true;     }    }     protected function onMapPanEnd(event:PanEvent):void    {     if (mustResumeTracking)     {      timer.start();      mustResumeTracking = false;     }    }    ]]>  </fx:Script>    <fx:Declarations>   <esri:Extent id="initialExtent"       xmin="-13635000"        ymin="4541000"        xmax="-13625000"        ymax="4547000">    <esri:SpatialReference wkid="102100"/>   </esri:Extent>   <esri:GeometryService id="geometryService"          url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer" />  </fx:Declarations>    <esri:Map id="map"      extent="{initialExtent}"      panStart="onMapPanStart(event)"      panEnd="onMapPanEnd(event)">      <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>      <esri:GraphicsLayer>        <esri:Graphic>     <esri:geometry>      <esri:Polyline id="trackLine" spatialReference="{new SpatialReference(102100)}">       <fx:Array>        <fx:Array>         <esri:MapPoint x="-13629302.512116898" y="4545949.1442212695"/>         <esri:MapPoint x="-13628433.040920155" y="4546016.026621019"/>         <esri:MapPoint x="-13628327.940006264" y="4544449.067541175"/>         <esri:MapPoint x="-13626541.2244701" y="4544582.832340674"/>         <esri:MapPoint x="-13626665.434641063" y="4546379.102505373"/>        </fx:Array>       </fx:Array>      </esri:Polyline>     </esri:geometry>     <esri:symbol>      <esri:SimpleLineSymbol width="3" color="0xFF0000"/>     </esri:symbol>    </esri:Graphic>        </esri:GraphicsLayer>      <esri:GraphicsLayer id="trackLayer" />    </esri:Map>    <s:HGroup gap="20"       width="100%">      <s:Button label="Move"       click="onMoveClick(event)"/>      <s:Button id="btnPauseResume"        label="Pause"       click="onPauseResumeClick(event)"/>     </s:HGroup>   </s:Application>


Good luck
0 Kudos
AhmedFarghali
Emerging Contributor
Well, thanks mate,
That seems much close to my intention, while its complicated a little, but its helpful.
The last code had a couple of unused lines.
Still wanna test it with Arc Server 9.3 and with different geometry services.

little questions using the timer:
*Can I modify the speed, I mean with tweens I can set the time for the animation, that control the speed, I got that I can change the maxSegmentLenght, but I didn't get how it works.
*what exactly the use of the "Densify" parameters and method.

and many thanks.
0 Kudos
IvanBespalov
Frequent Contributor
*Can I modify the speed, I mean with tweens I can set the time for the animation, that control the speed, I got that I can change the maxSegmentLenght, but I didn't get how it works.

information about flash.utils.Timer in Adobe reference

[/HR]

*what exactly the use of the "Densify" parameters and method.

from ESRI REST API help
This operation densifies geometries by plotting points between existing vertices.


[/HR]

How it is work?
What is "Densify"?
Where is FLEX API reference?

All ESRI help Pages in 1 😉

Good luck.
0 Kudos