Более новая версия доступна в разделе документации.

Предисловие

Данный документ содержит описание двух функциональных модулей платформы CUBA - подсистем отображения диаграмм и географических карт. Эти подсистемы реализованы в одном компоненте платформы - charts, и могут быть подключены в прикладной проект только вместе.

Функциональность отображения диаграмм и карт в настоящий момент доступна только в веб клиенте приложения.

Целевая аудитория

Данное руководство предназначено для разработчиков приложений на платформе CUBA. Предполагается, что читатель ознакомлен с Руководством по разработке приложений, доступным по адресу www.cuba-platform.ru/manual.

Дополнительные материалы

Настоящее Руководство, а также другая документация по платформе CUBA доступны по адресу www.cuba-platform.ru/manual.

Подсистема отображения диаграмм платформы CUBA основана на библиотеке AmCharts, поэтому знакомство с ее устройством будет полезным. См. www.amcharts.com/.

Обратная связь

Если у Вас имеются предложения по улучшению данного руководства, обратитесь, пожалуйста, в службу поддержки по адресу www.cuba-platform.ru/support/topics.

При обнаружении ошибки в документации укажите, пожалуйста, номер главы и приведите небольшой участок окружающего текста для облегчения поиска.

1. Отображение диаграмм

Подсистема отображения диаграмм платформы CUBA поддерживает большое количество типов диаграмм: круговые, линейные, пузырьковые, лепестковые, диаграммы с накоплением и прочие. Имеется возможность экспорта диаграмм. Для большинства типов диаграмм поддерживается прокрутка и зуммирование. Подсистема отображения диаграмм работает только в веб клиенте.

Библиотека AmCharts, на которой основана реализация подсистемы отображения диаграмм, распространяется по лицензии, позволяющей использовать ее бесплатно при сохранении ссылки на сайт библиотеки. Для своего проекта Вы можете купить лицензию на AmCharts и убрать ссылку.

1.1. Добавление диаграмм в проект

Для использования диаграмм в Вашем проекте, необходимо активировать элемент charts в списке App components на экране редактирования свойств проекта (секция Project properties, кнопка Edit) в CUBA Studio.

1.2. Конфигурация диаграмм

Для отображения диаграмм используется компонент Chart, являющийся универсальным холстом. Вид диаграммы задается его свойством configuration типа AbstractChart.

Диаграммы можно описывать в XML-дескрипторе экрана. Для этого необходимо подключить соответствующий namespace:

<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
        ...>

Соответствие элементов XML видам диаграмм:

  • chart:xyChart - XYChart

  • chart:serialChart - SerialChart

  • chart:pieChart - PieChart

  • chart:funnelChart - FunnelChart

  • chart:gaugeChart - AngularGaugeChart

  • chart:radarChart - RadarChart

  • chart:ganttChart - GanttChart

Каждый вид диаграммы имеет свой набор атрибутов и методов, которые повторяют функционал соответствующих диаграмм библиотеки AmCharts. Документация по свойствам и методам диаграмм находится по адресу docs.amcharts.com/3/javascriptcharts.

Все атрибуты конфигурации могут иметь значение null, вместо таких значений будут использоваться значения по умолчанию (кроме случаев, указанных в документации AmCharts).

Диаграммы могут быть экспортированы из работающего приложения в формате изображения или исходных данных. Для создания меню экспорта используется элемент chart:export, включающий по умолчанию следующие атрибуты:

  • Download as…​ с доступными форматами: PNG, JPG, SVG, PDF

  • Save as…​ с доступными форматами: CSV, XLSX, JSON

  • Annotate…​, используемый для добавления заметок и векторных аннотаций. Иинформацию о плагине для создания аннотаций вы можете найти здесь.

  • Print, открывающий стандартное окно отправки страницы на печать.

charts export menu 1

Меню экспорта может быть настроено для ограничения доступа пользователей к данным диаграммы. Собственное меню экспорта может содержать только формат(ы) изображения, например:

<chart:export fileName="my-chart" position="TOP_RIGHT">
    <chart:menu>
        <chart:item label="PNG" title="Save as PNG" format="PNG"/>
        <chart:item label="JPG" title="Save as JPG" format="JPG"/>
    </chart:menu>
</chart:export>

В этом случае пользователю будут доступны только кнопки для прямого скачивания диаграммы в заданных форматах:

charts export menu 2

1.3. Связь с данными

Реализовано два варианта передачи данных в диаграмму: через интерфейс DataProvider или через механизм источников данных.

  • Интерфейс DataProvider имеет стандартную реализацию: класс ListDataProvider. Он содержит список экземпляров DataItem из которых будут браться данные для диаграммы. Существует несколько стандартных реализаций интерфейса DataItem:

    • EntityDataItem принимает экземпляр сущности.

    • MapDataItem содержит набор пар ключ-значение.

    • SimpleDataItem принимает экземпляр любого public класса.

Экземпляр DataProvider передается методу setDataProvider() конфигурации диаграммы. Данный способ предоставления данных для диаграммы наиболее универсален, однако требует создания экземпляров DataProvider и DataItem в коде контроллера экрана.

  • Источник данных типа CollectionDatasource устанавливается для компонента Chart вызовом метода setDatasource(). Данный вариант требует наличия сущности, представляющей данные диаграммы. Он удобен, когда такая сущность уже есть в модели данных приложения, а также когда данные диаграммы нужно отобразить и в виде таблицы.

В главе Пример работы с диаграммами проиллюстрированы оба способа получения данных.

Используемые для отображения свойства сущности или значения, содержащиеся в экземпляре DataProvider, задаются в атрибутах диаграммы, причем атрибуты различаются для разных типов диаграмм. Например для компонента chart:pieChart необходимо задать атрибуты valueField и titleField.В качестве значений могут выступать типы Integer, Long, Double, String, Boolean, Date.

Динамическое добавление данных в существующий график поддерживается для обоих механизмов.

1.4. События

Имеется возможность настроить реакцию на различные типы событий. Доступны следующие типы слушателей событий:

  • AxisZoomListener - масштабирование оси графика.

  • ChartClickListener - щелчок по холсту.

  • RightClickListener - щелчок по холсту правой клавишей мыши.

  • CursorPeriodSelectListener - выбор периода отображения курсором.

  • CursorZoomListener - масштабирование области графика курсором.

  • GraphClickListener - щелчок по графику.

  • GraphItemClickListener - щелчок по элементу графика.

  • LegendItemHideListener - скрытие элемента легенды.

  • LegendItemShowListener - показ элемента легенды.

  • LegendItemClickListener - щелчок по элементу легенды.

  • SliceClickListener - щелчок по элементу круговой диаграммы.

  • SliceRightClickListener - щелчок по элементу круговой диаграммы правой клавишей мыши.

  • SlicePullInListener - элемент круговой диаграммы соединён с диаграммой.

  • SlicePullOutListener - элемент круговой диаграммы отсоединён от диаграммы.

  • ZoomListener - масштабирование холста.

Пример использования событий проиллюстрирован в разделе Использование событий.

1.5. Пример работы с диаграммами

В данной главе мы рассмотрим применение подсистемы отображения диаграмм.

1.5.1. Настройка проекта приложения

  1. Запустите CUBA Studio, создайте новй проект и назовите его sampler.

  2. Откройте окно свойств проекта Project propertiesEdit и в списке App components включите проект charts, затем сохраните изменения. Studio предложит пересоздать скрипты Gradle - согласитесь.

  3. Запустите RunDeploy. На этом этапе будет произведена сборка приложения, и оно будет развернуто на сервере Tomcat в подкаталоге build/tomcat.

  4. Запустите BuildCreate or update IDEA project files чтобы создать проектные файлы для IntelliJ IDEA.

После выполнения вышеописанных действий функциональность для отображения диаграмм подключена к приложению и готова к работе.

1.5.2. Создание диаграммы с данными из сущности

Для первого примера мы создадим диаграмму похожую на 3D Stacked Column Chart из демо AmCharts. JavaScript код выглядит следующим образом:

var chart = AmCharts.makeChart("chartdiv", {
    "theme": "light",
    "type": "serial",
    "dataProvider": [{
        "country": "USA",
        "year2004": 3.5,
        "year2005": 4.2
    }, {
        "country": "UK",
        "year2004": 1.7,
        "year2005": 3.1
    }, {
        "country": "Canada",
        "year2004": 2.8,
        "year2005": 2.9
    }, {
        "country": "Japan",
        "year2004": 2.6,
        "year2005": 2.3
    }, {
        "country": "France",
        "year2004": 1.4,
        "year2005": 2.1
    }, {
        "country": "Brazil",
        "year2004": 2.6,
        "year2005": 4.9
    }, {
        "country": "Russia",
        "year2004": 6.4,
        "year2005": 7.2
    }, {
        "country": "India",
        "year2004": 8,
        "year2005": 7.1
    }, {
        "country": "China",
        "year2004": 9.9,
        "year2005": 10.1
    }],
    "valueAxes": [{
        "stackType": "3d",
        "unit": "%",
        "position": "left",
        "title": "GDP growth rate",
    }],
    "startDuration": 1,
    "graphs": [{
        "balloonText": "GDP grow in [[category]] (2004): <b>[[value]]</b>",
        "fillAlphas": 0.9,
        "lineAlpha": 0.2,
        "title": "2004",
        "type": "column",
        "valueField": "year2004"
    }, {
        "balloonText": "GDP grow in [[category]] (2005): <b>[[value]]</b>",
        "fillAlphas": 0.9,
        "lineAlpha": 0.2,
        "title": "2005",
        "type": "column",
        "valueField": "year2005"
    }],
    "plotAreaFillAlphas": 0.1,
    "depth3D": 60,
    "angle": 30,
    "categoryField": "country",
    "categoryAxis": {
        "gridPosition": "start"
    },
    "export": {
            "enabled": true
     }
});
1.5.2.1. Создание сущности
  1. Откройте кладку Entities в CUBA Studio и нажмите кнопку New entity.

  2. В диалоге создания новой сущности задайте ей имя CountryGrowth и выберите тип Not persistent, после чего нажмите кнопку OK.

  3. Используя Entity Designer добавьте атрибуты:

    • country типа String

    • year2014 типа Double

    • year2015 типа Double

  4. Откройте вкладку Source, чтобы увидеть сгенерированный код:

    package com.company.sampler.entity;
    
    import com.haulmont.chile.core.annotations.MetaClass;
    import com.haulmont.chile.core.annotations.MetaProperty;
    import com.haulmont.cuba.core.entity.AbstractNotPersistentEntity;
    
    @MetaClass(name = "sampler$CountryGrowth")
    public class CountryGrowth extends AbstractNotPersistentEntity {
    
        @MetaProperty
        protected String country;
    
        @MetaProperty
        protected Double year2014;
    
        @MetaProperty
        protected Double year2015;
    
        public void setCountry(String country) {
            this.country = country;
        }
    
        public String getCountry() {
            return country;
        }
    
        public void setYear2014(Double year2014) {
            this.year2014 = year2014;
        }
    
        public Double getYear2014() {
            return year2014;
        }
    
        public void setYear2015(Double year2015) {
            this.year2015 = year2015;
        }
    
        public Double getYear2015() {
            return year2015;
        }
    }

    Этот класс описывает неперсистентную сущность. Экземпляр этого класса содержит процент роста ВВП страны за 2014 и 2015 года.

  5. Нажмите кнопку OK, чтобы сохранить сущность и закрыть экран дизайнера.

  6. Во вкладке Entities нажмите Generate DB scripts и сохраните сгенерированные скрипты.

  7. Создайте базу данных приложения, запустив RunCreate database.

1.5.2.2. Создание диаграммы
1.5.2.2.1. XML-дескриптор экрана

Откройте в CUBA Studio вкладку Screens и создайте экран в модуле web. Введите значение com/company/sampler/web/screens/column3d-chart.xml в поле Descriptor. В полях Id, Controller Name и Messages Pack будут сгенерированы подходящие значения. Сохраните изменения. Далее перейдите на вкладку XML и замените ее содержимое на следующий код:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://caption"
        class="com.company.sampler.web.screens.Column3dChart"
        messagesPack="com.company.sampler.web.screens"
        xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
    <dsContext>
        <collectionDatasource id="countryGrowthDs"
                              class="com.company.sampler.entity.CountryGrowth"
                              refreshMode="NEVER"
                              view="_local">
            <query>
                <![CDATA[select e from sampler$CountryGrowth e]]>
            </query>
        </collectionDatasource>
    </dsContext>
    <layout>
        <chart:serialChart id="chart"
                           angle="30"
                           categoryField="country"
                           datasource="countryGrowthDs"
                           depth3D="60"
                           height="100%"
                           plotAreaFillAlphas="0.1"
                           startDuration="1"
                           width="100%">
            <chart:categoryAxis gridPosition="START"/>
            <chart:valueAxes>
                <chart:axis position="LEFT"
                            stackType="BOX_3D"
                            title="GDP growth rate"
                            unit="%"/>
            </chart:valueAxes>
            <chart:graphs>
                <chart:graph id="graph2014"
                             balloonText="GDP grow in [[category]] (2014): &lt;b&gt;[[value]]&lt;/b&gt;"
                             fillAlphas="0.9"
                             lineAlpha="0.2"
                             title="2014"
                             type="COLUMN"
                             valueField="year2014"/>
                <chart:graph id="graph2015"
                             balloonText="GDP grow in [[category]] (2015): &lt;b&gt;[[value]]&lt;/b&gt;"
                             fillAlphas="09."
                             lineAlpha="0.2"
                             title="2015"
                             type="COLUMN"
                             valueField="year2015"/>
            </chart:graphs>
            <chart:export/>
        </chart:serialChart>
    </layout>
</window>

В корневой элемент дескриптора экрана добавлен атрибут xmlns:chart:

<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
    ...
    >

Диаграмма получает данные из источника countryGrowthDs, указанного в атрибуте datasource. Для отображения названий и значений используются атрибуты country, year2014 и year2015 сущности CountryGrowth, список экземпляров которой находится в источнике данных.

Компонент chart:serialChart содержит следующие атрибуты:

  • angle - определяет угол наклона диаграммы. Может принимать значения от 0 до 90.

  • balloonText - определяет текст всплывающей подсказки при наведении на колонку диаграммы. Доступны для использования тэги [[value]], [[title]], [[persents]], [[description]], а также ключи из DataItem, список которых хранится в экземпляре DataProvider, либо имена атрибутов сущности в источнике данных. Для использования html тегов, их нужно экранировать.

  • depth3D - толщина диаграммы. При использовании совместно с атрибутом angle позволяет создать эффект объема.

  • plotAreaFillAlphas - степень непрозрачности области графика.

  • startDuration - длительность анимации в секундах.

  • categoryField - ключ из набора пар, содержащихся в объектах DataItem, список которых хранится в экземпляре DataProvider, по которому будут взяты значения для подписи оси категорий.

Компонент chart:serialChart содержит следующие элементы:

  • chart:categoryAxis - элемент, описывающий ось категорий.

    • Атрибут gridPosition определяет будет ли линия сетки расположена по центру ячейки или от ее начала.

  • chart:valueAxes - элемент, описывающий вертикальные оси значений. В данном случае используется только одна ось, описываемая элементом chart:axis

    • Атрибут position задает положение оси значений относительно диаграммы.

    • Установка атрибуту stackType значения BOX_3D говорит о том, что колонки гистограммы будут расположены одна позади другой.

  • chart:graphs - элемент, описывающий графы диаграммы. Граф описывается элементом chart:graph.

    • Атрибут type задает тип графа и может быть: line, column, step line, smoothed line, olhc и candlestick.

    • Атрибут `valueField`определяет ключ из набора пар, содержащихся в объектах DataItem, список которых хранится в экземпляре DataProvider, по которому будет взято значение.

    • Атрибут fillAlphas задает степень непрозрачности заполнения.

    • Атрибут lineAlpha задает степень непрозрачности линии (или рамки колонки).

  • chart:export – добавляет возможность сохранить полученный график.

1.5.2.2.2. Контроллер экрана

Перейдите на вкладку Controller и замените ее содержимое на следующий код:

package com.company.sampler.web.screens;

import com.company.sampler.entity.CountryGrowth;
import com.haulmont.cuba.gui.components.AbstractWindow;
import com.haulmont.cuba.gui.data.CollectionDatasource;

import javax.inject.Inject;
import java.util.Map;
import java.util.UUID;

public class Column3dChart extends AbstractWindow {
    @Inject
    private CollectionDatasource<CountryGrowth, UUID> countryGrowthDs;

    @Override
    public void init(Map<String, Object> params) {
        countryGrowthDs.refresh();

        countryGrowthDs.includeItem(countryGrowth("USA", 3.5, 4.2));
        countryGrowthDs.includeItem(countryGrowth("UK", 1.7, 3.1));
        countryGrowthDs.includeItem(countryGrowth("Canada", 2.8, 2.9));
        countryGrowthDs.includeItem(countryGrowth("Japan", 2.6, 2.3));
        countryGrowthDs.includeItem(countryGrowth("France", 1.4, 2.1));
        countryGrowthDs.includeItem(countryGrowth("Brazil", 2.6, 4.9));
        countryGrowthDs.includeItem(countryGrowth("Russia", 6.4, 7.2));
        countryGrowthDs.includeItem(countryGrowth("India", 8.0, 7.1));
        countryGrowthDs.includeItem(countryGrowth("China", 9.9, 10.1));
    }

    private CountryGrowth countryGrowth(String country, double year2014, double year2015) {
        CountryGrowth cg = new CountryGrowth();
        cg.setCountry(country);
        cg.setYear2014(year2014);
        cg.setYear2015(year2015);
        return cg;
    }
}

В Методе init(Map<String, Object> params) происходит заполнение источника данных countryGrowthDs данными. Метод refresh() производит инициализацию источника данных. Этот метод необходимо вызвать, несмотря на атрибут refreshMode="NEVER", установленный в XML-дескрипторе.

1.5.2.3. Результат
  1. Откройте вкладку Main Menu в CUBA Studio и нажмите кнопку edit для web-menu.xml.

  2. Выберите элемент application и нажмите кнопку new.

  3. В диалоге создания элемента меню выберите column3d-chart в поле id и нажмите add.

  4. Выполните комманду RunStart application server.

После входа в приложение и открытия экрана из меню приложения, вы увидите диаграмму, как показано ниже:

column3d chart
Рисунок 1. Трехмерная гистограмма

1.5.3. Создание диаграммы с данными из DataProvider

Данная диаграмма получает данные из экземпляра DataProvider, создаваемого в контроллере экрана, поэтому атрибут datasource не определен.

1.5.3.1. Создание диаграммы
1.5.3.1.1. XML-дескриптор экрана

Откройте в CUBA Studio вкладку Screens и создайте экран в модуле web. Введите значение com/company/sampler/web/screens/stackedarea-chart.xml в поле Descriptor. В полях Id, Controller Name и Messages Pack будут сгенерированы подходящие значения. Сохраните изменения. Далее перейдите на вкладку XML и замените ее содержимое на следующий код:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://caption"
        class="com.company.sampler.web.screens.StackedAreaChart"
        messagesPack="com.company.sampler.web.screens"
        xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
    <layout>
        <chart:serialChart id="chart"
                           categoryField="year"
                           height="100%"
                           marginLeft="0"
                           marginTop="10"
                           plotAreaBorderAlpha="0"
                           width="100%">
            <chart:chartCursor cursorAlpha="0"/>
            <chart:legend equalWidths="false"
                          periodValueText="total: [[value.sum]]"
                          position="TOP"
                          valueAlign="LEFT"
                          valueWidth="100"/>
            <chart:valueAxes>
                <chart:axis gridAlpha="0.07"
                            position="LEFT"
                            stackType="REGULAR"
                            title="Traffic incidents"/>
            </chart:valueAxes>
            <chart:graphs>
                <chart:graph fillAlphas="0.6"
                             hidden="true"
                             lineAlpha="0.4"
                             title="Cars"
                             valueField="cars"/>
                <chart:graph fillAlphas="0.6"
                             lineAlpha="0.4"
                             title="Motorcycles"
                             valueField="motorcycles"/>
                <chart:graph fillAlphas="0.6"
                             lineAlpha="0.4"
                             title="Bicycles"
                             valueField="bicycles"/>
            </chart:graphs>
            <chart:categoryAxis axisColor="#DADADA"
                                gridAlpha="0.07"
                                startOnAxis="true"/>
            <chart:export/>
        </chart:serialChart>
    </layout>
</window>

В корневой элемент дескриптора экрана добавлен атрибут xmlns:chart:

<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
    ...
>

Компонент chart:serialChart содержит следующие атрибуты:

  • categoryField - ключ из набора пар, содержащихся в объектах DataItem, список которых хранится в экземпляре DataProvider, по которому будут взяты значения для подписи оси категорий.

Компонент chart:serialChart содержит следующие элементы:

  • chart:chartCursor - необязательный элемент, добавляющий курсор к диаграмме. Курсор следует за указателем мыши и показывает всплывающие подсказки со значениями элементов диаграммы над которыми находится указатель мыши.

    • Атрибут cursorAlpha задает степень непрозрачности линий курсора.

  • chart:legend - определяет легенду графика.

    • Атрибут position определяет положение легенды относительно диаграммы.

    • Атрибут equalWidths определяет, должны ли все элементы легенды быть такой же ширины как самый широкий.

    • Атрибут periodValueText задает текст, который будет показан в значении легенды, когда пользователь не раполагает указатель мыши ни над одним элементом данных. Теги должны состоять из пары значений - название поля (value / open / close / high / low) и значение периода, для которого дожно быть показано значение - open / close / high / low / sum / average / count.

    • Атрибут valueAlign задает выранивание значения. Возможные значения "left" и "right".

    • Атрибут valueWidth задает ширину значения.

  • chart:valueAxes - элемент, описывающий вертикальные оси значений. В данном случае используется только одна ось, описываемая элементом chart:axis

    • Атрибут position задает положение оси значений относительно диаграммы.

    • Атрибут title задает заголовок оси значения.

    • Установка атрибуту stackType значения REGULAR говорит о том, что используется диаграмма с накоплением. По умолчанию значение этого атрибута - none, в таком случае используется диаграмма без накопления.

    • Атрибут gridAlpha задает степень непрозрачности линий сетки.

  • chart:graphs - элемент, описывающий графы диаграммы. Граф описывается элементом chart:graph.

    • Атрибут type задает тип графа и может быть: line, column, step line, smoothed line, olhc и candlestick.

    • Атрибут valueField определяет ключ из набора пар, содержащихся в объектах DataItem, список которых хранится в экземпляре DataProvider, по которому будет взято значение.

    • Атрибут fillAlphas задает степень непрозрачности заполнения.

    • Атрибут lineAlpha задает степень непрозрачности линии (или рамки колонки).

    • Атрибут hidden определяет, будет ли граф отображаться.

  • chart:categoryAxis - элемент, описывающий ось категорий.

    • Установка атрибуту startOnAxis значения true дает указание начинать отрисовывать график сразу от оси значений. По умолчанию этот атрибут имеет значение false. В этом случае между осью значений и графиком имеется некоторый помежуток.

    • Атрибут gridAlpha задает степень непрозрачности линий сетки.

    • Атрибут axisColor задает цвет оси.

  • chart:export – добавляет возможность сохранить полученный график.

1.5.3.1.2. Контроллер экрана

Перейдите на вкладку Controller и замените ее содержимое на следующий код:

package com.company.sampler.web.screens;

import com.haulmont.charts.gui.amcharts.model.charts.SerialChart;
import com.haulmont.charts.gui.amcharts.model.data.DataItem;
import com.haulmont.charts.gui.amcharts.model.data.ListDataProvider;
import com.haulmont.charts.gui.amcharts.model.data.MapDataItem;
import com.haulmont.charts.gui.components.charts.Chart;
import com.haulmont.cuba.gui.components.AbstractWindow;

import javax.inject.Inject;
import java.util.Map;

public class StackedAreaChart extends AbstractWindow {
    @Inject
    private Chart chart;

    @Override
    public void init(Map<String, Object> params) {
        ListDataProvider dataProvider = new ListDataProvider();


        dataProvider.addItem(transportCount(1994, 1587, 650, 121));
        dataProvider.addItem(transportCount(1995, 1567, 683, 146));
        dataProvider.addItem(transportCount(1996, 1617, 691, 138));
        dataProvider.addItem(transportCount(1997, 1630, 642, 127));
        dataProvider.addItem(transportCount(1998, 1660, 699, 105));
        dataProvider.addItem(transportCount(1999, 1683, 721, 109));
        dataProvider.addItem(transportCount(2000, 1691, 737, 112));
        dataProvider.addItem(transportCount(2001, 1298, 680, 101));
        dataProvider.addItem(transportCount(2002, 1275, 664, 97));
        dataProvider.addItem(transportCount(2003, 1246, 648, 93));
        dataProvider.addItem(transportCount(2004, 1318, 697, 111));
        dataProvider.addItem(transportCount(2005, 1213, 633, 87));
        dataProvider.addItem(transportCount(2006, 1199, 621, 79));
        dataProvider.addItem(transportCount(2007, 1110, 210, 81));
        dataProvider.addItem(transportCount(2008, 1165, 232, 75));
        dataProvider.addItem(transportCount(2009, 1145, 219, 88));
        dataProvider.addItem(transportCount(2010, 1163, 201, 82));
        dataProvider.addItem(transportCount(2011, 1180, 285, 87));
        dataProvider.addItem(transportCount(2012, 1159, 277, 71));

        SerialChart serialChart = (SerialChart) chart.getConfiguration();
        serialChart.setDataProvider(dataProvider);
    }

    private DataItem transportCount(int year, int cars, int motorcycles, int bicycles) {
        MapDataItem item = new MapDataItem();
        item.add("year", year);
        item.add("cars", cars);
        item.add("motorcycles", motorcycles);
        item.add("bicycles", bicycles);
        return item;
    }
}

В методе init(Map<String, Object> params) происходит установка данных в диаграмму с накоплением. Диаграммы подобного типа показывают отношение отдельных составляющих к их совокупному значению.

1.5.3.2. Результат
  1. Откройте вкладку Main Menu в CUBA Studio и нажмите кнопку edit для web-menu.xml.

  2. Выберите элемент application и нажмите кнопку new.

  3. В диалоге создания элемента меню выберите stackedarea-chart в поле id и нажмите add.

  4. Выполните комманду RunStart application server.

После входа в приложение и открытия экрана из меню приложения, вы увидите диаграмму, как показано ниже:

stackedarea chart
Рисунок 2. Диаграмма с накоплением

1.5.4. Использование событий

Проиллюстрируем использование событий. Добавим в экран, созданный в разделе Создание диаграммы, обработку события нажатия на элемент графа. Откройте XML-дескриптор экрана в IDE, затем инжектируйте диаграмму:

@Inject
private Chart chart;

Далее добавьте слушателя в конце метода init(Map<String, Object> params):

chart.addGraphItemClickListener(event -> {
        CountryGrowth countryGrowth = (CountryGrowth) event.getItem();
        String message = String.format("GDP grow in %s (%s): %.1f%%",
        countryGrowth.getCountry(),
        event.getGraphId().substring(5),
        "graph2014".equals(event.getGraphId()) ? countryGrowth.getYear2014() : countryGrowth.getYear2015());
        showNotification(message, NotificationType.HUMANIZED_HTML);
});

Для просмотра результата пересоберите проект командой RunRestart application server и зайдите в систему. Откройте экран и нажмите на одину из колонок гистограммы.

chart with event
Рисунок 3. Диаграмма с обработкой события нажатия на элемент графа

1.5.5. Конфигурация с помощью JSON

Для конфигурации графика, помимо указания атрибутов в XML, можно напрямую использовать JSON, описанный в документации AmCharts.

Рассмотрим это на примере serialChart:

<chart:serialChart id="serialChart">
    <chart:valueAxes>
        <chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
    </chart:valueAxes>
    <chart:graphs>
        <chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
    </chart:graphs>
    <chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>

Для графика заданы определенные данные:

@Inject
protected Chart serialChart;

@Override
public void init(Map<String, Object> params) {
    super.init(params);

    ListDataProvider serialChartDataProvider = new ListDataProvider();
    int[] serialChartChartData = {5, 7, 6, 9, 7, 8, 5, 6, 4, 6, 5, 7, 4, 5, 3, 4, 2, 0};

    for (int i = 0; i < redLineChartData.length; i++) {
        serialChartDataProvider.addItem(graphData(serialChartChartData[i]));
    }

    SerialChart serialChartConfiguration = (SerialChart) serialChart.getConfiguration();
    serialChartConfiguration.setDataProvider(serialChartDataProvider);
}
chart custom json

Теперь мы можем изменить конфигурацию графика. Например, добавить заголовок:

serialChart.setCustomJson("{\n" +
        " \"titles\": [\n" +
        " {\n" +
        " \"size\": 15,\n" +
        " \"text\": \"Chart Title\"\n" +
        " }\n" +
        " ]\n" +
        "}");
chart custom json title

Также возможно задать JSON конфигурацию с помощью XML:

<chart:serialChart id="serialChart">
    <chart:customJson>
        <![CDATA[
        {
            "titles": [
                {
                    "size": 15,
                    "text": "Chart Title"
                }
            ]
        }
        ]]>
    </chart:customJson>
    <chart:valueAxes>
        <chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
    </chart:valueAxes>
    <chart:graphs>
        <chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
    </chart:graphs>
    <chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>

1.6. Типы диаграмм

Существует несколько типов диаграмм, поддерживаемых платформой.

charts hierarchy dia
Рисунок 4. Иерархия видов диаграмм

1.6.1. SerialChart

Компонент SerialChart позволяет вам создать большое количество диаграмм: линейчатые, диаграммы с областями, гистограммы, диаграммы с накоплением и прочие. Такие диаграммы поддерживают несколько осей в простом или логарифмическом масштабе. Данные могут быть отображены на равных/неравных отрезках или на временной шкале.

line chart
Рисунок 5. SerialChart в виде линейного графика
column chart
Рисунок 6. SerialChart в виде гистограммы

1.6.2. PieChart

Компонент PieChart позволяет вам создать круговые диаграммы.

pie chart
Рисунок 7. PieChart

1.6.3. XYChart

Компонент XYChart позволяет вам создать точечные диаграммы, графики и пузырьковые диаграммы. Такие диаграммы поддерживают несколько осей в простом или логарифмическом масштабе.

xy chart
Рисунок 8. XYChart

1.6.4. FunnelChart

Компонент FunnelChart позволяет вам создать пирамиды или конусы.

funnel chart
Рисунок 9. FunnelChart

1.6.5. RadarChart

Компонент RadarChart позволяет вам создать радиальные/сетчатые диаграммы.

radar chart
Рисунок 10. RadarChart

1.6.6. AngularGaugeChart

Компонент AngularGaugeChart позволяет вам создать диаграмму-спидометр.

gauge chart
Рисунок 11. GaugeChart

1.6.7. GanttChart

Компонент GanttChart позволяет вам создать диаграмму Ганта.

gantt chart
Рисунок 12. GanttChart

1.6.8. StockChartGroup

Компонент StockChartGroup позволяет вам создать фондовую диаграмму.

Фондовые диаграммы поддерживают несколько наборов данных и имеют готовый к использованию селектор наборов данных. Наборы данных можно сравнивать между собой.

stock chart with datasets
Рисунок 13. StockChart с несколькими наборами данных

Фондовые диаграммы могут отображать различные типы аннотаций на графе или оси. Эти аннотации называются stock events.

stock chart with stockevents
Рисунок 14. StockChart содержащий StockEvents

Фондовые диаграммы поддерживают любое количество панелей. Каждая панель может иметь любое количество графов. Каждая панель - это отдельная диаграмма и базируется на SerialChart. Другими словами панель может все то же самое, что и эта диаграмма.

stock chart with panels
Рисунок 15. StockChart с несколькими панелями

1.7. Замена версии AmCharts

Версию библиотеки AmCharts, включенную в платформу, можно заменить на другую. Для этого необходимо:

  1. Скачать исходный код charts и stock charts с сайта AmCharts.

  2. Объединить содержимое папок amcharts в одну папку.

  3. Скопировать папку amcharts в {project.rootDir}/modules/web/web/VAADIN/resources

  4. Произвести развертывание приложения заново.

Для использования новых атрибутов, добавленных в новой версии, необходимо в контроллере экрана задать пользовательскую JSON строку для диаграммы, как показано ниже.

CubaAmchartsScene cubaAmchartsScene = (CubaAmchartsScene) WebComponentsHelper.unwrap(chart);
cubaAmchartsScene.setJson("{\"valueScrollbar\":{\"autoGridCount\":true}}");

2. Отображение карт

Подсистема отображения карт платформы CUBA основана на интеграции со сторонним поставщиком сервиса карт. На данный момент поддерживается только сервис Google Maps.

2.1. Возможности отображения карты

  • Реакция на события:

    • Щелчок мышью.

    • Перемещение и зуммирование карты.

    • Щелчок по маркеру и его перетаскивание.

    • Закрытие всплывающего окна.

      map demo click
  • Установка маркеров. Маркер может быть фиксированным или с перетаскиваемым пользователем. Маркер может обрабатывать щелчки мыши и передавать соответствующее событие в код экрана.

    map demo marker
  • Отображение ломаных линий и полигонов (многоугольников).

    map demo polygon display
  • Рисование полигонов.

    map demo polygon draw
  • Отображение тепловой карты (heat map).

    map demo heatmap

2.2. Настройка проекта приложения

Для отображения карт в проект приложения необходимо подключить компонент charts, как это описано для подсистемы отображения диаграмм. Кроме того, необходимо установить следующие свойства приложения блока Web Client:

  • Один из следующих параметров (см. подробную информацию об этих параметра в документации Google Maps API):

    • charts.map.apiKey - browser key.

    • charts.map.clientId - client ID.

  • Необязательные параметры:

    • charts.map.defaultZoom - масштаб карты (zoom) по умолчанию.

    • charts.map.defaultLatitude - широта центра карты по умолчанию.

    • charts.map.defaultLongitude - долгота центра карты по умолчанию.

Пример содержимого файла web-app.properties:

charts.map.apiKey = my_key
charts.map.defaultZoom = 13.0
charts.map.defaultLatitude = 51.5001
charts.map.defaultLongitude = -0.1262

2.3. Компонент MapViewer

Для отображения карт в экранах приложения используется компонент com.haulmont.charts.gui.components.map.MapViewer.

Для подключения компонента в XML-дескриптор экрана в корневом элементе необходимо объявить пространство имен chart:

<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
        ...>

XML-имя компонента: mapViewer. Пример объявления компонента:

<layout>
    <vbox id="mapBox" height="100%">
        <chart:mapViewer id="map" width="100%" height="100%"/>
    </vbox>
</layout>

В XML-дескрипторе можно задать следующие параметры компонента:

  • id, width, height - стандартные параметры компонентов.

  • mapType - тип карты, соответствующий перечислению MapViewer.Type: roadmap, satellite, hybrid, terrain. По умолчанию выбирается roadmap.

  • vendor - поставщик сервиса. На данный момент поддерживается только значение google.

Основная настройка карты и ее компонентов производится в контроллере экрана. Для этого достаточно инжектировать компонент, объявленный в XML-дескрипторе:

@Inject
private MapViewer map;

@Override
public void init(Map<String, Object> params) {
    GeoPoint center = map.createGeoPoint(53.490905, -2.249558);
    map.setCenter(center);
}
  • Методы настройки карты:

    • setZoom() - задание масштаба карты.

    • setCenter() - задание центра карты.

    • setVisibleAreaBoundLimitsEnabled() - включение режима, ограничивающего видимую область карты.

    • setVisibleAreaBoundLimits() - задание границ видимости карты.

    • fitToBounds() - задание минимального масштаба карты, при котором будет полностью отображена область, заданная северо-восточной и юго-западной коордианатами.

    • setMaxZoom() - задание максимального доступного масштаба.

    • setMinZoom() - задание минимального доступного масштаба.

    • setDraggable() - включение/выключение режима перетаскивания карты.

    • setKeyboardShortcutsEnabled() - включение/выключение сочетаний клавиш.

    • setScrollWheelEnabled() - включение/выключение изменения масштаба карты с помощью колесика мыши.

    • setMapType() - задание типа карты.

  • Интерфейсы компонентов карты (располагаются в пакете com.haulmont.charts.gui.map.model):

    • GeoPoint - вспомогательный компонент, непосредственно не отображаемый на карте. Используется для задания параметров карты, таких как центр, границы, и для создания более сложных компонентов карты. Для создания объекта используется метод createGeoPoint() интерфейса MapViewer. Например:

      GeoPoint center = map.createGeoPoint(53.490905, -2.249558);
      map.setCenter(center);
    • Marker - компонент для отметки места на карте. По умолчанию используется стандартная иконка сервиса карт. Для создания и размещения объекта на карте используются методы createMarker() и addMarker() интерфейса MapViewer. Например:

      Marker marker = map.createMarker("My place", map.createGeoPoint(53.590905, -2.249558), true);
      marker.setClickable(true);
      map.addMarker(marker);
    • Polyline - компонент для отображения ломаной линии. Для создания и размещения объекта на карте используются методы createPolyline() и addPolyline() интерфейса MapViewer. Например:

      List<GeoPoint> coordinates = new ArrayList<>();
      coordinates.add(map.createGeoPoint(53.49, -2.54));
      coordinates.add(map.createGeoPoint(53.49, -2.22));
      coordinates.add(map.createGeoPoint(53.89, -2.22));
      coordinates.add(map.createGeoPoint(53.99, -2.94));
      Polyline polyline = map.createPolyline(coordinates);
      map.addPolyline(polyline);
    • Polygon - компонент для отображения полигона. Для создания и размещения объекта на карте используются методы createPolygon() и addPolygonOverlay() интерфейса MapViewer. Например:

      List<GeoPoint> coordinates = new ArrayList<>();
      coordinates.add(map.createGeoPoint(53.49, -2.54));
      coordinates.add(map.createGeoPoint(53.49, -2.22));
      coordinates.add(map.createGeoPoint(53.89, -2.22));
      coordinates.add(map.createGeoPoint(53.99, -2.94));
      Polygon p = map.createPolygon(coordinates, "#9CFBA9", 0.6, "#2CA860", 1.0, 2);
      map.addPolygonOverlay(p);
    • InfoWindow - компонент карты для отображения информации во всплывающем окне. Для создания и размещения объекта на карте используются методы createInfoWindow() и openInfoWindow() интерфейса MapViewer. Например:

      InfoWindow w = map.createInfoWindow("Some text");
      map.openInfoWindow(w);

      Информационное окно может быть привязано к маркеру, например:

      map.addMarkerClickListener(new MarkerClickListener() {
          @Override
          public void onClick(MarkerClickEvent event) {
              Marker marker = event.getMarker();
              String caption = String.format("Marker clicked: %.2f, %.2f",
                      marker.getPosition().getLatitude(),
                      marker.getPosition().getLongitude());
              InfoWindow w = map.createInfoWindow(caption, marker);
              map.openInfoWindow(w);
          }
      });
    • HeatMapLayer - слой тепловой карты: предназначен для изображения плотности данных в различных географических точках. Степень плотности точек отображается с помощью цвета. По умолчанию области с высокой плотностью точек отображаются красным цветом, а области с низкой - зелёным. Для создания и размещения объекта на карте используются методы createHeatMapLayer() и addHeatMapLayer() интерфейса MapViewer. Например:

      HeatMapLayer heatMapLayer = map.createHeatMapLayer();
      List<GeoPoint> data = new ArrayList<>();
      data.add(map.createGeoPoint(53.450, -2.00));
      data.add(map.createGeoPoint(53.451, -2.00));
      data.add(map.createGeoPoint(53.452, -2.00));
      data.add(map.createGeoPoint(53.453, -2.00));
      data.add(map.createGeoPoint(53.454, -2.00));
      heatMapLayer.setData(data);
      map.addHeatMapLayer(heatMapLayer);

      Данные добавленного на карту слоя тепловой карты могут быть изменены с помощью дополнительного вызова метода setData(). Заново добавлять слой на карту при этом не требуется.

    • DrawingOptions - компонент поддержки рисования. В данный момент поддерживается только рисование полигонов. Режим рисования будет включен если в MapViewer передан экземпляр DrawingOptions. Пример использования:

      DrawingOptions options = new DrawingOptions();
      PolygonOptions polygonOptions = new PolygonOptions(true, true, "#993366", 0.6);
      ControlOptions controlOptions = new ControlOptions(
          Position.TOP_CENTER, Arrays.asList(OverlayType.POLYGON));
      options.setEnableDrawingControl(true);
      options.setPolygonOptions(polygonOptions);
      options.setDrawingControlOptions(controlOptions);
      options.setInitialDrawingMode(OverlayType.POLYGON);
      map.setDrawingOptions(options);
  • Слушатели событий (располагаются в пакете com.haulmont.charts.gui.map.model.listeners):

    • MapMoveListener - перемещение карты с зажаток клавишей мыши.

    • MapClickListener - щелчок по карте.

    • MarkerClickListener - щелчок по маркеру.

    • MarkerDragListener - перетаскивание маркера.

    • InfoWindowClosedListener - закрытие информационного окна.

    • PolygonCompleteListener - создание полигона в режиме редактирования.

    • PolygonEditListener - редактирование полигона (перемещение или добавление вершины существующего полигона).

    • MapInitListener - завершение инициализации карты: вызывается один раз после первоначальной загрузки карты, когда тайлы загружены и координаты доступны.

Для более подробной информации о методах и параметрах компонентов карты см. соответствующие JavaDocs.

. . .