Флекс диаграммы.
Так сложилось, что мне нечасто приходится выводить диаграммы в своих проектах. А что делаешь нечасто - забывается слишком легко. Хотя диаграммы я люблю и пользуюсь ими всегда. Например мой топик Фальсификация выборов в Москве (база данных для статистических исследований) построен именно на диаграмме. Именно наглядность данных статистического анализа, поданная с помощью c помощью диаграммы - позволяет в явном виде продемонстрировать факт совершения вопиющего преступления - фальсификации волеизъявления народов Российской Федерации. А ровно те же самые данные, упрятанные конторой Чурова на его сайте в тысячи отдельных таблиц и табличек (каждая из которой открывается на своей страничке) - не показывают вообще ничего. Это просто тысячи и тысячи таблиц с цифирьками. Кто и что пытался намутить в этих цифирках - совершенно непонятно. Группенфюрер Чуров нам объвляет только итог своих табличек - мы, мол, тут все посчитали, проверили и у нас тут получается что Верховный Чекистский ЛысоГном будет вашим хозяином пожизненно. И только на диаграмме (в которой можно окинуть одним взглядом все расчеты конторы Чурова) сразу видно - 140 миллионов человек, полностью игнорируя Конституцию Российской Федерации и руководствуясь корыстными умыслами, цинично и нагло дурачит чисто конкретная бангдруппировка, известная как "Питерские Чекисты".
Так же полезны и наглядны диаграммы и для прочих случаев статистического анализа. Например в моем топике WebDownloader_UltraLite - ваш личный поисковик по рунету с особыми возможностями поиска я наглядно показал именно с помощью диаграмм тот сектор рынка в 0,4%, которые сумела завоевать бригада Билла Гейтса со своими чудо-технологиями - в интернете. В идеально конкурентной среде, в среде где не срабатывают взятки, в среде где надо доказывать на деле, что твои технологии лучше. И эти статистические данные наводят на удивительные вопросы - как такая мизерная доля рынка могла привести к такому крупному гнойному нарыву, как Билл Гейтс (самый богатый человек планеты). И по здравому размышлению понимаешь - все дело во взятках, ибо ничьи другие технологии (даже существенно лучшие) не изучают в школе в обязательном порядке.
Flex не только превосходный инструмент рисования векторной графики - но, что особенно приятно, флекс позволяет позволяет обрабатывать и выводить на диаграммы большие обьемы либо локальных данных - Открой для себя SQLite, либо данных, хранимых на сервере - Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX. Сочетание всех этих условий - превосходная, быстрая и хорошо управляемая графика, наличие мощных готовых контролов, возможность обрабатывать большие обьемы данных даже непосредственно в браузере - и делают Флекс настоящей технологической бомбой для вывода диаграмм.
Сами по себе контролы флекса для отображения диаграмм - это OpenSource фреймворк от компании Adobe, надстроенный над рисованием простых форм - прямоугольников, секторов, окружностей. Фреймворк это нехилого размера и работает он медленно. Для многих применений контролы (например онлайновое отображение звуков) просто не тянут по скорости. Звук зависает на одной ноте по несколько секунд - пока выстроится даже простейшая столбчатая диаграмка из тысячи столбцов. Бейсик, конечно, работает миниммум в сто раз быстрее - хотя принцип построения диаграмм там точно такой же. Но увы, бейсик работает только на серверах (выкидыш Silverlight'а не в счет), а jQuery на клиентах - работает еще наверное в сто раз медленне откомпилированного байт-кода Flex. Поэтому в реальности - при возникновении необходимости отрисовать диаграмму - выбор есть либо в выводе диаграмм контролами флексового фреймворка - либо можно самому более быстрым кодом отрисовывать какие-то прямоугольнички и волны. Разумеется в самых убогих десктопных Win-приложениях есть и другие варианты - только они трудно переносимы на более современные OpenSource платформы и эти решения обречены на пожизненное гниение в устаревшей операционной системе, принадлежащей Биллу Гейтсу.
Моя любимая диаграмма (еще до появления Эксела и шестого бейсика) - столбчатая. И она довольно крученая. Каждый столбец может отображать даже не одну серию данных, а несолько, а столбцев в пакете может быть много. Как я говорил, поскольку диаграмма - нечасто применяемый компонент (даже в бейсике) - когда раз в полгода приходится построить сложную диаграмму - приходится все вспоминать практически заново.
Aдобовская документация показывает примеры диаграмм лишь в простейших случаях (даже источник данных у них в документации всегда декларативный). Столь простых применений в дикой природе не встречается. Поэтому я и решил тут выложить базовый шаблон проекта диаграммы, который чуть-чуть интереснее адобовской документации. В этом примере кода я ограничился лишь тремя диаграммами, а в принципе в Адобовском фреймворке есть восемь стандартных типов диаграмм (AreaCharts, BarCharts, BubbleCharts, CandlestickCharts, ColumnCharts, HighLowOpenCloseCharts, LineCharts, PieCharts, PlotCharts). У каждого типа диаграмм есть множество режимов. Но в этом кода я сконцентрировался на уходе от декларативного синтаксиса и обошел управление стилями диаграмм, такими как цвет линий, толщина, прозрачность и прочее. Кроме того, все элементы диаграмм могут быть кликабельными и анимированными. К элементам диаграмм можно применять всевозможнейшие фильтры. Легенду диаграмм я тоже здесь для простоты опустил.
Итак, ниже вы видите живую работающую Flex-диаграмму и ее OpenSource:
To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.
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="955" minHeight="600"
5: creationComplete="init();" height="656" width="643" backgroundColor="#FDF5E6">
6:
7: <fx:Script>
8: <![CDATA[
9: import mx.collections.ArrayCollection;
10: import mx.events.FlexEvent;
11:
12: import spark.events.IndexChangeEvent;
13:
14: [Bindable]
15: private var ChartDataProvider1:ArrayCollection=new ArrayCollection();
16:
17: protected function init():void{
18: //инициализация провайдера данных: первая строка - это ось X, вторая и последующие строки - это данные
19: for(var i:int = 0; i < 10 ; i++){
20: var One:Object={};
21: One.x=i;
22: One.y1=i;
23: One.y2=i*i;
24: One.y3=i*i*i;
25: One.y4=-i;
26: ChartDataProvider1.addItem(One);
27: }
28: ComboBox1.selectedIndex=1;
29: ComboBox2.selectedIndex=1;
30: ComboBox3.selectedIndex=0;
31: ComboBox4.selectedIndex=1;
32: DynamicCreate();
33: }
34:
35: private function DynamicCreate():void{
36:
37: //**************************************************
38: //сначала определяется горизонтальная ось - имя строки данных абциссой
39: //**************************************************
40: var xAxis:CategoryAxis = new CategoryAxis();
41: xAxis.categoryField = "x";
42: ColumnChart2.horizontalAxis = xAxis;
43:
44: //**************************************************
45: //создаем первую серию столбцов с данными (в одном столбце будет показано два набора данных)
46: //**************************************************
47:
48: //SeriesArray1 - определяет одну последовательность данных для столбца
49: var SeriesArray1:Array = new Array();
50:
51: //определение ИМЕНИ поля данных для первой отображаемой последовательности в столбце
52: var OneColumnSeries1:ColumnSeries = new ColumnSeries();
53: OneColumnSeries1.yField="y1"
54: OneColumnSeries1.displayName = "y1";
55: SeriesArray1.push(OneColumnSeries1);
56:
57: //определение имени во второй последовательности данных в том е столбце
58: var OneColumnSeries2:ColumnSeries = new ColumnSeries();
59: OneColumnSeries2.yField="y2"
60: OneColumnSeries2.displayName = "y2";
61: SeriesArray1.push(OneColumnSeries2);
62:
63: //ColumnSeriesSet1 - массив с последовательностями отображаемых данных в одном столбце
64: var ColumnSeriesSet1:ColumnSet = new ColumnSet();
65: //тип коминации двух наборов данных в одном столбце берется из комбобокса
66: ColumnSeriesSet1.type=CurrentType2;
67: ColumnSeriesSet1.series = SeriesArray1;
68:
69: //**************************************************
70: //теперь создадим вторую серию параллельных столбцов
71: //**************************************************
72:
73: //SeriesArray2 - определяет вторую последовательность данных (параллелных столбцов)
74: var SeriesArray2:Array = new Array();
75:
76: //определение имени данных в этой второй последовательности
77: var OneColumnSeries3:ColumnSeries = new ColumnSeries();
78: OneColumnSeries3.yField="y4"
79: OneColumnSeries3.displayName = "y4";
80: SeriesArray2.push(OneColumnSeries3);
81:
82: //ColumnSeriesSet1 - массив с последовательностями отображаемых данных во втором параллельном столбце
83: var ColumnSeriesSet2:ColumnSet = new ColumnSet();
84: //тип коминации двух наборов данных в одном столбце берется из комбобокса
85: ColumnSeriesSet2.series = SeriesArray2;
86:
87: //*******************************************
88: //и все загружаем в диаграмму для отображения
89: //*******************************************
90: ColumnChart2.series=[ColumnSeriesSet1, ColumnSeriesSet2 ];
91: }
92:
93: [Bindable]
94: private var Type1:ArrayCollection=new ArrayCollection([
95: {label:"overlaid", data:1},
96: {label:"stacked", data:2},
97: {label:"100%", data:3}
98: ]);
99:
100: [Bindable]
101: private var CurrentType1:String="stacked";
102:
103: protected function combobox1_changeHandler(event:IndexChangeEvent):void
104: {
105: CurrentType1=ComboBox1.selectedItem.label;
106: }
107:
108: [Bindable]
109: private var CurrentType2:String="stacked";
110:
111: protected function combobox2_changeHandler(event:IndexChangeEvent):void
112: {
113: CurrentType2=ComboBox2.selectedItem.label;
114: DynamicCreate();
115: }
116:
117: [Bindable]
118: private var Type3:ArrayCollection=new ArrayCollection([
119: {label:"segment", data:1},
120: {label:"step", data:2},
121: {label:"vertical", data:3},
122: {label:"horizontal", data:4},
123: {label:"reverseStep", data:5},
124: {label:"curve", data:6}
125: ]);
126:
127: protected function combobox3_changeHandler(event:IndexChangeEvent):void
128: {
129: LineChart3.series[2].setStyle("form", ComboBox3.selectedItem.label);
130: }
131:
132: private var Type4:ArrayCollection=new ArrayCollection([
133: {label:"many series", data:1},
134: {label:"explode", data:2},
135: {label:"inner", data:3},
136: ]);
137:
138:
139: protected function combobox4_changeHandler(event:IndexChangeEvent):void
140: {
141: if (ComboBox4.selectedItem.data==1){
142:
143: //SeriesArray1 - определяет одну последовательность данных для столбца
144: var SeriesArray1:Array = new Array();
145:
146: //определение ИМЕНИ поля данных для первой отображаемой последовательности в столбце
147: var OneColumnSeries1:PieSeries = new PieSeries();
148: OneColumnSeries1.field="y1"
149: OneColumnSeries1.displayName = "y1";
150: SeriesArray1.push(OneColumnSeries1);
151:
152: //определение имени во второй последовательности данных в том е столбце
153: var OneColumnSeries2:PieSeries = new PieSeries();
154: OneColumnSeries2.field="y2"
155: OneColumnSeries2.displayName = "y2";
156: SeriesArray1.push(OneColumnSeries2);
157:
158:
159: PieChart1.series=SeriesArray1;
160: PieChart1.setStyle("innerRadius",0);
161:
162: }
163: else if (ComboBox4.selectedItem.data==2)
164: {
165: //SeriesArray1 - определяет одну последовательность данных для столбца
166: var SeriesArray2:Array = new Array();
167:
168: //определение ИМЕНИ поля данных для первой отображаемой последовательности в столбце
169: var OneColumnSeries2:PieSeries = new PieSeries();
170: OneColumnSeries2.field="y1"
171: OneColumnSeries2.displayName = "y1";
172: OneColumnSeries2.explodeRadius=0.2;
173: SeriesArray2.push(OneColumnSeries2);
174:
175: PieChart1.series=SeriesArray2;
176: PieChart1.setStyle("innerRadius",0);
177:
178:
179: }
180: else if (ComboBox4.selectedItem.data==3)
181: {
182: //SeriesArray1 - определяет одну последовательность данных для столбца
183: var SeriesArray3:Array = new Array();
184:
185: //определение ИМЕНИ поля данных для первой отображаемой последовательности в столбце
186: var OneColumnSeries3:PieSeries = new PieSeries();
187: OneColumnSeries3.field="y1"
188: OneColumnSeries3.displayName = "y1";
189: OneColumnSeries3.explodeRadius=0;
190: SeriesArray3.push(OneColumnSeries3);
191:
192: PieChart1.series=SeriesArray3;
193: PieChart1.setStyle("innerRadius",0.2);
194:
195: }
196: }
197:
198: ]]>
199: </fx:Script>
200:
201:
202: <fx:Declarations>
203: <!-- Place non-visual elements (e.g., services, value objects) here -->
204: </fx:Declarations>
205:
206: <s:TileGroup horizontalGap="12" verticalGap="12" width="624" x="10" height="282" y="10">
207: <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true" contentBackgroundColor="#FFFFFF" backgroundColor="#FFFFFF">
208: <mx:FormItem>
209: <mx:FormHeading label="ColumnChart (one column)"/>
210: <mx:FormItem>
211: <s:ComboBox id="ComboBox1" change="combobox1_changeHandler(event)" dataProvider="{Type1}" />
212: </mx:FormItem>
213: <mx:ColumnChart width="250" height="200" showDataTips="true" dataProvider="{ChartDataProvider1}">
214: <mx:horizontalAxis>
215: <mx:CategoryAxis categoryField="x"/>
216: </mx:horizontalAxis>
217: <mx:series>
218: <mx:ColumnSet type="{CurrentType1}">
219: <mx:ColumnSeries yField="y1" displayName="y1"/>
220: <mx:ColumnSeries yField="y2" displayName="y2"/>
221: <mx:ColumnSeries yField="y3" displayName="y3"/>
222: </mx:ColumnSet>
223: </mx:series>
224: </mx:ColumnChart>
225: </mx:FormItem>
226: </mx:Form>
227: <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true" contentBackgroundColor="#FFFFFF" backgroundColor="#FFFFFF">
228: <mx:FormHeading label="ColumnChart - First Column Type"/>
229: <mx:FormItem>
230: <s:ComboBox id="ComboBox2" change="combobox2_changeHandler(event)" dataProvider="{Type1}" />
231: </mx:FormItem>
232: <mx:FormItem>
233: <mx:ColumnChart id="ColumnChart2" width="250" height="200" showDataTips="true" dataProvider="{ChartDataProvider1}">
234: </mx:ColumnChart>
235: </mx:FormItem>
236: </mx:Form>
237: <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true" contentBackgroundColor="#FFFFFF" backgroundColor="#FFFFFF">
238: <mx:FormItem>
239: <mx:FormHeading label="LineChart (first line type)"/>
240: <mx:FormItem>
241: <s:ComboBox id="ComboBox3" change="combobox3_changeHandler(event)" dataProvider="{Type3}" />
242: </mx:FormItem>
243: <mx:LineChart id="LineChart3" width="250" height="200" showDataTips="true" dataProvider="{ChartDataProvider1}">
244: <mx:horizontalAxis>
245: <mx:CategoryAxis categoryField="x"/>
246: </mx:horizontalAxis>
247: <mx:series>
248: <mx:LineSeries yField="y1" displayName="y1"/>
249: <mx:LineSeries yField="y2" displayName="y2"/>
250: <mx:LineSeries yField="y3" displayName="y3"/>
251: </mx:series>
252: </mx:LineChart >
253: </mx:FormItem>
254: </mx:Form>
255: <mx:Form width="300" dropShadowVisible="true" borderStyle="solid" borderVisible="true" contentBackgroundColor="#FFFFFF" backgroundColor="#FFFFFF">
256: <mx:FormItem>
257: <mx:FormHeading label="PieChart"/>
258: <mx:FormItem>
259: <s:ComboBox id="ComboBox4" change="combobox4_changeHandler(event)" dataProvider="{Type4}" />
260: </mx:FormItem>
261: <mx:PieChart width="250" height="200" showDataTips="true" id="PieChart1" dataProvider="{ChartDataProvider1}" >
262: <mx:series>
263: <mx:PieSeries field="y1" displayName="y1" explodeRadius="0.2" />
264: </mx:series>
265: </mx:PieChart>
266: </mx:FormItem>
267: </mx:Form>
268: </s:TileGroup>
269:
270: </s:Application>
|