Данный документ содержит описание двух функциональных модулей платформы CUBA - подсистем отображения диаграмм и географических карт. Эти подсистемы реализованы в одном базовом проекте платформы - charts, и могут быть подключены в прикладной проект только вместе.
Функциональность отображения диаграмм и карт в настоящий момент доступна только в веб клиенте приложения.
Данное руководство предназначено для разработчиков приложений на платформе CUBA. Предполагается, что читатель ознакомлен с Руководством по разработке приложений, доступным по адресу www.cuba-platform.ru/manual.
Настоящее Руководство, а также другая документация по платформе CUBA доступны по адресу www.cuba-platform.ru/manual.
Подсистема отображения диаграмм платформы CUBA основана на библиотеке AmCharts, поэтому знакомство с ее устройством будет полезным. См. www.amcharts.com/.
Если у Вас имеются предложения по улучшению данного руководства, обратитесь, пожалуйста, в службу поддержки по адресу ru.cuba-platform.com/support/topics.
При обнаружении ошибки в документации укажите, пожалуйста, номер главы и приведите небольшой участок окружающего текста для облегчения поиска.
Подсистема отображения диаграмм платформы CUBA поддерживает большое количество типов диаграмм: круговые, линейные, пузырьковые, лепестковые, диаграммы с накоплением и прочие. Имеется возможность экспорта диаграмм. Для большинства типов диаграмм поддерживается прокрутка и зуммирование. На момент написания настоящего руководства подсистема отображения диаграмм работает только в блоке Web Client для Vaadin7.
Библиотека AmCharts, на которой основана реализация подсистемы отображения диаграмм, распространяется по лицензии, позволяющей использовать ее бесплатно при сохранении ссылки на сайт библиотеки. Для своего проекта Вы можете купить лицензию на AmCharts и убрать ссылку.
Для отображения диаграмм используется компонент 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
Каждый вид диаграммы имеет свой набор атрибутов и методов, которые повторяют функционал соответствующих диаграмм библиотеки AmCharts. Документация по свойствам и методам диаграмм находится по адресу docs.amcharts.com/3/javascriptcharts.
Все атрибуты конфигурации могут иметь значение null
, вместо таких значений будут использоваться значения по умолчанию (кроме случаев, указанных в документации AmCharts).
Реализовано два варианта передачи данных в диаграмму: через интерфейс DataProvider
, или через механизм источников данных.
Интерфейс DataProvider
имеет стандартную реализацию: класс ListDataProvider
. Он содержит список экземпляров DataItem
, каждый из которых содержит набор пар ключ-значение. Экземпляр DataProvider
передается методу setDataProvider()
конфигурации диаграммы. Данный способ предоставления данных для диаграммы наиболее универсален, однако требует создания экземпляров DataProvider
и DataItem
в коде контроллера экрана.
Источник данных типа CollectionDatasource
устанавливается для компонента Chart
вызовом метода setDatasource()
. Данный вариант требует наличия сущности, представляющей данные диаграммы. Он удобен, когда такая сущность уже есть в модели данных приложения, а также когда данные диаграммы нужно отобразить и в виде таблицы.
В главе Раздел 1.4, «Пример работы с диаграммами» проиллюстрированы оба способа получения данных.
Используемые для отображения свойства сущности или значения, содержащиеся в экземпляре DataProvider
, задаются в атрибутах диаграммы, причем атрибуты различаются для разных типов диаграмм. Например для компонента chart:pieChart
необходимо задать атрибуты valueField
и titleField
.
В качестве значений могут выступать типы Integer
, Long
, Double
, String
, Boolean
, Date
.
Динамическое добавление данных в существующий график не поддерживается, возможно только полностью перерисовать график с новыми данными. Для этого необходимо воспользоваться методом repaint()
.
Имеется возможность настроить реакцию на различные типы событий. Доступны следующие типы слушателей событий:
AxisZoomListener
- масштабирование оси графика.
ChartClickListener
- щелчок по холсту.
RightClickListener
- щелчок по холсту правой клавишей мыши.
CursorPeriodSelectListener
- выбор периода отображения курсором.
CursorZoomListener
- масштабирование области графика курсором.
GraphClickListener
- щелчок по графику.
GraphItemClickListener
- щелчок по элементу графика.
LegendItemHideListener
- скрытие элемента легенды.
LegendItemShowListener
- показ элемента легенды.
LegendItemClickListener
- щелчок по элементу легенды.
SliceClickListener
- щелчок по элементу круговой диаграммы.
SliceRightClickListener
- щелчок по элементу круговой диаграммы правой клавишей мыши.
SlicePullInListener
- элемент круговой диаграммы соединён с диаграммой.
SlicePullOutListener
- элемент круговой диаграммы отсоединён от диаграммы.
ZoomListener
- масштабирование холста.
Пример использования событий проиллюстрирован в разделе Раздел 1.4.4, «Использование событий».
В данной главе мы рассмотрим применение подсистемы отображения диаграмм в приложении-примере Библиотека, который может быть загружен с помощью CUBA Studio.
Запустите CUBA Studio, перейдите в окно и загрузите проект Library.
Откройте проект Library в Studio.
Откройте окно свойств проекта Base projects включите проект charts, затем сохраните изменения. Studio предложит пересоздать скрипты Gradle - согласитесь.
-> и в спискеЗапустите build/tomcat
.
Создайте базу данных приложения, запустив
-> .Запустите IntelliJ IDEA.
-> чтобы создать проектные файлы дляПосле выполнения вышеописанных действий функциональность для отображения диаграмм подключена к приложению и готова к работе.
В данном разделе мы создадим сервис, позволяющий извлечь из базы данные для построения диаграмм.
Один из методов сервиса будет возвращать список неперсистентных сущностей, поэтому начнем с создания и регистрации класса этой сущности.
Создайте в пакете com.sample.library.entity
модуля global класс BooksByGenre
:
package com.sample.library.entity; import com.haulmont.chile.core.annotations.MetaClass; import com.haulmont.chile.core.annotations.MetaProperty; import com.haulmont.cuba.core.entity.AbstractNotPersistentEntity; @MetaClass(name = "library$BooksByGenre") public class BooksByGenre extends AbstractNotPersistentEntity { @MetaProperty private String genre; @MetaProperty private Long countOfBooks; public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; } public Long getCountOfBooks() { return countOfBooks; } public void setCountOfBooks(Long countOfBooks) { this.countOfBooks = countOfBooks; } }
Экземпляр этого класса содержит количество книг определенного жанра. Далее необходимо зарегистрировать класс сущности в файле metadata.xml
модуля global:
<metadata-model root-package="com.sample.library"> <class>com.sample.library.entity.BooksByGenre</class> </metadata-model>
Для создания интерфейса и класса сервиса можно воспользоваться CUBA Studio. Для этого откройте вкладку Services на панели навигатора и нажмите на кнопку . В открывшемся окне установите в поле Interface значение com.sample.library.service.StatisticsService
. В полях Bean и Service name будут сгенерированы подходящие значения com.sample.library.service.StatisticsServiceBean
и library_StatisticsService
соответственно. Сохраните изменения.
Откройте интерфейс сервиса StatisticsService
в IDE и объявите в нем методы получения данных из базы:
package com.sample.library.service; import com.sample.library.entity.BooksByGenre; import java.util.List; import java.util.Map; public interface StatisticsService { String NAME = "library_StatisticsService"; public List<BooksByGenre> getCountOfBooksByGenre(); public List<String> getTopPublishers(int count); public Map<Integer, Map<String, Long>> getCountOfBooksByPublisherAndYear(); }
Далее откройте класс сервиса StatisticsServiceBean
и замените его содержимое на следующий код:
package com.sample.library.service; import com.google.common.collect.Lists; import com.haulmont.cuba.core.EntityManager; import com.haulmont.cuba.core.Persistence; import com.haulmont.cuba.core.Transaction; import com.sample.library.entity.BooksByGenre; import org.springframework.stereotype.Service; import javax.inject.Inject; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service(StatisticsService.NAME) public class StatisticsServiceBean implements StatisticsService { @Inject private Persistence persistence; @Override public List<BooksByGenre> getCountOfBooksByGenre() { List<BooksByGenre> result = new ArrayList<>(); String query = "select ltype.name, count(book) " + "from library$Book book join book.literatureType ltype " + "group by ltype.name order by ltype.name"; Transaction transaction = persistence.createTransaction(); try { EntityManager em = persistence.getEntityManager(); List<Object[]> resultList = em.createQuery(query, Object[].class).getResultList(); for (Object[] row : resultList) { BooksByGenre entity = new BooksByGenre(); entity.setGenre((String) row[0]); entity.setCountOfBooks((Long) row[1]); result.add(entity); } } finally { transaction.end(); } return result; } @Override public List<String> getTopPublishers(final int count) { List<String> result = Lists.newArrayList(); String query = "select instance.bookPublication.publisher.name, count(instance) " + "from library$BookInstance instance " + "group by instance.bookPublication.publisher.name order by count(instance) desc"; Transaction transaction = persistence.createTransaction(); try { EntityManager em = persistence.getEntityManager(); List resultList = em.createQuery(query).getResultList(); for (int i = 0; i < resultList.size(); i++) { if (i == count) { break; } Object[] data = (Object[]) resultList.get(i); result.add((String) data[0]); } } finally { transaction.end(); } return result; } @Override public Map<Integer, Map<String, Long>> getCountOfBooksByPublisherAndYear() { Map<Integer, Map<String, Long>> result = new LinkedHashMap<>(); String query = "select instance.bookPublication.publisher.name, instance.bookPublication.year, count(instance) " + "from library$BookInstance instance " + "group by instance.bookPublication.year, instance.bookPublication.publisher.name " + "order by instance.bookPublication.year, instance.bookPublication.publisher.name"; Transaction transaction = persistence.createTransaction(); try { EntityManager em = persistence.getEntityManager(); List resultList = em.createQuery(query).getResultList(); for (Object row : resultList) { Object[] data = (Object[]) row; String publisher = (String) data[0]; Integer year = (Integer) data[1]; Long quantity = (Long) data[2]; if (result.get(year) == null) { result.put(year, new LinkedHashMap<String, Long>()); } result.get(year).put(publisher, quantity); } } finally { transaction.end(); } return result; } }
Метод getCountOfBooksByGenre()
возвращает количество книг каждого жанра в виде списка сущностей BooksByGenre
. Метод getTopPublishers(int count)
сортирует издателей по убыванию количества экземпляров выпущенных ими книг, находящихся в библиотеке, и возвращает первые count
издателей. Метод getCountOfBooksByPublisherAndYear()
возвращает количество книг, выпущенных издателями в определенном году.
Откройте в CUBA Studio вкладку Screens и создайте экран в модуле web. Введите значение com/sample/library/web/charts/statistics.xml
в поле Reference. В полях 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://statistic" class="com.sample.library.web.charts.statistics.Statistics" messagesPack="com.sample.library.web.charts.statistics" xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"> <dsContext> <collectionDatasource id="pieDs" class="com.sample.library.entity.BooksByGenre" refreshMode="NEVER" view="_local"/> </dsContext> <layout spacing="true"> <tabSheet height="100%" width="100%"> <tab id="pieChartTab" caption="msg://booksByGenres"> <hbox expand="pieChart" height="100%" margin="true" spacing="true" width="100%"> <chart:pieChart id="pieChart" angle="30" balloonText="[[genre]] - [[percents]]%" datasource="pieDs" depth3D="15" height="100%" titleField="genre" valueField="countOfBooks" width="100%"> <chart:exportConfig menuTop="0px"> <chart:menuItems> <chart:menu format="PNG" icon="VAADIN/resources/amcharts/images/export.png"/> </chart:menuItems> </chart:exportConfig> </chart:pieChart> <table columnControlVisible="false" height="100%" width="300px"> <columns> <column id="genre"/> <column id="countOfBooks"/> </columns> <rows datasource="pieDs"/> </table> </hbox> </tab> <tab id="stackedChartTab" caption="msg://countOfBooksByPublisherAndYear" spacing="true"> <chart:serialChart id="stackedChart" categoryField="year" height="100%" plotAreaFillAlphas="0.1" width="100%"> <chart:chartCursor/> <chart:legend markerType="TRIANGLE_RIGHT" position="TOP" valueAlign="LEFT"/> <chart:categoryAxis startOnAxis="true" title="msg://year"/> <chart:valueAxes> <chart:axis gridAlpha="0.07" position="LEFT" stackType="REGULAR" title="msg://countOfBooks"/> </chart:valueAxes> <chart:exportConfig menuTop="0px"> <chart:menuItems> <chart:menu format="PNG" icon="VAADIN/resources/amcharts/images/export.png"/> </chart:menuItems> </chart:exportConfig> </chart:serialChart> </tab> </tabSheet> </layout> </window>
В корневой элемент дескриптора экрана добавлен атрибут xmlns:chart
:
<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd" ... >
Созданный нами экран содержит панель с двумя вкладками. На первой находится круговая диаграмма, представляющая распределение книг по жанрам:
<chart:pieChart id="pieChart" angle="30" balloonText="[[genre]] - [[percents]]%" datasource="pieDs" depth3D="15" height="100%" titleField="genre" valueField="countOfBooks" width="100%"> <chart:exportConfig menuTop="0px"> <chart:menuItems> <chart:menu format="PNG" icon="VAADIN/resources/amcharts/images/export.png"/> </chart:menuItems> </chart:exportConfig> </chart:pieChart>
Даграмма получает данные из источника pieDs
, указанного в атрибуте datasource
. Для отображения названий и значений используются атрибуты genre
и countOfBooks
сущности BooksByGenre
, список экземпляров которой находится в источнике данных. С источником данных соединена также таблица, поэтому она отображает те же данные, что и диаграмма.
Компонент pieChart
содержит следующие атрибуты:
angle
- определяет угол наклона диаграммы. Может принимать значения от 0
до 90
.
balloonText
- определяет текст всплывающей подсказки при наведении на отделяемую часть диаграммы. Доступны для использования тэги [[value]]
, [[title]]
, [[persents]]
, [[description]]
, а также ключи из DataItem
, список которых хранится в экземпляре DataProvider
, либо имена атрибутов сущности в источнике данных.
depth3D
- толщина диграммы. При использовании совместно с атрибутом angle
позволяет создать эффект объема.
titleField
- ключ из набора пар, содержащихся в объектах DataItem
, список которых хранится в экземпляре DataProvider
, по которому будет взято значение для заголовка сектора в круговой диаграмме.
valueField
- ключ из набора пар, содержащихся в объектах DataItem
, список которых хранится в экземпляре DataProvider
, по которому будет взято значение для сектора.
Компонент pieChart
содержит следующие элементы:
chart:legend
- определяет легенду графика. Атрибут position
определяет положение легенды относительно диаграммы, markerType
- форму маркера, помечающего информацию о каждом секторе диаграммы.
chart:exportConfig
- добавляет возможность сохранить полученный график. Атрибуты menuTop
, menuLeft
, menuRight
, menuBottom
позволяют задать положение кнопки сохранения. В примере кнопка располагается в правом верхнем углу диаграммы.
Элемент chart:menuItems
содержит настройки сохранения. Кроме используемого в примере формата png
поддерживается сохранение в форматах jpg
, svg
и pdf
. Атрибут icon
содержит путь к изображению, которое будет использоваться в качестве кнопки импорта.
Вторая вкладка содержит график, отражающий количество книг, выпущенных в разные годы несколькими издательствами:
<chart:serialChart id="stackedChart" categoryField="year" height="100%" width="100%"> <chart:chartCursor/> <chart:legend markerType="TRIANGLE_RIGHT" position="TOP" valueAlign="LEFT"/> <chart:categoryAxis startOnAxis="true" title="msg://year"/> <chart:valueAxes> <chart:axis position="LEFT" stackType="REGULAR" title="msg://countOfBooks"/> </chart:valueAxes> <chart:exportConfig menuTop="0px"> <chart:menuItems> <chart:menu format="PNG" icon="VAADIN/resources/amcharts/images/export.png"/> </chart:menuItems> </chart:exportConfig> </chart:serialChart>
Эта диаграмма получает данные через DataProvider
, созданный в контроллере (см. ниже), поэтому атрибут datasource
не указан.
Атрибуты chart:serialChart
:
categoryField
- ключ из набора пар, содержащихся в объектах DataItem
, список которых хранится в экземпляре DataProvider
, по которому будут взяты значения для подписи оси категорий.
Элементы chart:serialChart
:
chart:chartCursor
- необязательный элемент, добавляющий на график курсор, который следует за движениями мыши и отображает всплывающую подсказку со значением графика, соответствующим точке нахождения курсора.
chart:categoryAxis
- элемент, описывающий ось категорий. Установка атрибуту startOnAxis
значения true
дает указание начинать отрисовывать график сразу от оси значений. По умолчанию этот атрибут имеет значение false
. В этом случае между осью значений и графиком имеется некоторый помежуток. Атрибут title
задает заголовок оси категорий.
chart:valueAxes
- элемент, описывающий вертикальные оси значений. В данном случае используется только одна ось, описываемая элементом chart:axis
. Атрибут position
задает положение оси значений относительно диаграммы. Установка атрибуту stackType
значения REGULAR
говорит о том, что используется диаграмма с накоплением. По умолчанию значение этого атрибута - none
, в таком случае используется диаграмма без накопления.
Перейдите на вкладку Controller и замените ее содержимое на следующий код:
package com.sample.library.web.charts.statistics; import com.haulmont.charts.gui.amcharts.model.Graph; import com.haulmont.charts.gui.amcharts.model.GraphType; import com.haulmont.charts.gui.amcharts.model.charts.SerialChart; 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 com.haulmont.cuba.gui.data.CollectionDatasource; import com.sample.library.entity.BooksByGenre; import com.sample.library.service.StatisticsService; import javax.inject.Inject; import java.util.List; import java.util.Map; import java.util.UUID; public class Statistics extends AbstractWindow { @Inject private CollectionDatasource<BooksByGenre, UUID> pieDs; @Inject private Chart stackedChart; @Inject private StatisticsService statisticsService; public void init(Map<String, Object> param) { initPieChart(); initStackedChart(); } private void initPieChart() { pieDs.refresh(); List<BooksByGenre> booksByGenreList = statisticsService.getCountOfBooksByGenre(); for (BooksByGenre booksByGenre : booksByGenreList) { pieDs.includeItem(booksByGenre); } } private void initStackedChart() { List<String> allPublishers = statisticsService.getTopPublishers(5); Map<Integer, Map<String, Long>> structuredData = statisticsService.getCountOfBooksByPublisherAndYear(); ListDataProvider dataProvider = new ListDataProvider(); for (Map.Entry<Integer, Map<String, Long>> entry : structuredData.entrySet()) { MapDataItem mapDataItem = new MapDataItem().add("year", entry.getKey()); for (String publisher : allPublishers) { if (entry.getValue().containsKey(publisher)) { mapDataItem.add(publisher, entry.getValue().get(publisher)); } else { mapDataItem.add(publisher, 0); } } dataProvider.addItem(mapDataItem); } SerialChart stackedChartConfiguration = (SerialChart) stackedChart.getConfiguration(); stackedChartConfiguration.setDataProvider(dataProvider); Graph[] graphs = new Graph[allPublishers.size()]; int i = 0; for (String publisher : allPublishers) { Graph publisherGraph = new Graph(); publisherGraph.setFillAlphas(0.6); publisherGraph.setLineAlpha(0.4); publisherGraph.setTitle(publisher); publisherGraph.setType(GraphType.LINE); publisherGraph.setValueField(publisher); publisherGraph.setBalloonText(publisher + " - [[year]] year: [[" + publisher + "]] books"); graphs[i] = publisherGraph; i++; } stackedChartConfiguration.addGraphs(graphs); } }
В методе initPieChart()
происходит заполнение источника данных pieDs
данными, полученными из сервиса. Метод refresh()
производит инициализацию источника данных. Этот метод необходимо вызвать, несмотря на атрибут refreshMode="NEVER"
, установленный в XML-дескрипторе.
В методе initStackedChart(List<String> allPublishers)
происходит установка данных в диаграмму с накоплением. Диаграммы подобного типа показывают отношение отдельных составляющих к их совокупному значению. В метод передается список издателей, выпустивших наибольшее количество экземпляров книг, находящихся в библиотеке. Для каждого издателя строится график, представляющий количество книг, выпущенных в разные годы. Графику соответствует экземпляр класса Graph
. Рассмотрим методы настройки графиков:
setFillAlphas(0.6)
- устанавливает степень непрозрачности заливки.
setLineAlpha(0.4)
- устанавливает толщину линии графика. Допустимые значения от 0
до 1
.
setTitle(publisher)
- устанавливает заголовок графика.
setType(GraphType.LINE)
- устанавливает тип отбражения данных.
setValueField(publisher)
- ключ из набора пар, содержащихся в объектах DataItem
, список которых хранится в экземпляре DataProvider
, по которому будет взято значение для графика.
setBaloonText(publisher + " - [[year]] year: [[" + publisher + "]] books")
- устанавливает значение всплывающей подсказки.
Посмотрим, как созданный нами экран выглядит в работающем приложении. Добавьте созданный экран в меню, затем пересоберите проект командой
-> и зайдите в систему. Откройте экран со статистикой.На диаграмме с накоплением проиллюстрирована работа курсора, который выводит подробную информацию о количестве книг, выпущенных издателями в выбранном году.
Проиллюстрируем использование событий. Добавим в экран, созданный в разделе Раздел 1.4.3, «Создание диаграмм», обработку отделения элемента круговой диаграммы пользователем. Откройте XML-дескриптор экрана в IDE, затем инжектируйте диаграмму:
@Inject private Chart pieChart;
Далее добавьте слушателя в методе initPieChart()
:
pieChart.addSlicePullOutListener(new Chart.SlicePullOutListener() { @Override public void onPullOut(Chart.SlicePullOutEvent event) { BooksByGenre booksByGenre = (BooksByGenre) event.getItem(); String msg = booksByGenre.getGenre() + ": " + booksByGenre.getCountOfBooks() + " book(s)"; showNotification(msg, NotificationType.HUMANIZED); } });
Для просмотра результата пересоберите проект командой
-> и зайдите в систему. Откройте экран и нажмите на один из элементов круговой диаграммы для его отделения.Подсистема отображения карт платформы CUBA основана на интеграции со сторонним поставщиком сервиса карт. На данный момент поддерживается только сервис Google Maps.
Реакция на события:
Щелчок мышью.
Перемещение и зуммирование карты.
Щелчок по маркеру и его перетаскивание.
Закрытие всплывающего окна.
Установка маркеров. Маркер может быть фиксированным или с перетаскиваемым пользователем. Маркер может обрабатывать щелчки мыши и передавать соответствующее событие в код экрана.
Отображение ломаных линий и полигонов (многоугольников).
Рисование полигонов.
Отображение тепловой карты (heat map).
Для отображения карт в проект приложения необходимо подключить базовый проект charts, как это описано для подсистемы отображения диаграмм. Кроме того, необходимо установить следующие свойства приложения блока Web Client:
Обязательный параметр - ключ доступа к API поставщика карты. В случае использования бесплатного ключа это свойство cuba.charts.map.freeApiKey
. В случае наличия коммерческой лицензии должны быть установлены следующие свойства:
cuba.charts.map.useBusinessApiKey = true
- признак использования коммерческого ключа.
cuba.charts.map.businessApiKey
- ключ доступа к API.
cuba.charts.map.clientId
- идентификатор клиента, в зависимости от поставщика может быть обязательным к заполнению. Обязателен для Google Maps.
Необязательные параметры:
cuba.charts.map.defaultZoom
- масштаб карты (zoom) по умолчанию.
cuba.charts.map.defaultLatitude
- широта центра карты по умолчанию.
cuba.charts.map.defaultLongitude
- долгота центра карты по умолчанию.
cuba.charts.map.provider
- поставщик сервиса карт, по умолчанию google
.
Пример содержимого файла web-app.properties
:
cuba.charts.map.freeApiKey = my_key cuba.charts.map.defaultZoom = 13.0 cuba.charts.map.defaultLatitude = 51.5001 cuba.charts.map.defaultLongitude = -0.1262
Для отображения карт в экранах приложения используется компонент 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.