Select to view content in your preferred language

Custom com.esri.ags.symbols.Symbol

3152
10
03-16-2011 09:26 AM
Ganael_Jatteau
Emerging Contributor
Hello!

I'm trying to write a custom symbol that extends com.esri.ags.symbols.Symbol to display my own UIComponent on the map.

I did some tests by overriding the method createSwatch but it doesn't get called...

Anyone has managed to do that ? Is there any example somewhere ?

Thanks a lot in advance
Tags (2)
0 Kudos
10 Replies
RobertScheitlin__GISP
MVP Emeritus
Ganael,

   You need to be overriding the draw method. The createswatch method is only used in custom development like creating a legend.

Here is some code from Mansour's Blog. http://thunderheadxpler.blogspot.com/

package com.esri.overlay
{
    import com.esri.ags.Map;
    import com.esri.ags.geometry.Geometry;
    import com.esri.ags.geometry.MapPoint;
    import com.esri.ags.symbol.Symbol;
    
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.geom.Matrix;
    import flash.net.URLRequest;
    import flash.system.Capabilities;
    import flash.system.LoaderContext;
    
    import mx.controls.Label;

    public class OverlaySymbol extends Symbol
    {
        private const m_matrix:Matrix = new Matrix();
        private var m_bitmap:Bitmap;
        
        private var m_source:Object;
        private var m_width:Number = 0;
        private var m_height:Number = 0;
        private var m_rotation:Number = 0;
        private var m_iname:String = "";
        private var m_alpha:Number = 1;

        public function OverlaySymbol(source:String=null, width:Number=0,
            height:Number=0, rotation:Number=0, alpha:Number=1)
        {
            m_source = source;
            m_width = width;
            m_height = height;
            m_rotation = rotation;
            m_alpha = alpha;
        }

        [Bindable]
        public function get source():Object
        {
            return m_source;
        }

        public function set source(value:Object):void
        {
            if (value != m_source)
            {
                m_bitmap = null;
                m_source = value;
                dispatchEventChange();
            }
        }

        [Bindable]
        public function get rotation():Number
        {
            return m_rotation;
        }

        public function set rotation(value:Number):void
        {
            if (value != m_rotation)
            {
                m_rotation = value;
                dispatchEventChange();
            }
        }

        [Bindable]
        public function get width():Number
        {
            return m_width;
        }

        public function set width(value:Number):void
        {
            if (value != m_width)
            {
                m_width = value;
                dispatchEventChange();
            }
        }

        [Bindable]
        public function get height():Number
        {
            return m_height;
        }

        public function set height(value:Number):void
        {
            if (value != m_height)
            {
                m_height = value;
                dispatchEventChange();
            }
        }
        
        [Bindable]
        public function get alpha():Number
        {
            return m_alpha;
        }

        public function set alpha(value:Number):void
        {
            if (value != m_alpha)
            {
                m_alpha = value;
                dispatchEventChange();
            }
        }

        override public function clear(sprite:Sprite):void
        {
            sprite.graphics.clear();
        }

        override public function draw(sprite:Sprite, geometry:Geometry, attributes:Object, map:Map):void
        {
            if (geometry is MapPoint)
            {
                drawOverlay(sprite, MapPoint(geometry), map);
            }
        }

        private function drawOverlay(sprite:Sprite, mapPoint:MapPoint, map:Map):void
        {
            if (m_bitmap == null)
            {
                if (m_source is Class)
                {
                    m_bitmap = new m_source();
                    drawBitmap(sprite, mapPoint, map);
                }
                else if (m_source is String)
                {
                    var url : String = String(m_source);
                    if( Capabilities.isDebugger == true )
                    {
                        url = url + (url.indexOf("?") > -1 ? "&debug=true" : "?debug=true"); 
                    } 
                    const loaderContext:LoaderContext = new LoaderContext();
                    loaderContext.checkPolicyFile = true;

                    const loader:Loader = new Loader();
                    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
                    loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoaderError );   
                    loader.load(new URLRequest(url), loaderContext);
                    
                    function completeHandler(event:Event):void
                    {
                        const loaderInfo:LoaderInfo = event.target as LoaderInfo;
                        m_bitmap = loaderInfo.content as Bitmap;
                        drawBitmap(sprite, mapPoint, map);
                    }
                    
                    function onLoaderError(evt:Event):void
                    {
                     //do nothing
                    }
                }
            }
            else
            {
                drawBitmap(sprite, mapPoint, map);
            }
        }

        private function drawBitmap(sprite:Sprite, mapPoint:MapPoint, map:Map):void
        {
            const width2:Number = m_width / 2.0;
            const height2:Number = m_height / 2.0;
            const xmin:Number = toScreenX(map, mapPoint.x);
            const xmax:Number = toScreenX(map, mapPoint.x + m_width);
            const ymax:Number = toScreenY(map, mapPoint.y);
            const ymin:Number = toScreenY(map, mapPoint.y + m_height);

            const width:Number = xmax - xmin;
            const height:Number = ymax - ymin;

            m_matrix.a = width / m_bitmap.bitmapData.width;
            m_matrix.d = height / m_bitmap.bitmapData.height;
            m_matrix.tx = width / m_bitmap.bitmapData.width;
            m_matrix.ty = height / m_bitmap.bitmapData.height;
            
            sprite.x = toScreenX(map, mapPoint.x);
            sprite.y = toScreenY(map, mapPoint.y);
            sprite.rotation = m_rotation;
            sprite.alpha = m_alpha;

            sprite.graphics.beginBitmapFill(m_bitmap.bitmapData, m_matrix, false, true);
            sprite.graphics.drawRect(m_matrix.tx, m_matrix.ty, width, height);
            sprite.graphics.endFill();
            var tLabel:Label = new Label();
            tLabel.text = m_iname;
            tLabel.x = sprite.x + 10;
            tLabel.y = sprite.y + 10;
            sprite.addChild(tLabel);
        }

    }
}
0 Kudos
Ganael_Jatteau
Emerging Contributor
Thanks Robert

I will search how I can transfer the content of my UIComponent into the Sprite given by the method draw(). I'll post some code when I have the solution.
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Ganael,

   Actually you would just be adding your UIComponent to the sprite. The sprite is already provided.

sprite.addChild(yourUIComponent);
0 Kudos
Ganael_Jatteau
Emerging Contributor
I tried a quick example using sprite.addChild(UIComponent) but the symbol seems empty. At least, it doesn't displays on the map...

public override function draw(sprite:Sprite, geometry:Geometry, attributes:Object, map:Map):void
            {
                if (geometry is MapPoint)
    {
     var label:Label = new Label();
     sprite.x = toScreenX(map, (geometry as MapPoint).x);
     sprite.y = toScreenY(map, (geometry as MapPoint).y);
     label.text = "dummy label";
     label.x = sprite.x;
     label.y = sprite.y;
     label.alpha = 1;
     sprite.addChild(label);
     sprite.width = 50;
     sprite.height = 20;
    }
    else throw new Error("not a map point ");
            }
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Ganael,

   Here is a VERY simple example one that works.

package org.calhoun.county
{
 import com.esri.ags.Map;
 import com.esri.ags.geometry.Geometry;
 import com.esri.ags.geometry.MapPoint;
 import com.esri.ags.symbols.Symbol;
 
 import flash.display.Sprite;
 
 import flash.text.TextField;
 import flash.text.TextFieldAutoSize;
 
 public class MySymbol extends Symbol
 {
  public function MySymbol()
  {
   super();
  }
  
  override public function clear(sprite:Sprite):void
  {
   sprite.graphics.clear();
  }
  
  override public function draw(sprite:Sprite, geometry:Geometry, attributes:Object, map:Map):void
  {
   if (geometry is MapPoint)
   {
    var m_textField:TextField;
    
    sprite.x = toScreenX(map, (geometry as MapPoint).x);
    sprite.y = toScreenY(map, (geometry as MapPoint).y);
    
    m_textField = new TextField();
    m_textField.name = "textField";
    m_textField.mouseEnabled = false;
    m_textField.mouseWheelEnabled = false;
    m_textField.selectable = false;
    m_textField.autoSize = TextFieldAutoSize.CENTER;
    m_textField.text = "Dummy Text";
    
    sprite.addChild(m_textField);
    sprite.width = 50;
    sprite.height = 20;
   }
   else throw new Error("not a map point ");
  }

 }
}
0 Kudos
Ganael_Jatteau
Emerging Contributor
Thanks, your example works well. So I understand it won't work to add an mx or spark component to the sprite.
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Ganael,

   I am not sure on the exacts of the requirements but it seems like spark primitives are necessary.
0 Kudos
SarahBurgin
Emerging Contributor
I am not sure on the exacts of the requirements but it seems like spark primitives are necessary.


Hi, this topic looks interesting as I'd like to add spark.primitives.Graphic (specifically spark.primitives.Ellipse) objects to a map layer... is this something that's possible to do? Thanks!
0 Kudos
SarahBurgin
Emerging Contributor
I'm making some progress. Starting from the simple example provided by rscheitlin above, I've been able to create a similar custom symbol and display it against the map using a GraphicsLayer. My draw method firstly creates a spark.primitives.Ellipse, then creates a spark.primitives.Graphic and uses addElement(ellipse) on the graphic before then invoking addChild(graphic) on the sprite.

This is somewhat successful and I've also been able to scale the custom ellipse symbols so that they maintain the correct size whenever the map is zoomed, however it seems that sprite.x and sprite.y locate the top-left corner of the Ellipse instead of the centre, so my custom symbol appears in the wrong place on the map. I haven't been able to resolve this, unfortunately.

The issue is also further complicated when I apply the necessary rotation to each Graphic. This turns out to likewise rotate the symbol around its top-left corner whereas I need the ellipses to be rotated around their centre instead.

Do any of the expects here know of ways to correct these problems please? I hope so - thanks!
0 Kudos