В этом уроке я покажу вам, как создать гибкое, анимируемое облако тегов, используя подход объектно-ориентированного программирования. Я не верю в правильный или неправильный метод, а скорее в несколько степеней эффективности. Если у вас есть конструктивная критика моего кода, не стесняйтесь комментировать.
Тем не менее, давайте начнем!
Шаг 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 не может найти место для размещения.
Надеюсь, вам понравился этот урок, спасибо за чтение!

