В этом уроке я покажу вам, как создать гибкое, анимируемое облако тегов, используя подход объектно-ориентированного программирования. Я не верю в правильный или неправильный метод, а скорее в несколько степеней эффективности. Если у вас есть конструктивная критика моего кода, не стесняйтесь комментировать.
Тем не менее, давайте начнем!
Шаг 1: Как думать об облаке
Этот шаг является наиболее важным, поскольку он будет диктовать все последующие шаги. Я начинаю с того, что смотрю на то, чего хочу достичь, а затем разбиваю его на кусочки.
Я хочу иметь возможность добавить несколько облаков тегов на странице. Я хочу, чтобы это было просто и настраиваемо . Так что мне нужно для создания этого облака тегов?
Мне нужен массив слов, цвет, шрифт, определения минимального и максимального размера, и мне нужны элементы облака тегов для хранения этой информации, эти элементы должны быть основаны на textField. Поскольку я хочу несколько облаков, очевидным выбором является создание экземпляра класса tagCloud, который в этом случае расширит Sprite.
Вот как должна выглядеть моя основная функция:
| 1 | var tagCloud:TagCloud = new TagCloud(words,font,color,minFontsize,maxFontsize,fullsize) | 
Как вы можете сказать, существует множество параметров, которые необходимо определить, следующее поможет вам в этом процессе. Создайте следующие файлы:
- MainTagCloud.fla — этот файл будет создавать теги
- TagCloud.as — это класс, который будет создавать tagcloud
- TagCloudElement.as — это элемент, который будет заполнять tagcloud

Шаг 2: Создание Матери класса
Откройте TagCloud.as и напишите этот код
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | 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();         } } | 
импортировать эти библиотеки:
| 1 2 3 4 | import flash.text.Font; import TagCloudElement; import flash.display.Sprite; import flash.events.Event; | 
определить эти переменные:
| 1 | public var cloudElements:Array; | 
Вы получите что-то вроде этого:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package {     //First import these packages:     import flash.text.Font;     import TagCloudElement;     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();         }     } } | 
Шаг 3: Создайте свою основную функцию
Вот основная функция, которая будет строить наше облако.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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)            }        } | 
Шаг 4: Добавление счетчика слов
Посмотрим, с какими словами мы имеем дело.
| 1 2 3 4 5 6 7 8 9 | 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);        } | 
Шаг 5: Установите размер элемента
Я устанавливаю размер элемента, используя формулу, найденную в Википедии:
| 1 2 3 4 5 | function setElementSize($word:String, $array:Array, $minSize:Number, $maxSize:Number):Number {            var $size:Number = $maxSize * countWord($word, $array) / $array.length            $size *= $minSize            return $size        } | 
Шаг 6: Создание списка из одного слова
Это вызывает фильтр для массива.
| 1 2 3 4 | private function getSingleWordList($source:Array):Array {            var $array:Array=$source.filter(singleWordFilter);            return $array;        } | 
Теперь установите правила фильтра.
| 01 02 03 04 05 06 07 08 09 10 11 | 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;             }         } | 
Шаг 7: Как пройти тестирование
Нам нужно будет проверить перекрывающиеся позиции.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | 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)         }     }     } | 
Шаг 8: Настройка элемента получения
Это просто получатель элемента по имени, на случай, если он мне нужен на основной временной шкале.
| 1 2 3 4 5 6 7 8 9 | 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 } | 
Шаг 9: Внутри класса элемента
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 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»);         }     } } | 
Шаг 10: Реализация
Теперь все, что осталось сделать, — это реализовать этот класс в реальном файле .fla со всеми вещами, к которым вы привыкли (т.е. с временной шкалой): P
Вам нужно будет создать шрифт, чтобы вы могли отображать textFields, я встроил шрифт Arial.

Затем в первом кадре вашего .fla импортируйте класс TagCloud, установите stage.align в верхнем левом углу (чтобы мы могли найти среднее положение рабочей области без особых усилий) и создайте новый экземпляр шрифта, который мы только что добавили в библиотека:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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,0×000000);     // 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(); | 
Шаг 11: Создайте запрос на подачу RSS
Теперь нам нужно взять канал откуда-то, чтобы мы могли его скрыть. Я выбрал канал новостей CNN. Чтобы иметь возможность загружать XML, вам нужно 4 объекта, включая urlRequest, который будет использоваться в качестве пути к каналу.
| 1 2 3 4 5 6 7 | 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; | 
Шаг 12: Метод инициализации
Теперь внутри нашей основной функции мне нужно добавить полный обработчик событий в запрос, чтобы он мог быть вызван при успешной загрузке.
| 1 2 3 4 5 6 7 8 | 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);     } | 
Шаг 13: Структура данных
Структура данных хранится внутри e.target.data, поэтому мы создаем XML здесь, выполнив:
| 1 2 3 4 5 6 7 | 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++){ | 
Шаг 14: Создание списка слов
Создавайте titleWords в каждой итерации, чтобы у вас был чистый массив каждый раз, когда у нас появляется новый заголовок.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 |         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(); | 
Шаг 15: Запуск облака тегов
Теперь у нас есть все элементы, необходимые для создания этого облака тегов.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 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(); | 
Шаг 16: Окончательный код
Вот полный код, который вы можете прочитать полностью.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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(); | 
Вывод
Я мог бы использовать связанные списки и циклы while, чтобы сделать это немного быстрее, но вы найдете это достаточно быстро. Последнее замечание: не забудьте установить достаточно большой случайный размер, иначе вы получите ошибку stackOverFlow, когда cloudElement не может найти место для размещения.
Надеюсь, вам понравился этот урок, спасибо за чтение!

