1. Привязка карты к данным

В этой главе вы создадите:

  • Перечисление LocationType.

  • Сущность Location с атрибутом типа GeoPoint.

  • CRUD-экраны с картой на экране Location.detail.

Создание сущности Location и экранов

Для начала мы создадим перечисление LocationType, состоящее из двух значений: Office и Coworking. Подробные инструкции по созданию перечислений можно найти в разделе Использование перечислений Руководства.

enumeration location type

Затем создайте сущность Location. Подробные инструкции по созданию сущностей можно найти в разделе Простой CRUD Руководства.

Установите флажок Traits → Versioned в диалоговом окне New JPA Entity.

new location entity dialog

Сущность Location имеет следующие атрибуты:

  • city типа String. Установите флажок Mandatory.

  • address типа String. Установите флажок Mandatory.

  • type типа перечисления LocationType.

  • building типа GeoPoint. Установите флажок Mandatory:

    geo point attribute

Определите атрибут address для генерации имени экземпляра.

Создайте CRUD-экраны для сущности Location. Подробные шаги по генерации экранов деталей и списка сущности можно найти в разделе Создание CRUD-экранов Руководства.

Следуйте предлагаемым значениям на каждом шаге мастера создания экранов.

Studio автоматически сгенерирует два экрана: Location.list и Location.detail, и откроет их соответствующий исходный код.

Добавление карты на экран

Найдите location-detail-view.xml в окне Jmix и дважды щелкните по нему. Появится конструктор экранов:

location detail view

Вы заметите, что для отображения атрибута building используется компонент textField.

Если вы хотите отобразить карту на экране, вам следует добавить UI-компонент geoMap в XML-дескриптор.

Поместите курсор после элемента formLayout.

Затем нажмите Add Component на панели действий, найдите элемент GeoMap и дважды щелкните по нему.

adding map

Новый элемент geoMap будет добавлен под элементом formLayout как на панели структуры Jmix UI, так и в XML. Настройте атрибуты id, height и width, как показано ниже.

<maps:geoMap id="map" height="100%" width="100%"/>

Добавление тайлового слоя с OsmSource

Мы собираемся использовать растровый слой в качестве базового фонового слоя карты. Для этого мы будем использовать OsmSource - предопределенный источник для отображения тайлов OpenStreetMap.

Выберите map на панели структуры Jmix UI или в XML-дескрипторе экрана, затем нажмите кнопку Add на панели инспектора. В выпадающем списке выберите Layers → TileLayer.

add tile layer

Выберите maps:tile на панели структуры Jmix UI или в XML-дескрипторе экрана, а затем нажмите кнопку Add на панели инспектора. В выпадающем списке выберите OsmSource.

add osmsource

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

Нажмите кнопку Debug (start debugger) на главной панели инструментов.

Перед запуском приложения Studio сравнивает модель данных проекта со схемой базы данных. Когда вы создали новую сущность, Studio автоматически сгенерировала changelog Liquibase для отражения соответствующих изменений в базе данных (таких как создание таблицы LOCATION):

changelog location

Нажмите Save and run.

Studio выполнит changelog в вашей базе данных, после чего соберет и запустит приложение:

run app

После запуска приложения перейдите по адресу http://localhost:8080 в вашем веб-браузере и войдите в приложение с учетными данными admin/admin.

Выберите пункт Locations в меню Application. Вы увидите экран Location.list. Нажмите Create. Откроется экран Location.detail:

location detail1

Настройка отображения карты

По умолчанию компонент geoMap отображает карту мира с начальным географическим центром в (0,0).

Мы используем отображение карты (map view) для настройки местоположения, отображаемого на карте.

Выберите map на панели структуры Jmix UI или в XML-дескрипторе экрана, а затем нажмите кнопку Add на панели инспектора. В выпадающем списке выберите MapView.

add map view

Укажите атрибут centerY:

<maps:mapView centerY="51.0"/>

Выберите maps:mapView на панели структуры Jmix UI или в XML-дескрипторе экрана, а затем нажмите кнопку Add на панели инспектора. В выпадающем списке выберите Extent и настройте атрибуты minX, minY, maxX и maxY, как указано ниже.

<maps:extent minX="-15.0"
             minY="30.0"
             maxX="40.0"
             maxY="60.0"/>

Экстент (extent) ограничивает область просмотра, то есть ничего за пределами этого экстента не будет видно на карте.

Запустите приложение, чтобы увидеть новую функцию в действии.

Добавление векторного слоя с DataVectorSource

Для работы с геообъектами мы добавим векторный слой.

Перейдите к maps:layers на панели структуры Jmix UI или в XML-дескрипторе экрана и нажмите кнопку Add на панели инспектора. В выпадающем списке выберите VectorLayer. Укажите атрибут id следующим образом: id="vectorLayer".

Мы будем использовать DataVectorSource, который поддерживает привязку данных к контейнерам данных Jmix.

Выберите vectorLayer на панели структуры Jmix UI или в XML-дескрипторе экрана, а затем нажмите кнопку Add на панели инспектора. В выпадающем списке выберите DataVectorSource. Настройте для него атрибут dataContainer:

<maps:vector id="vectorLayer">
    <maps:dataVectorSource id="dataVectorSource"
                           dataContainer="locationDc"
                           property="building"/>
</maps:vector>

Давайте посмотрим: полное описание нашей карты выглядит следующим образом:

<maps:geoMap id="map" height="100%" width="100%">
    <maps:layers>
        <maps:tile>
            <maps:osmSource/>
        </maps:tile>
        <maps:vector id="vectorLayer">
            <maps:dataVectorSource id="dataVectorSource"
                                   dataContainer="locationDc"
                                   property="building"/>
        </maps:vector>
    </maps:layers>
    <maps:mapView centerY="51.0">
        <maps:extent minX="-15.0"
                     minY="30.0"
                     maxX="40.0"
                     maxY="60.0"/>
    </maps:mapView>
</maps:geoMap>

Сохранение координат в атрибут Building

Когда менеджер по персоналу создает местоположение, он щелкает на точке на карте, которая затем сохраняется в сущности Location как Point с координатами.

Давайте добавим ClickEvent для нашей карты.

Выберите map на панели структуры Jmix UI или в XML-дескрипторе экрана, перейдите на вкладку Handlers и создайте метод-обработчик события MapClickEvent:

add click event

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

public class LocationDetailView extends StandardDetailView<Location> {
    protected GeometryFactory geometryFactory = GeometryUtils.getGeometryFactory(); (1)

    @Subscribe("map")
    public void onMapMapClick(final MapClickEvent event) {
        Point point = geometryFactory.createPoint(event.getCoordinate()); (2)
        Location location = getEditedEntity(); (3)
        location.setBuilding(point);
    }
}
1 Для получения GeometryFactory используйте GeometryUtils - специализированный служебный класс с функциями, связанными с библиотекой JTS.
2 Преобразуйте координаты, полученные из event, в объект Point, используя метод GeometryFactory.
3 Используйте метод getEditedEntity() базового класса StandardDetailView для получения редактируемой сущности Location.

Запустите приложение. Выберите пункт Locations в меню Application, чтобы перейти к экрану Location.list. Нажмите Create, чтобы открыть экран Location.detail. Заполните поля City, Address и Type соответствующей информацией. Щелкните на карте в указанном месте адреса. Значение для поля Building будет автоматически заполнено на основе координат выбранной точки на карте. Сохраните местоположение, нажав ОК.

location detail2