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