# Build an OOP Tag Cloud in ActionScript 3.0

In this tutorial I’ll show you how to build a flexible, animatable tagcloud using an Object Oriented Programming approach. I don’t believe in a right or wrong method, but rather several degrees of efficiency. If you have any constructive criticism on my code feel free to comment.

That said, lets start!

## Step 1: How to Think Cloud

This step is the most important one as it will dictate all the following steps. I start by looking at what I want to achieve and then break it into pieces, here’s my line of thought:

I want to be able to add multiple tag clouds in a page. I want it to be simple and customizable. So what do I need to build this tag cloud?

I need a word array, a color, a font, minimum and maximum size definitions, oh and I need tag cloud elements to store that information, these elements should be textField based. Since I want several clouds the obvious choice is to create an instanceable tagCloud class that in this case will extend a Sprite.

Here’s what my main function should look like:

var tagCloud:TagCloud = new TagCloud(words,font,color,minFontsize,maxFontsize,fullsize)

As you can tell there are plenty of parameters which need to be defined, the following will walk you trough the process. Create the following files:

• MainTagCloud.fla – this file will instantiate the tagcloud
• TagCloud.as – this is the class that will create the tagcloud
• TagCloudElement.as – this is the element that will populate the tagcloud

## Step 2: Building the Mother Class

Open TagCloud.as and write this code

package
{

public class TagCloud extends Sprite
{

public function TagCloud($word_array:Array,$font="Arial",$minFontSize:Number=10,$maxFontSize:Number=30,$elementColor:Number=0xffffff,$fullsize:Number=200):void
{
//here I assign the variables I receive to the class's variables
wordArray = $word_array; font =$font
minFontSize = $minFontSize maxFontSize =$maxFontSize
elementColor = $elementColor fullsize =$fullsize
//after setting the variables I build the cloud
buildTagCloud();
}
}


import these libraries:

	import flash.text.Font;
import TagCloudElement; // I'll get to this one later on
import flash.display.Sprite;
import flash.events.Event;


define these variables:

		public var cloudElements:Array;
private var wordArray:Array;
private var word:String;
private var relevancy:Number;
private var size:int;
private var element:TagCloudElement;
private var minFontSize:Number;
private var maxFontSize:Number;
private var elementColor:Number;
private var font:String;
private var wordLength:int
private var fullsize:Number


You’ll end up with something like this:

package
{
//First import these packages:
import flash.text.Font;
import TagCloudElement; // I'll get to this one later on
import flash.display.Sprite;
import flash.events.Event;

//Create a class that will extend a sprite
public class TagCloud extends Sprite
{
//we need these variables to be abble to create the tagCloud
public var cloudElements:Array;
private var wordArray:Array;
private var word:String;
private var relevancy:Number;
private var size:int;
private var element:TagCloudElement;
private var minFontSize:Number;
private var maxFontSize:Number;
private var elementColor:Number;
private var font:String;
private var wordLength:int
private var fullsize:Number

public function TagCloud($word_array:Array,$font="Arial",$minFontSize:Number=10,$maxFontSize:Number=30,$elementColor:Number=0xffffff,$fullsize:Number=200):void
{
//here I assign the variables I receive to the class's variables
wordArray = $word_array; font =$font
minFontSize = $minFontSize maxFontSize =$maxFontSize
elementColor = $elementColor fullsize =$fullsize
//after setting the variables i build the cloud
buildTagCloud();
}
}
}

## Step 3: Construct Your Main Function

Here’s the main function that will build our cloud.

private function buildTagCloud() {
//create an element array
cloudElements = new Array();
//gets the words lenght so i can iterate trought them and create the elements
wordLength = getSingleWordList(wordArray).length
for (var i=0; i<wordLength; i++) {
//this function returns me an array, its basically a filter, read more about it later on
word = getSingleWordList(wordArray)[i]
//this function uses the wikipedia formula to calculate the element size
size = setElementSize(word, wordArray, minFontSize, maxFontSize);
//creates a new element
element = new TagCloudElement(word, size, font, elementColor);
//stores the new element in the array
cloudElements[i] = element
//sets the transparency based on the size
cloudElements[i].alpha=size/maxFontSize
//just a random way to display the cloud elements
cloudElements[i].x = Math.random() * fullsize
cloudElements[i].y = Math.random() * fullsize
//performs a hit test trought the created objects
cloudHitTest(i)
}
}

## Step 4: Adding a Word Counter

Let’s see how many words we’re dealing with.

private function countWord($word:String,$array:Array):int {
var count:int=0;
for (var i:int=0; i<$array.length; i++) { if ($array[i].toLowerCase()==$word.toLowerCase()) { count+=1; } } return (count); } ## Step 5: Set the Element Size I set the element size by using a formula found on wikipedia: function setElementSize($word:String, $array:Array,$minSize:Number, $maxSize:Number):Number { var$size:Number = $maxSize * countWord($word, $array) /$array.length
$size *=$minSize
return $size } ## Step 6: Creating a Single Word List This calls a filter for the array. private function getSingleWordList($source:Array):Array {
var $array:Array=$source.filter(singleWordFilter);
return $array; }  Now set the filter rules. private function singleWordFilter(element:*, index:int, arr:Array):Boolean { if(arr[index+1]){ if (arr[index].toLowerCase()!=arr[index+1].toLowerCase()) { return true; } else { return false; } }else { return false; } } ## Step 7: How to HitTest We’re going to need to test for overlapping positions.  private function cloudHitTest($i) {
for (var a:int=0; a < $i; a++) { //if HITS if (cloudElements[a].hitTestObject(cloudElements[$i])) {
//Reposition
cloudElements[$i].x = Math.random() * fullsize cloudElements[$i].y = Math.random() * fullsize
addChild(cloudElements[$i]); //and test again cloudHitTest($i)
}
}

}

## Step 8: Setting up an Element Getter

This is just a getter of an element by name, in case I need one over the main timeline.

		public function getElementByName($name:String):TagCloudElement { var$auxCloudElement:TagCloudElement;
for (var i:int=0; i < wordLength; i++) {
if (cloudElements[i].word == $name) {$auxCloudElement =  cloudElements[i]
}
}
return $auxCloudElement } ## Step 9: Inside the Element Class package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.text.Font; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldAutoSize; import flash.text.AntiAliasType; import flash.text.GridFitType; import flash.net.URLRequest; import flash.net.navigateToURL; public class TagCloudElement extends Sprite { public var word:String; public var urlpath:String; private var textCloudFormat:TextFormat; private var textCloud:TextField; public var font:String; public var size:Number; public var color:Number; // Same constructor as TagCloud, the element extends a Sprite // and Builds the Element based on a TextField public function TagCloudElement($word:String, $size:Number = 10,$font:String = "Arial", $elementColor:Number = 0xffffff):void { word =$word
font = $font size =$size
color = \$elementColor

buildElement();
}

private function buildElement() {
//creates the textformat
textCloudFormat = new TextFormat();
// defines the font size and color
textCloudFormat.font = font
textCloudFormat.size = size
textCloudFormat.color = color
// creates a textField
textCloud = new TextField();
// embeds the font
textCloud.embedFonts=true;
//sets the antialias to readable equivalent
//defines its text
textCloud.text=word
//defines its size as automatic
textCloud.autoSize=TextFieldAutoSize.LEFT;
//fit to pixel
textCloud.gridFitType = GridFitType.PIXEL
// unselectable text
textCloud.selectable = false;
// assigns the textformat to the textfield
textCloud.setTextFormat(textCloudFormat)
}

private function rollOverCloudElement(e:MouseEvent){
e.target.textColor = 0x666666;
}
private function rollOutCloudElement(e:MouseEvent){
e.target.textColor = color
}
private function clickCloudElement(e:MouseEvent){
}
}
}

## Step 10: Implementation

Now, all that's left to be done is to implement this class in a real .fla file with all the stuff that you are accustumed to (ie:timeline) :P

You'll need to create a font so you can display the textFields, I embeded an Arial font.

Then in the first frame of your .fla import the TagCloud class, set a stage.align to the top left (so that we can find the stage middle position without much work) and create a new instance of the font we just added to the library:

import TagCloud;

stage.align = StageAlign.TOP_LEFT
var wordArray:Array;
var tagCloud:TagCloud;
var arial:Arial = new Arial();//sets a new instance of Arial (already in the library)

function init() {
//creates an array to populate the cloud
//sorts the array alphabetically so i can filter later on
wordArray.sort();
// creates a new tagCloud instance
tagCloud = new TagCloud(wordArray,arial.fontName,15,20,0x000000);
// center's it to stage
tagCloud.x = stage.stageWidth*0.5-tagCloud.width*0.5
tagCloud.y = stage.stageHeight*0.5-tagCloud.height*0.5
}

init();

## Step 11: Build an RSS Feed Request

Now we need to grab a feed from somewhere so we can cloud it. I chose the CNN news feed. To be able to load an XML you need 4 objects including a urlRequest that will be used as a path to the feed.

var requestFeed:URLRequest = new URLRequest("http://rss.cnn.com/rss/cnn_world.rss");
//an urlLoader so that we can load the request we need to make
// a XML object so we can store the data we recieve from the feed
var xmlFeed:XML;
//and last but not least a title array that i can explode the words from...
var titleWords:Array;



## Step 12: The Initialization Method

Now inside our main function I need to add the complete event handler to the request so that it can be called upon a successful load.

function init() {
//I will need the wordArray to be instantiated so I can store the words inside the feed
wordArray = new Array()

}



## Step 13: The Data Structure

The data structure is stored inside the e.target.data so we create the XML here by doing:

function onFeedComplete(e:Event){
xmlFeed = new XML(e.target.data)
//after viewing the source of the rss feed I noticed the structure was something like channel.item.title so i'm using the titles as my word source.
//I need to make an array to store all the words of a title and then add each on of those words inside the word array
//for this I cycle through them

for(var i:uint=0;i<xmlFeed.channel.item.length();i++){



## Step 14: Building the Word List

Instanciate the titleWords in every iteration so that you have a clean array everytime we have a new title.


titleWords = new Array()
//to make single words I split them on "space"
titleWords = xmlFeed.channel.item[i].title.split(" ")
//after them being split i iterate them to be added to the wordArray
for(var j:uint=0;j<titleWords.length;j++){
//i use lowercase so i don't have any duplicated words
wordArray.push(titleWords[j].toLowerCase());
}

}
//after that being done I sort the word array alphabetically
wordArray.sort();
//and I start the tagCloud
startTagCloud();



## Step 15: Starting the Tag Cloud

Now we have all the elements we need to make this tag cloud.

try{
tagCloud = new TagCloud(wordArray,arial.fontName,20,40,0xFFFFCD,300);
}catch(e:Error){
startTagCloud()
}
//all that is left is to define an X and a Y
tagCloud.x = stage.stageWidth*0.5-tagCloud.width*0.5
tagCloud.y = stage.stageHeight*0.5-tagCloud.height*0.5
//and adding it to the stage
}

//don't forget to initialize the main function :)
init();



## Step 16: The Final Code

Here's the complete code for you to read fully.

import TagCloud;
stage.align = StageAlign.TOP_LEFT

var wordArray:Array;
var tagCloud:TagCloud;
var arial:Arial = new Arial();

var xmlFeed:XML;
var titleWords:Array;

function init() {
wordArray = new Array()
}

function onFeedComplete(e:Event){

xmlFeed = new XML(e.target.data)

for(var i:uint=0;i<xmlFeed.channel.item.length();i++){
titleWords = new Array()
titleWords = xmlFeed.channel.item[i].title.split(" ")
for(var j:uint=0;j<titleWords.length;j++){
wordArray.push(titleWords[j].toLowerCase());
}
}
wordArray.sort();
startTagCloud();
}

function startTagCloud(){
try{
tagCloud = new TagCloud(wordArray,arial.fontName,20,40,0xFFFFCD,300);
}catch(e:Error){
startTagCloud()
}
tagCloud.x = stage.stageWidth*0.5-tagCloud.width*0.5
tagCloud.y = stage.stageHeight*0.5-tagCloud.height*0.5

}

init();


## Conclusion

I could have used linked lists and while loops to make this a bit faster, but you'll find it reasonably quick. One final note: be sure to set the random size big enough or you'll get a stackOverFlow error when the cloudElement can't find a place to be put.

I hope you liked this tutorial, thanks for reading!

• David Nash

Nice

• http://labs.dariux.com Dario Gutierrez

Bruno definitely this is an excellent tut. Nice code.

• http://skillz-commmunity.net Shurandy Thode

Great tut.

• http://www.xitestudiomagazine.com Roberto XSM

Very good. Thanks

• http://www.w2point.com Web 2.0

Great work :)

• André

very nice, very well coded man, thanks a lot for this tutorial

• Jirka

hi, i have problem with open .fla file. I have CS3. Can you save it for my version and send it? Thank you very much

• Bruno Crociquia

Here you go,

http://tiny.cc/upJyp

• http://snaptin.com Ian Yates
Staff

Thanks Bruno,

I grabbed a copy and included it in the existing source.zip. CS3 is therefore now available from the source link at the top of the page.

• Bruno Crociquia

Thanks Ian

• http://www.flashden.net/user/wangruyi wang ruyi

nice tutorial!

• http://www.pixelmaestro.com Pixel Maestro

There is a WordPress TagCloud worth looking at http://www.roytanck.com/tag/wp-cumulus/

Flash source files are in the Development version

• http://www.flashframer.com Flash Framer

OOP always fries my brain but you did a great job. Thanks!

• Pingback: Twitted by seacloud9

• Maria Luiza

Maravilhoso, muito bom

• user

hey,

first of all i appreciate your tutorial.
but i have the problem that the source files only work for

if i edit the main with the new code, or generate it completly new
with your tutoial i get an error “only expected 5 arguments” referring
to your constructor for your tagCloud, but which you want to initalize
witz 6 arguments:
[...]
tagCloud = new TagCloud(wordArray,arial.fontName,20,40,0xFFFFCD,300);
[...]

even if i fix this (reducing it to the 5 arguments it won’t load or work
with the xml file from cnn.rss or any other.

i would appreciate your help, or instead see the complete source file with
the coude from this tutorial and not with the example without the url loader.

greetz.

• Bruno Crociquia

Sorry, for only reading your question now. Use mainTagCloud_cs3.fla version inside, as it has the xml loader instead of the other fla that has a static name array.

remember, you can’t test the swf in your local machine, because we are accessing http we can only work within a network sandbox. meaning if you want to run inside your computer you need to either host a server in your machine, or edit your flash player security settings.

Cheers

• kedicik

i found bag! Because i don’see last word in array

• http://complexcortex.com Aaron

awesome tutorial! I like that you go from scratch in your code, really helps to walk through the process. Thanks!

• http://sara444@wordpress.com sara

hai i am clearning flash current send me some samples of AS2 in flash.That will help me for the future

• nic

Hi, I have problem with the.fla file.
I’m currently using CS3. Can you save it in CS3 format and send it again?
Thanks. It’s a good tutorial.

• olivier

Great tutorial! It save my nerve !

• Alex

Super tutorial. So easy and clear. Saved me plenty of time.Thank u

• http://www.aidanapps.co.uk Aidan Mack

Good tut, i like the hitTest method. But it suffers from an issue I have had before. What if it caunt find a place to add an element and you get a “Stack overflow occurred.”

What I do is count the number of times the for loop occurs. If its tried to add it say… 50 times and fails I “break” the for statement and just let it place the element where ever.

• http://www.asrd.info sergio

Thanks very much, i have been squeezing my brain for two days and many loops/hittests and didnt get a proper way to do it randomly. Your app helped me a lot

• http://www.yellowshark.com David C.

Hi!

First of all, this is a very nice tutorial. Thank you!

Now to my problem:
How can I add a hand cursor on mouseover the titles? My words are from an XML-File.

I think I would have to dynamically create MovieClips with “useHandCursor” and “buttonMode” and assign (and placing them above) them to the Arrays which are holding the words?

Any help would be highly appreciated!

Thanks!

• JohnS

Nice, very comprehensive tutorial. However, I have a question, how difficult would be to make it to rotate, like the WP cumulus plugin or like this Flash tag cloud: http://www.flashxml.net/tag-cloud.html ?