Tiago's Weblog Code & Technology Aficionado – Come for the Flash, stay for more!

Flash CS3: googleAnalytics like map overlay

To finish this tutorial you need to DOWNLOAD this .zip file

A few of you are for sure using Google Analytics to view statistics of who is visiting your site or blog, for sure you've noticed the map overlay showing you how many hits have come from a country / state / city. Looks pretty cool is more or less useful, depending which kind of business you running. Anyway a few days ago I've got an email from Alex asking me for hints on how to create someting similar to that Map Overlay like Google has. First I thought that wouldn't be a big problem, since I'm still migrating to AS 3.0 I'm having a bit of a hard time moving on, anyway I gave it a try and the result of it, is this tutorial.

I'm creating the map overlay with only one County (USA) and with three states activated, just because a) I don't know all the states from top of my head and b) I don't have a use for it at the moment. If you wondering why I've used the US, like I've said before when using Google Analytics you find out from where your visitors are coming from, and on my blog, we're talking about 60% of them are coming from the USA. ;)

So let's get started by grabbing a nice vectorized map from the US, you can use the one I provided at the beginning of the tutorial.
Start up Flash CS3, create a new action script 3.0 document and import the usMaps.ai file I've provided.
Flash will come up with a new dialog box, this is one of the newest features in Flash CS3, the improved import of other Adobe Applications like Photoshop or Illustrator.

Import Dialog box when importing Illustrator files .AI
On the left hand side you will see a bunch of layers, which were the layers created in Illustrator you can either import all together or select only those you want, on the right hand side you have the options for every single/all selected layers, on the bottom you have further options like the convert layers combo box which allows you to convert layers to a single flash layer, key frames or to multiple flash layers.
For our example we are going to choose this settings:

- Select all Layers available by selecting one of them and then pressing CTRL+A.
- Check the CreateMovieClip check box and make sure that the registration point in centered.
- Leave the bottom settings as they are (Single Flash layer and both check boxes unchecked)

Press ok, and Flash will import & convert the selected layers to more flash friendly movie clips.

When you open your library tab you will find a 2 new objects inside, a movieclip and a folder containing all layers that have been converted to movieclips, now you just need to drag & drop your main movieclip to the stage.
Library Contents

Now we are almost ready to code, there are a few things that I need to point out before we move on.

In case you using my sample map, you will notice that inside the mainmovieclip you'll find 2 movieclips, this happens because Flash imports the layer & the path and converts each one to a movieclip. You can work around this issue by selecting each single path on the Import dialog box, check convert to movieclip and assign a new name.

I can live with my solution since it had to be delivered in a very short amount of time and I was more worried about the code then the functionality of the map, as it can be replaced easily.

If you continue to work with my file, let's double click on the mainmovieclip and again on one of the states, now give the selected movieclip an instance name, preferably the correct name of the state ;) . "for this tutorial I'm only using 3 states, "California, Texas and Florida". Feel free to do all or do the ones you want."
Do that as well for Texas & Florida Using the same procedure as mentioned above.

Last but not least create 3 dynamic text fields where you have some free space (the map is quite big and assign them these instance names.
Textfields with their appropriate instance names

Now let's get our hands dirty with some coding
First we need to setup a proper xml file where the informations of our feed are being delivered from.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<mainmap>
	<states>
		<state>
		<id>0</id>
		<name>California</name>
		<population>12800000</population>
		<other>Surfin USA</other>
		</state>
	</states>
	<states>
		<state>
		<id>1</id>
		<name>Texas</name>
		<population>22800000</population>
		<other>What do you know about Texas?</other>
		</state>
	</states>
	<states>
		<state>
		<id>2</id>
		<name>Florida</name>
		<population>32800000</population>
		<other>Florida is also called the sunny state</other>
		</state>
	</states>
</mainmap>

save it on the same location as your flash project with the name infoFeed.xml

Now back to our Flash Environment, we should start to create the Actionscript blocks for the map to work properly.
To keep the project nice & tidy lock the map layer and create a new layer above it and rename it to actions, lock that layer as well, select the first frame and press F9 to open the actionscript panel.

I will try to explain every line of code as much as I can, at the bottom of the tutorial you'll find the complete code, so if you just want to copy & paste scroll down all the way to the bottom.

ACTIONSCRIPT
You still with me? In that case you want to learn something :)

1
var contentArray:Array = new Array();

The first line of our code defines a new Array called contentArray which will be holding the request data from the XML file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function init():void {
	var infoFeedXML:XML = new XML();
	infoFeedXML.ignoreWhitespace = true;
	var XMLURL:URLRequest = new URLRequest("infoFeed.xml");
	var myLoader:URLLoader = new URLLoader(XMLURL);
	myLoader.addEventListener("complete", xmlLoaded);
 
	function xmlLoaded(event:Event):void {
		infoFeedXML = XML(myLoader.data);
		for (var i:int = 0; i < infoFeedXML.states.length(); i++) {
			var index:Number = infoFeedXML.states.state[i].id;
			var usState:String = infoFeedXML.states.state[i].name;
			var population:String = infoFeedXML.states.state[i].population;
			var other:String = infoFeedXML.states.state[i].other;
			contentArray.push({identity:index,name:usState,popul:population,custom:other});
		}
	}
}

Line 1: This is our function called init which will handle all the needed procedures as soon as the swf is loaded
Line 2: Then we create a new XML object called infoFeedXML I'm using the same name as the physical .xml so that I know which Object I am loading / creating
Line 3: As already on earlier versions of Flash, we tell Flash to ignore the white spaces that an xml may have, with this you can be sure that your XML will be parsed correctly even if you have 100's of whitespaces in between the lines
Line 4: XMLURL is quite self explanatory, it's a URLRequest method holding the URL to our .xml file
Line 5: Then we create an URLLoader Object that will download the data from our .xml file
Line 6: Next we assign an EventListener that waits until all the data has been downloaded and calls up the function xmlLoaded
Line 7: Here's the function that you've been waiting for, this function is being called by the listener if you look one live above you will find it ;)
Line 8: infoFeedXML finally get's his data from our URLloader object, that downloaded the required data
Line 9: As with earlier versions of Flash the for.. loop is still around "lucky us" and it's still rocking. The for loop checks for the amount of state nodes and replies with a number "don't forget that it will start with 0"
Line 10-end: Everytime the for method loops, we are assigning a few variables and pushing them to our contentArray that we created just at the beginning.

1
2
3
4
5
function rollOverState(stateID:Number):void {
	stateName_txt.text = contentArray[stateID].name;
	population_txt.text = contentArray[stateID].popul;
	otherInfo_txt.text = contentArray[stateID].custom;
}

The above function will display the data of the XML file in the textfields that have been created on the stage, it's will display the correct state information by grabbing the array ID which here has been called stateID.

1
2
3
4
function displayInfo(evt:MouseEvent):void {
	evt.target.transform.colorTransform = new ColorTransform(1, 1, 1, 1, 255, 0, 120, 0);
	getID(evt.target.name);
}

The ColorTransform class lets you adjust the color values in a display object. The color adjustment or color transformation can be applied to all four channels: red, green, blue, and alpha transparency.
When a ColorTransform object is applied to a display object, a new value for each color channel is calculated like this:

New red value = (old red value * redMultiplier) + redOffset
New green value = (old green value * greenMultiplier) + greenOffset
New blue value = (old blue value * blueMultiplier) + blueOffset
New alpha value = (old alpha value * alphaMultiplier) + alphaOffset
If any of the color channel values is greater than 255 after the calculation, it is set to 255. If it is less than 0, it is set to 0.

Source: Flash CS3 Help File

Shortly explained the colorTransform method changes our color based on the color of the movieclip, in our example I gave the states a slightly higher red tone. Don't hang me up because it doesn't look nice, I leave the design and colours up to you.

1
2
3
4
5
6
function resetMap(evt:MouseEvent):void {
	evt.target.transform.colorTransform = new ColorTransform(1, 1, 1, 1, 0,0,0, 0);
	stateName_txt.text = "";
	population_txt.text = "";
	otherInfo_txt.text = "";
}

As we assigned 2 functions to display the information and colour the map, we are using one function to remove all the informations & modifications at once. By using no color transformation values (0,0,0) the movieclips resets itself to his original colour, at the same time we replace our text inside the textfields with an empty string.

1
2
3
4
5
6
7
8
9
10
function getID(searchName:String):void {
	trace("SEARCHNAME: "+searchName);
	for (var k:Number = 0; k < contentArray.length; k++) {
		if (contentArray[k].name == searchName) {
			trace("Match at position "+k);
			rollOverState(k);
		}
	}
}
init()

The last function we are going to create is the most importang of all, this function will search the Array for the hovered state's instance name. For your own debugging heart, put some trace actions inside such functions so that you can always see what your script is doing and if the variables are being passed correctly.

Again using a for loop, we crawl through all the array objects available on the search for the state's name using a simple if statement. If the "if" statement matches the hovered state, then the function rollOverState is being called and the textfields will be filled with the XML information.

The last line is so simple that it needs no explanation, but without it nothing is working, start up the init function as soon as the movie is loaded!

Now you probably wondering where I'm using the other functions? Well.. there is the last bit of code that you need to write.

1
2
3
4
5
6
mainMap.California.addEventListener(MouseEvent.MOUSE_OVER, displayInfo);
mainMap.California.addEventListener(MouseEvent.MOUSE_OUT, resetMap);
mainMap.Florida.addEventListener(MouseEvent.MOUSE_OVER, displayInfo);
mainMap.Florida.addEventListener(MouseEvent.MOUSE_OUT, resetMap);
mainMap.Texas.addEventListener(MouseEvent.MOUSE_OVER, displayInfo);
mainMap.Texas.addEventListener(MouseEvent.MOUSE_OUT, resetMap);

I haven't found an easier way to use less lines of code for something this simple, I probably will have to write a class for this although I'm not very sure that if will work either.

Now that you're done test your movie and see if everything is lightning up as you want.

Instead of using the textfields, you can also create a nice panel that moves with the mouse x.y coordinates when hovering a state. One of the features that I'm working on is as well the proper colorization of the states based on the population. Shoudn't be too difficult. As soon as I have that done, I will post an update.

That's it for now, I hope you've learned something from this short tutorial and if you have any questions don't hesitate on dropping me a line or just leaving a comment.

Comments (3) Trackbacks (0)
  1. “I haven’t found an easier way to use less lines of code for something this simple, I probably will have to write a class for this although I’m not very sure that if will work either.”

    You should be able to take advantage of Event Bubbling in AS3.

    http://www.adobe.com/devnet/actionscript/articles/event_handling_as3_03.html

  2. In the download zip file there is one file us_map.ai file. How do we create such file

  3. Rakesh, you need to create your own map or download a vectorized version where you can edit it on your own

Trackbacks are disabled.