Guide to amazing maps with ...

Mercator.swc

  1. Installing
  2. Creating the map
  3. Setting the center
  4. Exploring the maps
  5. Getting the center of a map
  6. Changing colors
  7. Interaction with the map
  8. Working with objects
  9. Map Locations

Installing

In Flex copy Mercator.swc to your libs folder. In Flash Studio copy it into your component folder!

Creating the map

Creating a map is simple. Start with the following code! ( Please look at the sources of the examples to see how to use the component in Flex )

import org.dschini.ui.maps.MercatorProjection;
import org.dschini.data.ui.maps.WorldMapData;

public var projection:MercatorProjection = new MercatorProjection();
public function startup():void{
    projection = new MercatorProjection();
    viewer.addChild( projection );
}

This will create a map centered where latitude and longitude is 0.

You probably want to set the size of the map and center it.

projection.width = 600;
projection.height = 500;
projection.x = 300;
projection.y = 250;

Setting the center

One important function is the setCenter function. It expects at least a Point which represents the new center and a zoom factor.

var point:Point = new Point();
point.x = 100;
point.y = -100;
projection.setCenter( point, 1 );

Exploring the maps

Mercator.swc holds all country maps of the world. And they are mainly structured not by political but geographical view.

Continents

var africaMap:Map = projection.map.africaMap;
var europeMap:Map = projection.map.europeMap;
var northAmericaMap:Map = projection.map.northAmericaMap;
var southAmericaMap:Map = projection.map.southAmericaMap;
var oceaniaMap:Map = projection.map.oceaniaMap;
var asiaMap:Map = projection.map.asiaMap;

Countries

var germanyMap:Map = projection.map.europeMap.germanyMap;
var chinaMap:Map = projection.map.asiaMap.chinaMap;
var australiaMap:Map = projection.map.oceaniaMap.australiaMap;
var usaMap:Map = projection.map.northAmericaMap.usaMap;

Getting the center of a map

Another quite important function is the getCenter function which calculates the center of a map for later use.

var usaCenter:Point = projection.getCenter( usaMap );
projection.setCenter( usaCenter, 4 );

You may also use the getZoom function to calculate the best possible zoom.

var usaCenter:Point = projection.getCenter( usaMap );
var usaZoom:Number = projection.getZoom( usaMap );
projection.setCenter( usaCenter, usaZoom );

Changing colors

You may change all possible colors, but a little bit of background information is required: Mercator.swc holds all maps of the world structured into Sprites (continents) and subsprites (countries). Each Sprite can be used with its corresponding map class. Now the clue: Each map-class holds a corresponding data class which defines the design of the map.

import org.dschini.ui.maps.world.europe.GermanyMap;
import org.dschini.data.ui.maps.world.europe.GermanyMapData;

Now you may want to change the color of germany: Here is the example:

import org.dschini.data.ui.maps.WorldMapData;
import org.dschini.data.ui.maps.MapData;
import org.dschini.data.ui.maps.world.EuropeMapData;
projection.map.data = new WorldMapData();
var germanyMapData:MapData = EuropeMapData(WorldMapData(projection.map.data).europeMapData).germanyMapData
germanyMapData.shapeColorTransform = new ColorTransform();
germanyMapData.shapeColorTransform.color = 0x000000;
germanyMapData.stateLinesVisible = true;
germanyMapData.stateLinesColorTransform = new ColorTransform();
germanyMapData.stateLinesColorTransform.color = 0xffffff;
projection.render();

Let's examine that code a little bit. Before changing data classes you first have to initialize the projection of a single map with the corresponding data class.

projection.map.data = new WorldMapData();

In this case we initialize the world with the WorldMapData class. This will then initialize all the submaps with their corresponding data classes automatically. But you may also do the following:

WorldMapData(projection.map.data).europeMapData = new EuropeMapData();

This would initialize the europeMap and all the countries within europe with it's corresponding data class. Mercator.swc has a hierachical structure. The world holds continents which hold countries so ...

EuropeMapData(WorldMapData(projection.map.data).europeMapData).germanyMapData = new GermanyMapData();

would only initialize the germanyMap with it's corresponding data file. However in most cases you want to initialize the whole world like in the example.

So now we have assigned data classes to the map. The example now sets the shapeColorTransform and the statelinesColorTransform. Yes Mercator.swc uses the ColorTransform object to do color changes. For several static reasons. Integers and String are copied by value. Object not! So you may assign single Color TransForm instances to multiple maps. If you are familiy with ColorTransform you notice that this offers a huge range of possibilities.

One more thing you should know is that when the world is initialized with a data class it sets the visibility of all stateLines to false because Mercator.swc now guesses you want to create amazing geo aps :) where stateLines would display at a later point within the application. Now.. beside stateLines we can also change the shapeColor, the backgroundColor and the countryLines of the world. Changing the backgroundColor of a map will change the backgroundColor of the whole world. CountryLines may only be changed for continents. StateLines only for countries. All the properties have 1 thing in common. They are organized hierachically, so you may change all these properties in the WorldMapData class and this would affects all ContinentClasses and Country Classes. But in return you may change a country data class later. Then this would only affect the country class. Got the picture?

If you are confused now about these damn data classes... well here's how it works. It's speed! You customize the map and once you're done! You render! Yes!.. Imagine what would happen if you render the map each time you change something.

projection.render();

This renders the whole world. But you may also render only specific parts of the world. Maybe only those that are currently used within you applications. Well..

projection.map.europeMap.render();
projection.map.europeMap.germanyMap.render();

Same logic again! Rendering the world will render all the continents + their countries. Rendering a continent will render their countries only...

Now ... you come that far! That's it. And you finished the most difficult part of Mercator.swc. The data files... the hierachical structure... the rendering

Interacting with the map

Mercator.swc implements all available Mouse events. See the example!

projection.mouseEnabled = true
projection.doubleClickEnabled = true;
projection.addEventListener( MapEvent.CLICK, mapClickHandler );
private function mapClickHandler( event:MapEvent ):void
{
}

Mouse Events are disabled by default. Once they're enabled you may add event listeners on all known Mouse events. But you may not use the MouseEvent anymore. Instead we use the MapEvent. MapEvent internally overrides all MouseEvent functions and once dispatched delievers more usefull information about the MouseEvent.

private function mapClickHandler( event:MapEvent ):void
{
  trace( MapPointData(event.data).x );
  trace( MapPointData(event.data).y );
  trace( MapPointData(event.data).lat );
  trace( MapPointData(event.data).lon );
}

The MapEvent is a slightly modified version of the MouseEvent class. See the following asciiart:
event = MapEvent
  |-- .data = MapLocationData
  |-- .event = MouseEvent

So there is basically all you need! Say you now clicked into the german map. Let's look deeper into event.data ... the MapPointData:

MapPointData(event.data).target === [object GermanyMap]
MapPointData(event.data).target.parent === [object EuropeMap]
MapPointData(event.data).target.parent.parent === [object WorldMap]

Besides calculating the latitude and longitude for a single click a MapPointData class also holds references to the corresponding MapClass. You may now also detect which country or continent the user clicked. You may use setCenter, getZoom oder getCenter depending on what you think fits best to you application. But you may also addMarkers, connections, lines, calculate distances, add Sprites or MovieClips and .... request localized data for that map.

projection.map.data.lang = "en"
Map(MapPointData(event.data).target).data.title ... prints out "Germany";
Map(Map(MapPointData(event.data).target).parent).data.title ... prints out "Europe";
projection.map.data.lang = "de"
Map(MapPointData(event.data).target).data.title ... prints out "Deutschland";
Map(Map(MapPointData(event.data).target).parent).data.title ... prints out "Europa";

Event listeners are removed once you call the dispose function. See the api docs here.

Working with objects

I call objects here whatever you place on the map. Example:

private function mapClickHandler( event:MapEvent ):void
{
  projection.addMarker( MapPointData(event.data) );
}

Wow! A really dark germany and a red dot! ... You may optionally use the second parameter to reference an instance of a Sprite you previously created! A red dot does not look that perfect! However, all following functions (addMarker,addConnection,addCircle,...) expect MapPointData classes that you can also create yourself.

var mapPointData:MapPointData = new MapPointData(); mapPointData.lat = 10;
mapPointData.lon = 10;
projection.addMarker( mapPointData );

What else? Conversion... in any direction. Good luck because I am getting bored of writing guides. If you come that far now. You'll be able to figure out the rest yourself! Look at the api docs. But hey... I think mentioning the conversion function is worth it.

projection.getXFromLon( 20.0000 );
projection.getYFromLat( 10.0000 );
projection.getLonFromX( 10 );
projection.getLatFromY( 20 );

Map Locations

Download Mercator.swc for free. Contact me for additional information! manfred.weber(at)gmail(dot)com