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 addChild(cloudElements[i]); //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 textCloud.antiAliasType=AntiAliasType.ADVANCED; //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) // adds the MouseEvents listeners textCloud.addEventListener(MouseEvent.ROLL_OVER,rollOverCloudElement) textCloud.addEventListener(MouseEvent.ROLL_OUT,rollOutCloudElement) textCloud.addEventListener(MouseEvent.CLICK,clickCloudElement) addChild(textCloud); } private function rollOverCloudElement(e:MouseEvent){ e.target.textColor = 0x666666; } private function rollOutCloudElement(e:MouseEvent){ e.target.textColor = color } // I've made a link to a twitter search using the word selected. private function clickCloudElement(e:MouseEvent){ navigateToURL(new URLRequest("http://search.twitter.com/search?q="+e.target.text),"_blank"); } } }
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 wordArray = new Array("In","this","fashion,","text","clouds","may","become","a","generally","applied","tool","for","managing","growing","information","overload","by","using","automated","synthesis","and","summarization","In","the","information","saturated","future","or","the","information","saturated","present"); //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 //adds to stage addChild(tagCloud); } 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 var loaderFeed:URLLoader = new URLLoader() // 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() { loaderFeed.addEventListener(Event.COMPLETE,onFeedComplete) //I will need the wordArray to be instantiated so I can store the words inside the feed wordArray = new Array() //we are ready to load the XML now loaderFeed.load(requestFeed); }
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 addChild(tagCloud); //tadaaa we are done.. } //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 requestFeed:URLRequest = new URLRequest("http://rss.cnn.com/rss/cnn_world.rss"); var loaderFeed:URLLoader = new URLLoader() var xmlFeed:XML; var titleWords:Array; function init() { loaderFeed.addEventListener(Event.COMPLETE,onFeedComplete) wordArray = new Array() loaderFeed.load(requestFeed); } 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 addChild(tagCloud); } 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!
Envato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post