Графики, диаграммы, графы … и все это в веб? Часть 2

October 22, 2007

Сегодня мы продолжим и завершим рассмотрение вопроса о разработке внедренных в сайт графиков, диаграмм. В прошлый раз я рассказывал об общих методиках, о плюсах и минусах основных подходов: генерация статического изображения, использование flash, работе с canvas и svg. Рассказал о трех библиотеках для php которые генерируют статические картинки, умолчал о паре не менее интересных библиотек. Сегодня я расскажу о средствах, которые есть в мире flash/flex.

Почти все библиотеки и программные продукты, о которых я пишу, принадлежат миру open source. Исключение я делаю лишь в тех случаях, когда аналогов нет или они заведомо хуже доступных “свободных” реализаций. Если набрать в строке поиска google запрос charting flash, то можно найти множество платных и бесплатных продуктов, качественных и не очень - на любой вкус. Большей частью предоставляемая ими функциональность сходна - диаграммы различных видов строятся flash-роликом на основании данных, загружаемых с сайта с помощью xml. Сам же код ролика (fla, as-файлы) обычно недоступен вообще или представлен только в старших версиях продукта за отдельные деньги.

Сегодня я расскажу о нескольких интересных коммерческих и не коммерческих продуктах. Первый из них - Swiff chart (сайт продукта globfx.com). Это не просто swf-файл, который можно внедрить на страницу и остается только привязать источник данных - это целая автономная (работающая вне среды flash/flex) программа с достаточно простым, удобным (и немного подтормаживающим - у меня, по крайней мере) интерфейсом. Вам нужно указать тип графика (доступны столбчатая гистограмма, линия, круговая диаграмма, Scatter, кольцевая, пузырьковая). Затем указать источник данных (импорт данных из excel, csv-файла, возможно указать данные непосредственно внутри самой программы на специальной форме выглядящей подобно листу excel). Третий шаг - это указать стили оформления. Предусмотрен набор типовых стилей, цветовых решений, но вы можете выполнить тонкую настройку каждого из параметров: оси, маркеры, легенда, цвет фона, линий, столбиков, шрифты для надписей - почти всего, что вы видите на диаграмме. Предусмотрен и специальный мастер анимации, который позволят задать стиль визуализации элементов диаграммы - привычные многим по powerpoint-презентациям эффекты выезжания, медленного проявления изображения, анимация движения столбиков, линий. На рабочей области диаграммы можно рисовать геометрические фигуры, надписи, сноски - набор фигур конечно не столь богат как в word или powerpoint - но заслуживает уважения. Поверх диаграммы можно разместить линии тренда на основании различных законов: линейного, полиномиального различных степеней, экспоненциального и других. И, наконец, создав диаграмму вы можете ее экспортировать в один из следующих форматов: flash, обычная статическая картинка, презентация powerpoint, svg-картинка и файл в формате pdf. Очень важно, что диаграмма и ее данные - единое целое, если ваши данные меняются достаточно редко, то вы можете обойтись одним лишь Swiff chart, чтобы создать автономный swf-файл и в последующем внедрить его в вашу страницу - все плюсы с сохранением страницы на жесткий диск, печатью достигаются автоматически. Пример окна swiff chart показан на рис. 1.



Если же графики строятся на основании интенсивно меняющихся в режиме реального времени данных, то вам поможет другой продукт этой же компании - Swiff chart generator - это решение включает с себя скрипт на одном из языков серверных расширений: php, asp, jsp. Знания какого-либо из этих языков вам необходимы т.к. скрипт выполняет подключение к источнику данных, затем создает объект SwiffChart, множество методов которого служат для наполнения диаграммы данными и настройки ее внешнего вида, затем скрипт выполняет генерацию двоичного файла swf с внедренными в него данными. Этот момент важен, т.к. генерация двоичного файла дает все те самые плюсы с сохранением страницы, но, увы, то что генерирует двоичный файл swf - не может быть php, java-скриптом - это отдельный исполнимый (exe) файл. Начитавшись в справке, что общение с этим файлов идет через технологию com, я уже было думал сделать uninstall и забыть об этом продукте. Все дело в том, что хоть php и jsp (не говоря о asp) отлично умеют работать с com, но выбор хостинга был бы ограничен только windows-хостингом. К счастью в ходе дальнейшего изучения справки оказалось, что существует и linux-версия данного скрипта, в основе своей обмен данными между вашим скриптом и Swiff chart generator идет через pipes. Если вы не знаете что такое pipes, то эта “штука”, которая есть везде и всегда, за исключением бесплатных хостингов, где php-работает в безопасном режиме и множество функций отключено. Хотя в итоге для моего проекта swiff chart и не был выбран, но причина была не в технических сложностях или багах (таковые не были обнаружены), а скорее организационная. Тем не менее, пара продуктов swiff chart (generator) произвела крайне положительное впечатление.

Второй продукт - fusioncharts (сайт проекта http://www.fusioncharts.com). Схема работы fusion chart отлична от swiff chart тем, что нет специального desktop приложения, которое генерирует конечный swf-ролик внедряемый в страницу. В fusion chart в страницу вставляется код swf-файла библиотеки (для каждого вида графики существует своя версия swf-файла, размер колеблется от 40-60 кб.), затем swf-ролик подзагружает данные в xml-формате. Формат достаточно прост, но если вы не принадлежите к касте “настоящих программистов”, то можете воспользоваться написанным на flash мастере-генераторе xml (идет в поставке с fusioncharts). Схема его работы подобна swiff, вы указываете тип диаграммы, способ заполнения его информацией (ручной ввод в некое подобие листа excel, копирование из txt, csv, excel-файлов) - вуаля, и на выходе получаем исходный текст xml документа как показано на рис. 2.



Для окончательного “тюнинга” внешнего вида вам все равно придется подправить получающийся файлик руками. Что меня не порадовало: примеры кода на разных языках (к слову, небольшие библиотечки, упрощающие вставку ролика на страницу доступны для php, jsp, ruby on rails, asp, coldfusion, asp.net) построены на сходной основе. Так мы формируем xml файл встроенными в состав конкретного языка программирования средствами, а затем печатаем вызов функции render из javascript-библиотеки, в свою очередь эта функция (построенная в стиле старой доброй swfobject) проверяет наличие flash на машине клиента и отображает swf-файл, в качестве параметра которому передается тот самый xml-файл с данными. Схема не сложна, но разработчики могли бы добавить к библиотеке специализированный api, представляющий высокоуровневую обертку над xml, это дало бы шанс избежать ряда ошибок-опечаток при ручном формировании xml. Приятный плюс, в том, что xml-данные могут не только подзагружаться внутрь swf-ролика с сервера, но и содержаться внутри html-кода, в качестве одного из параметров param тега object/embed (это дает нам корректное сохранение страницы на жесткий диск). В примере далее показано такое внедрение данных. Способ организации набора данных – это множество тегов каждый из которых задает некоторое значение серии данных, вложенных внутрь тега , атрибуты которого управляют общими параметрами внешнего вида диаграммы (заголовки, подписи к осям, формат чисел …), или (приятная возможность для диаграмм которые должны меняться в режиме реального времени) параметры обновления данных с сервера через некоторый интервал.
  1. <html>
  2.   <body bgcolor="#ffffff">
  3.      <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
  4.        codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
  5.        width="900" height="300" id="Column3D" >
  6.            <param name="movie" value="../FusionCharts/Column3D.swf" />
  7.            <param name="FlashVars" value="&dataXML=
  8.            <chart caption='Monthly Sales Summary' subcaption='For the year 2006' 
  9.              xAxisName='Month' yAxisName='Sales' numberPrefix='$'>
  10.               <set label='January' value='17400' />
  11.               <set label='February' value='19800' /><set label='March' value='21800' />
  12.               <set label='June' value='27600'/></chart>">
  13.  
  14.    // и другие параметры
Я бы не стал уделять особое внимание данному продукту - большей частью все его функции стандартны и реализованы где-нибудь еще (и стоят гораздо дешевле, или вообще бесплатно), если бы не PowerCharts Plug. Это дополнение к fusioncharts содержит набор интересных возможностей и нетривиальных видов диаграмм. Прежде всего, Drag-node Chart - это не даже не привычная нам диаграмма, а скорее граф, состоящий из набора узлов (каждый узел - геометрическая фигура: прямоугольник, круг, ромб, …). Также в качестве узла может быть изображение. Узлы графа связаны между собой дугами - естественно, что дуги “резиновые” и при смещении узла (узлы можно тягать мышкой - само название Drag-node Chart говорит об этом) связанные дуги также будут изменяться. Пример внешнего вида такого графа показан на рис. 3.



Откровенно говоря, не радует тот факт, что в исходном xml-файле необходимо явно задать координаты узлов. С одной стороны для сложного и динамически генерируемого графа задача раскладки является сложной математической проблемой, с другой стороны алгоритмы достаточно хорошо известны и существуют более специализированные на графах библиотеки. Drag-node Chart также может работать в режиме “editable”, когда можно не просто тягать по рабочей области узлы графа, но и с помощью контекстного меню добавлять новые узлы и соединяющие их дуги. Вторая возможность PowerCharts Plug - Multi-axis Line Chart - диаграмма, в которой есть несколько осей OY и, соответственно, несколько серий данных с большим разбросом значений по OY см. рис. 4.



Согласитесь, иначе показать одновременно эти серии на одной оси крайне “ненаглядно / неудобочитаемо”. Доступна разновидность Scatter диаграммы с возможностью выделения нескольких областей. Очень интересна диаграмма с возможностью “на лету” менять высоту столбиков (значения) некоторых параметров. Пользователь наглядно тягает столбики мышью, затем жмет кнопку, и данные в формате xml посылаются на сервер - неплохое применение для систем “online подбора параметров” см. рис. 5.



Остальные возможности обычны: логарифмические диаграммы, каскадные, радарные, диаграммы с инвертированной осью OY и многие другие. Разработчик fusioncharts предлагает также набор библиотек для flash с поддержкой карт, gauge-компоненты (привычные угловые и линейные, множество забавных разновидностей в виде градусника, сферы, цилиндра-мензурки), понравились мне и компоненты для отображения диаграмм Ганта. Компоненты диаграммы можно внедрять в ваш fla-файл, как обычные movieclip-ы, а получив исходные коды библиотеки можно сделать ей настоящий “тюнинг”.

Более интересным для нас будет PHP/SWF Charts (домашний сайт: http://www.maani.us). Это не opensource продукт, у него есть две схемы распространения: free и можно купить лицензию. Отличий между free и платной версией не очень много, единственное, что доставляет сильное неудобство - по клику на диаграмме выполняется переход на сайт разработчика, но это можно стерпеть. Доступны два схожих продукта: XML/SWF Charts и PHP/SWF Charts. Отличие в наличии специальной php-библиотеки представляющий дополнительные возможности по генерации xml-файла с описанием набора данных для построения диаграммы.

Начнем с того, что загрузим с сайта разработчика архив с библиотекой (в архиве вы найдете swf-файл который и строит диаграмму, в целью избежать монструозного swf, который умеет все, этот главный файл размером всего в 30 кб, подзагрузит специализированный swf-ролик под тип нужной вам диаграммы). Затем вы создадите новый html-файл, в теле которого вставите код object/embed (я же предпочел воспользоваться swfobject). В качестве параметра необходимо передать имя xml-файла с данными для диаграммы и путь к каталогу, где находятся библиотеки специализированных типов диаграмм, например, так:
  1. <param name=movie value="charts.swf?library_path=charts_library&xml_source=sample.xml">
Теперь надо создать файл sample.xml. Корневой тег - , внутри которого вы с помощью некоторого набора тегов задаете данные и их визуализацию, анимацию диаграммы и пользовательские фигуры рисуемые поверх диаграммы, активные области диаграммы и т.д. Начнем с тега chart_type, с помощью его вы указываете тип будущей диаграммы. Я выбрал столбчатую диаграмму (bar), возможны также варианты: Line, Column, Stacked column, Floating column, 3D column, Stacked 3D column, Parallel 3D column, Pie, 3D Pie, Bar, Stacked bar, Floating bar, Area, Stacked area, Candlestick, Scatter, Polar, Mixed, Composite, Joined. Следующий тег axis_category с его помощью вы задаете параметры внешнего вида оси категорий: шрифты, отступы, минимальное и максимальное значение оси, возможно задать префиксы и суффиксы подписей к оси, цвета, ориентация подписей, полезная функция skip – пропуск подписей (если значений категорий очень много, так чтобы не сливались подписи) и много другое. Тег chart_border – носит декоративную функцию задавая параметры границы области диаграммы (цвет, толщина линий). Пара тегов chart_grid_h и chart_grid_w позволяют управлять сеткой (цвет, прозрачность, толщина и стиль линии). Тег chart_bg позволяет задать цвет рабочей области. Тег chart_transition позволяет управлять стилем появления элементов диаграммы, например, задав атрибуту type значение drop, то столбики значений получат анимацию падения откуда-то сверху, также возможно задать стили: dissolve, drop, spin, scale, zoom, blink, slide_right, slide_left, slide_up, slide_down, если же вы не создадите тег chart_transition, то диаграмма появится мгновенно. Также в этом теге задается время в течении которого должен действовать эффект и порядок в котором будет действовать анимация различных частей диаграммы. Тег link позволяет задать активные зоны на диаграмме, нажатие на которые приводит к открытию некоторого сайта, или вызвать произвольную функцию на javascript. Тег draw содержит внутри себя некоторый сценарий, что нарисовать поверх диаграммы (круг, линия, изображение из внешнего файла, прямоугольник, тестовая надпись). Теперь самое важное: указать набор данных, для этого создайте тег chart_data, внутрь которого располагается произвольное количество тегов row, внутри которых в свою очередь находятся значения. А вот полный пример с использованием многих, но не всех возможностей PHP/SWF Charts, результат же показан на рис. 6:


  1. <chart>
  2.     <chart_data>
  3.         <row>
  4.             <null/>
  5.             <string>2005</string>
  6.             <string>2006</string>
  7.             <string>2007</string>
  8.         </row>
  9.         <row>
  10.             <string>region A</string>
  11.             <number>-15</number>
  12.             <number>45</number>
  13.             <number>100</number>
  14.         </row>
  15.         <row>
  16.             <string>region B</string>
  17.             <number>25</number>
  18.             <number>65</number>
  19.             <number>80</number>
  20.         </row>
  21.         <row>
  22.             <string>region C</string>
  23.             <number>10</number>
  24.             <number>30</number>
  25.             <number>5</number>
  26.         </row>
  27.     </chart_data>
  28.     <chart_grid_h alpha="20" color="000000" thickness="1" type="solid"/>
  29.     <chart_grid_v alpha="20" color="000000" thickness="1" type="dashed"/>
  30.     <chart_rect x="125" y="65" width="250" height="200" positive_color="ffffff" 
  31. negative_color="000000" positive_alpha="75" negative_alpha="15"/>
  32.     <chart_transition type="dissolve" delay="0" duration="2" order="series"/>
  33.     <chart_type>bar</chart_type>
  34.     <draw>
  35.         <text transition="slide_up" delay="1" duration="0.5" color="000033" alpha="15" font="arial"
  36.  rotation="-90" bold="true" size="48" x="0" y="295" width="300" height="50" h_align="right" 
  37.  v_align="middle">GROWTH</text>
  38.         <text transition="slide_up" delay="1" duration="0.5" color="ffffff" alpha="40" font="arial"
  39.  rotation="-90" bold="true" size="25" x="30" y="300" width="300" height="50" h_align="right"
  40.  v_align="middle">report</text>
  41.     </draw>
  42.     <legend_label layout="horizontal" font="arial" bold="true" size="13" color="444466" alpha="90"/>
  43.     <legend_rect x="125" y="10" width="250" height="10" margin="5" fill_color="ffffff"
  44. fill_alpha="35" line_color="000000" line_alpha="0" line_thickness="0"/>
  45.     <legend_transition type="slide_left" delay="0" duration="1"/>
  46. </chart>