AFComponents.com

Creating custom position control for GMap
Updated: Jun 3, 2007   Views: 18631  
Description: In this tutorial we are going to learn how to create custom controls for GMap. You can also download a fully functional position control form the sources.
Download source files

This tutorial uses advanced Action Script techniques. If you're not familliar with OOP, the information provided may be difficult to understand. Anyway please feel free to download the sources and use the control in your projects.

In this tutorial we are going to create a "Map Position" control using subclassing.
   
 

All the controls that are included in the GMap, along with custom AFC controls should extend native GControl class. It provides basic functionality which includes:

  • Accuiring new Movie Clip object inside the GMap component
  • Loading standard tuneable properties from the initizliation object (align, padding, etc)
  • Positioning the control inside GMap component's GUI
  • Methods for hiding and showing the control
  • Initalizing Event Dispathcer object to fire events which will be caught by GMap core

  • More information is provided in the GControl.as file's header which can be found in the sources package for this tutorial.

    Preparation steps:

  • Create a folder for the project files
  • Place GControl.as inside this folder from the sources package
  • Create new Flash file and save it in the same folder
  • Drag GMap component on Stage and give it an instance name "gMap"

  • After preparation has been completed, we can start developing our custom control. First, let's create a new Action Script file. Select File -> New, then choose "ActionScript file" line and click "OK" button at the bottom of the window.
    New and empty ActionScript file will be created named Script-1, click File -> Save and save the file in the same folder where you .fla file is. Name the file "customControl" (the name is case-sensitive!).
    Add this AS to the file:

    class customControl extends GControl
    {

        // class constructor (1)
        function customControl(initObject:Object)
        {
            // call super-class contructor, pass initialization object to it (2)
            super(initObject);
        }

    }


    We have created a customControl class that extends GControl class. We have also added a class constructor function (1). The first thing to do in this function is to call super-class constructor passing it an initialization object (2).

    The GControl class loads parameters from initialization object. For undefined properties it loads default values. Each control in GMap has it's own default placement, this way when you add controls to the map, they don't overlap each other. We also need to give our control a default placement. Let's align our control bottom-right corner with 10 horizontal and 10 vertical padding.

    // define default component alignment and padding
    if (!initObject.hasOwnProperty("align") || initObject == undefined) align = "bottom-right";
    if (!initObject.hasOwnProperty("padding") || initObject == undefined) padding = {x:10, y:10};


    For each propery, we check if it is defined in initialization object and also we check if this object have been passed to the constructor. If not, then we set the default value. Otherwise the values will be loaded in the super-class constructor.

    After a new movie clip has been created by a GUI manager, the control has been registered, the method init() will be invoked. We need to define it, to create all the control's child elements. In our case we should draw control's background and create 2 text fields, one for latitude and one for longitude.

    function init()
    {

        // define line thickness and dimensions of the control
        var line_width:Number = 1;
        var width:Number = 100;
        var height:Number = 50;

        // create all needed mc's that will be used inside our control
        // _mc - it is the root movie clip for the control
        _bg_mc = _mc.createEmptyMovieClip("bg_mc", _mc.getNextHighestDepth());
        _lat_txt = _mc.createTextField("lat_txt", _mc.getNextHighestDepth(), 5, 5, width - 10, 20);
        _lng_txt = _mc.createTextField("lng_txt", _mc.getNextHighestDepth(), 5, 25, width - 10, 20);
    }


    As you have noticed we have added 3 variables: line_width, width and height. We did it, so the code will be easier to modify. For example you can change the size of the control just adjusting width and height variables.

    Next, let's draw our control's background. We will draw the control in Google-style: black border, white background and a grey shading.

    // draw rectangle on the background
    with(_bg_mc)
    {
        // draw back
        lineStyle(line_width, 0x0, 100, false, "normal", "square", "miter", 0);
        beginFill(0xffffff, 100);
        moveTo(0, 0);
        lineTo(width, 0);
        lineTo(width, height);
        lineTo(0, height);
        lineTo(0, 0);
        endFill();

        // draw shading
        lineStyle(line_width, 0xCCCCCC, 100, false, "normal", "square", "miter", 0);
        moveTo(line_width, height - line_width);
        lineTo(width - line_width, height - line_width);
        lineTo(width - line_width, line_width);
    }


    Now, let's hadle our text fields. We can apply formatting to the text, so that it will look nice. Please note, that we can't apply text formatting if our text field is empty. To avoid this, we set the default text.

    // set default text
    _lat_txt.text = "LAT: 0.0000";
    _lng_txt.text = "LNG: 0.0000";

    // text fields' style
    _lat_txt.selectable = false;
    _lng_txt.selectable = false;

    // create new text format
    var fmt = new TextFormat();
    fmt.font = "_sans";
    fmt.bold = true;

    // apply formating to first 4 letters
    _lat_txt.setTextFormat(0, 4, fmt);
    _lng_txt.setTextFormat(0, 4, fmt);

    // apply format to numbers
    fmt.bold = false;
    _lat_txt.setTextFormat(4, 10, fmt);
    _lng_txt.setTextFormat(4, 10, fmt);


    Basically we can test our control now. First save your class file, then go to the main .fla file you have created. Open actions panel and add this AS for the first frame:
    // add our custom control to the map
    var myControl:customControl = new customControl();
    gMap.addControl(myControl);


    In tnis code we simple create new control object and add it to the map. Now press CTRL+Enter or choose Control -> Test Movie. You should see our control in the bottom-right corner of the map with the text LAT: 0.0000 and LNG: 0.0000.

    If everything is alright, let us continue, otherwise correct the errors. You may have noticed that our control is "dead" at the moments: the text doesn't change while you drag the map. To fix that we need to catch MAP_POSITION_CHANGED event and update the text. To access main GMap object we use _owner.core reference.

    We add this AS to init() function:

    // add event listener to catch MAP_POSITION_CHANGED event
    _owner.core.addEventListener("MAP_POSITION_CHANGED", this);


    We also write an event handler function inside the class:

    public function MAP_POSITION_CHANGED(evt:Object)
    {
        // set new text for text fields
        // note that lat and lng is taken from the event object
        _lat_txt.text = "LAT: " + formatNumber(evt.newLat, 4);
        _lng_txt.text = "LNG: " + formatNumber(evt.newLng, 4);

        // create new text format
        var fmt = new TextFormat();
        fmt.font = "_sans";
        fmt.bold = true;

        // apply formating to first 4 letters
        _lat_txt.setTextFormat(0, 4, fmt);
        _lng_txt.setTextFormat(0, 4, fmt);

        // apply format to numbers
        fmt.bold = false;
        _lat_txt.setTextFormat(4, 10, fmt);
        _lng_txt.setTextFormat(4, 10, fmt);
    }


    We set new text for the text fields and apply the same formatting as we did during the initialization. One function is still missing: formatNumber(). This function rounds and formats latitude and longitude to a specified number of decimal places. We are not going to explain the code for it, just add it's AS to your class:

    private function formatNumber(num:Number, dec:Number):String
    {
        var str:String = String(num);
        if (str.indexOf(".") < 0) str += ".";
        dec = dec < 0 ? dec-3 : dec-(str.length-str.indexOf(".")-2);
        var numbers:Array = str.split("");
        while ((dec--)>0) { numbers.push(0); }
        while ((dec++)<0) { numbers.splice(numbers.length-1, 1); }
        if(numbers[numbers.length-1]==".") numbers.splice(numbers.length-1, 1);
        return numbers.join("");
    }


    Finally, test the movie.


    © 2005-2007 advanced flash components