Модуль векторной графики для построения графов.
To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.
Ниже я покажу код одного своего теста, без которого у меня не получилось сдвинутся в одной моей коммерческой проге. Этот тест был написан для того, чтобы еще раз вникнуть в тригонометрические функции - в без них никуда при векторном рисовании. Когда в коммерческой проге нагромоздились горы кода - у меня не получилось с разбегу сообразить, какая из тригонометрических функций мне тут нужна в моей проге - котангенс, арктангенс, тангенс, арккотенгенс. Пришлось выделить нужный фрагмент кода - так получился тест, который вы видите.
Потом я добавил в тестик пульсацию - чтобы придать тесту более симпатичный вид. Хотя вариантов облагородить тест вокруг функции можно придумать миллион. Если бы у меня было свободное время - я бы сделал вокруг функции Koleso вращающееся, подпрыгивающее и деформируемое на кочках колесо. Ну или например вылазящие из орбит глаза в которых вращаются от удивления зрачки. Но, увы... времени нет совершенно - единственное что я успел - сделать для другого топика пример на этих же графических примитивах - Шаблон Flex/Air приложений со вкладками - ViewStack.
НумерикБокс с количеством спиц (сверху клипа) можно менять на ходу - это и есть проверка корректности тригонометрической функции - иначе это было бы простейшее матричное преобразование.
Есть много дорогих пакетов для построения графов. Разбираться с ними мне дольше, чем написать свой пакет. Поэтому я покажу тут свой небольшой фреймворк для построения графов. Я не стал оформлять этот фреймворк в виде библиотеки SWZ, а покажу тут прототип кода, который можно дальше гнуть в любую сторону.
Итак, тест рабочих функций моего фреймворка для работы с графами выглядит так: главный MXML содержит определения двух рабочих коллекций для работы на графах - PLACE и LINK, обьекта Stage2 - в котором производится отрисовка графа, линкует три модуля этого теста - graphics.as, EnterFrame.as, GrafLogic.as и содержит функию запуска отрисовки DrawGraf и функцию перерисовки.
1: <?xml version="1.0" encoding="utf-8"?>
2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
3: xmlns:s="library://ns.adobe.com/flex/spark"
4: xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="900" minHeight="600" creationComplete="application1_creationCompleteHandler(event)" width="900" height="600" enterFrame="application1_enterFrameHandler(event)" backgroundColor="#FDF5E6">
5:
6: <fx:Script>
7: <![CDATA[
8: import flash.display.Graphics;
9: mport flash.text.TextField;
10: import mx.controls.Alert;
11: import mx.core.UIComponent;
12: import mx.events.FlexEvent;
13: import mx.managers.PopUpManager;
14:
15:
16: protected function application1_creationCompleteHandler(event:FlexEvent):void
17: {
18:
19: //produce test data
20: var k:int=0;
21: for (var j:int=1;j<11;j++){
22: for (var i:int=0;i<100;i++){
23: //разместили узлы с состоянием K в координатах X и Y (place nodes)
24: PLACE.addItem(new OnePlace(i*30+j*50+50,i*50+50,k++ ));
25: }
26: }
27:
28: for (var j:int=0;j<10;j++){
29: for (var i:int=1;i<100;i++){
30: //содинили состояния линиями (crete link with nodes)
31: LINK.addItem(new OneLink(i+(j*100),(i+100)+(j*100)));
32: LINK.addItem(new OneLink(i+(j*100),(i-1)+(j*100)));
33: LINK.addItem(new OneLink(i+(j*100),(i+99)+(j*100)));
34: }
35: }
36:
37: button1_clickHandler(null);
38: }
39:
40:
41: protected function button1_clickHandler(event:MouseEvent):void
42: {
43: try{
44: if (Stage2.numChildren==0){
45: //на сцене пока ничего (canvas is clear)
46: GRAF = new UIComponent();
47: Stage2.addChild(GRAF);
48: DrawGraf();
49: }
50: else if (Checkbox1.selected) {
51: //нужна новая перерисовка (need redraw)
52: Stage2.removeAllChildren();
53: GRAF = new UIComponent();
54: PLACE.filterFunction=null;
55: PLACE.refresh();
56: Stage2.addChild(GRAF);
57: DrawGraf();
58: }
59: else {
60: GRAF = Stage2.getChildAt(0) as UIComponent;
61: //не нужна перерисовка (no need redraw)
62: }
63: }
64: catch (e){
65: Alert.show(e.toString());
66: }
67: }
68:
69:
70: protected function DrawGraf():void {
71: //это запуск EnterFrame
72: DrawCircleStartIndex = 0;
73: GRAF.x=0;
74: GRAF.y=0;
75: GRAF.width=5000;
76: GRAF.height=5000;
77: }
78:
79:
80: ]]>
81: </fx:Script>
82:
83:
84: <fx:Script source="graphics.as" />
85: <fx:Script source="EnterFrame.as" />
86: <fx:Script source="GrafLogic.as" />
87:
88: <fx:Declarations>
89: <s:ArrayCollection id="PLACE"/>
90: <s:ArrayCollection id="LINK"/>
91: <mx:UIComponent id="GRAF" />
92: </fx:Declarations>
93:
94: <mx:Canvas id="Stage2" left="10" top="50" bottom="10" right="10" contentBackgroundColor="#F99999" />
95: <s:Button x="76" y="15" label="Refresh" click="button1_clickHandler(event)"/>
96: <s:CheckBox id="Checkbox1" x="24" y="16" label="New" selected="true" visible="false"/>
97:
98: </s:Application>
Файл grafics.as - в приниципе для этого примера я взял отрисовку элументарных графических примитивов из топика - Векторное рисование в полярных координатах и арктангенс.
Собственно логика графа, которая соединяет узлы графа - содержится в модуле logic.as:
1: // моя логика графа - My logic
2: // PLACE - месторасположение узлов ( Node Place)
3: // LINK - связи между узлами графа ( Link nodes)
4:
5: private function GetPlace(State:int):OnePlace {
6: PLACE.filterFunction = function(One:OnePlace):Boolean {
7: return One.state == State;
8: }
9: PLACE.refresh();
10: return (PLACE.length>0 ? PLACE[0]: null);
11: }
12:
13:
14: //соединить состояние From и To линией (draw line on From node to To node)
15: private function DrawLink1 (Sprite:Graphics, FromState:int,ToState:int):void{
16: //найти координаты состояний From и To
17: var From:OnePlace = GetPlace(FromState);
18: var To:OnePlace = GetPlace(ToState);
19: //соединить их линией
20: if (From!==null && To !==null){
21: return DrawLine3(Sprite, From.x , From.y , To.x , To.y);
22: }
23: }
Кроме того, я сделал коллекции, писывающие координаты узлов не в виде анонимных колекций (в стиле JavaScript), а в виде типизированных коллекций (с тиле Бейсика и Явы):
1: public class OnePlace
2: {
3: public var x:Number;
4: public var y:Number;
5: public var state:int;
6:
7: public function OnePlace(X:Number, Y:Number, State:int) {
8: x=X;
9: y=Y;
10: state=State;
11: }
12: }
13:
14: public class OneLink
15: {
16: public var fromState:int;
17: public var toState:int;
18:
19: public function OneLink(FromState:int,ToState:int)
20: {
21: fromState=FromState;
22: toState=ToState;
23: }
24: }
И, наконец, главный компонент фрейморка - рендер, который отрисовывает по частям граф в событии EnterFrame:
1: //требование отрисовки этого количества объектов
2: //
3: private var DrawCircleStartIndex:int = -1;
4: private var DrawTextStartIndex:int = -1;
5: private var DrawLinkStartIndex:int = -1;
6: //
7: //шаг отрисовки в одном EnterFrame
8: //
9: private var DrawCircleStep:int = 10;
10: private var DrawLinkStep:int = 5;
11: //
12: protected function application1_enterFrameHandler(event:Event):void
13: {
14:
15: //отрисовали узлы состояний (draw nodes)
16: if (DrawCircleStartIndex >= 0)
17: {
18: for (var i:int=DrawCircleStartIndex; i<PLACE.length; i++){
19:
20: DrawCircle1(GRAF.graphics, PLACE[i].x, PLACE[i].y);
21:
22: if (i-DrawCircleStartIndex >= DrawCircleStep+DrawCircleStartIndex-1){
23: if (i==PLACE.length-1){
24: DrawCircleStartIndex=-1;
25: }
26: else {
27: DrawCircleStartIndex=i;
28: return;
29: }
30: }
31: }
32:
33: DrawCircleStartIndex=-1;
34: DrawTextStartIndex = 0;
35:
36: }
37:
38: //отрисовали номера состояний (draw nodes number)
39: if (DrawTextStartIndex >= 0)
40: {
41: for (var i:int=0;i<PLACE.length;i++){
42: if ((i % 100) == 0 || i>900){
43: var Text1:TextField= DrawText(PLACE[i].x - Circle_Radius,PLACE[i].y - Circle_Radius - Text_size - 5 , PLACE[i].state);
44: if (Text1 !== null){
45: GRAF.addChild(Text1);
46: }
47: }
48: }
49: DrawTextStartIndex=-1;
50: DrawLinkStartIndex =0;
51: }
52:
53:
54: //отрисовали связи (draw link with nodes)
55: if (DrawLinkStartIndex >= 0)
56: {
57: for (var i:int=DrawLinkStartIndex; i<LINK.length; i++){
58:
59: DrawLink1(GRAF.graphics, (LINK[i] as OneLink).fromState,(LINK[i] as OneLink).toState);
60:
61: if (i-DrawLinkStartIndex >= DrawLinkStep+DrawLinkStartIndex-1){
62: if (i==LINK.length-1){
63: DrawLinkStartIndex=-1;
64: }
65: else {
66: DrawLinkStartIndex=i;
67: return;
68: }
69: }
70: }
71: DrawLinkStartIndex=-1;
72: }
73: }
Если вас интересует FLASH, AIR и FLEX - то вы можете посмотреть и другие мои заметки, которые собрались у меня на сайте в прошлом году:
- 2012 год: Векторное рисование в полярных координатах и арктангенс.
- 2012 год: Шаблон Flex/Air приложений со вкладками - ViewStack.
- 2011 год: Simple Freeware OpenSource Flex Player for Web (one sound).
- 2011 год: Парсинг AJAX-сайтов в среде AIR (путем выполнения jQuery-запросов из ActionScript).
- 2011 год: Флекс диаграммы.
- 2011 год: Видео-камеры, видео-чаты и Flash-медиасервера (работающие по RTMP и самописным протоколам).
- 2011 год: Сокеты во Flash.
- 2011 год: Freeware OpenSource панорамный фотослайдер.
- 2011 год: AIR приложения для платформ Android, Macintosh и Linux.
- 2011 год: Реклама в видеоплеере (возможности объектного программирования ActionScript).
- 2011 год: Трехмерное вдохновение PaperVision3D.
- 2011 год: TextBannerRotator - простой ротатор текстовых баннеров с эффектом BLUR.
- 2011 год: OpenSource Freeware FotoSlider on Flex 3 and jQuery.
- 2011 год: Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX.
- 2011 год: Как с помощью jQuery сделать флеш-ролик резиновым.
- 2011 год: Мой первый фото-слайдер на Flex 4.
|