Пример создания гео-виджета с метками

Для реализации гео-аналитики в Analytic Workspace есть виджет “Карта”. Подробнее о нем, можно прочитать в документации и в базе знаний. С помощью этого виджета есть возможность строить аналитику по регионам России через раскраску областей в зависимости от значений параметра.

Но, что, если этих возможностей недостаточно и есть запрос на более расширенный функционал? В этом случае на помощь придет html-виджет. В этой статье рассмотрим, как его можно создать.

Будем использовать библиотеку 2gis для визуализации карт. При помощи этой библиотеки можно:

  • создавать интерактивные карты, не ограничиваясь только Россией;
  • показывать на карте различные объекты (метки, попапы, геометрические объекты);
  • производить поиск на карте: определять координаты геообъектов по их названиям и названия по координатам.

Для примера построим карту Дальнего Востока и отобразим на ней точки с достопримечательностями.

Будем использовать датасет, содержащий координаты точек с достопримечательностями и названия этих достопримечательностей.

Перейдем к построению виджета.

  1. Сначала создадим виджет, добавив в область агрегатов поля с координатами и названиями достопримечательностей, и выберем для него тип “HTML”. В виджете HTML есть 3 вкладки: HTML, CSS и JS. Будем заполнять их по порядку.

  1. Вкладка HTML
  • Для подключения библиотеки добавим следующий код:

<script src="https://maps.api.2gis.ru/2.0/loader.js?pkg=full"></script>

  • Для создания контейнера, в котором будет отображаться карта, добавим блочный HTML-элемент с идентификатором id=”map”, по которому будем в дальнейшем обращаться в js-коде:
<div class="container">
    <div id="map"></div>
</div>
  1. Вкладка CSS. Добавим стилизацию виджета, для этого на вкладку CSS добавим следующий код:
@import url('https://fonts.googleapis.com/css2?family=Madimi+One&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');

.container {
    width: 100%;
    height: 100%;
    display: flex;
    gap: .5rem;
    font-family: "Roboto", sans-serif;
    background: rgb(255, 255, 255);
    background: rgba( 255, 255, 255, 0.25 );
    border-radius: 8px;
    -webkit-box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    -moz-box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    backdrop-filter: blur( 5px );
    -webkit-backdrop-filter: blur( 5px );
    border: 1px solid rgba( 255, 255, 255, 0.18 );
    padding: 1rem;
}

#map {
    border-radius: 15px;
    flex: 3;
}

.dg-attribution__copyright, .leaflet-control {
    opacity: 0;
}
  1. Вкладка JS
  • Добавим функцию initMap, которая создает карту map в html-элементе, которому в html-разметке был присвоен идентификатор id=”map”.
let map;
const initMap = (DG) => {
        map = DG.map('map', {
        center: [60.957223, 150.472756],
        zoom: 3
    });
}

В данном примере карта принимает параметра:

center - координаты центра карты в формате [широта, долгота];

zoom - коэффициент масштабирования в диапазоне от 1 до 18.

  • Далее добавим функцию initMarkers, которая создает список маркеров markers и всплывающие подсказки к ним. В функцию передаем параметр map со ссылкой на созданную карту и параметр data - с данными датасета, который используется для построения карты. В подсказках tooltipText будут отображаться названия достопримечательностей.
let markers = [];
const initMarkers = (DG, map, data) => {
    if (markers.length) {
        markers.forEach(item => item.remove())
    }

    markers.length = 0;
    for (let i = 0; i < data.length; i++) {
        const tooltipText = `${data[i].attr_name.value}`
    
        markers.push(
            DG
            .marker([Number(data[i].calc__coord_0.value), Number(data[i].calc__coord_1.value)])
            .addTo(map)
            .bindPopup(tooltipText)
        )
    }
}
  1. Объявим функцию render. В ней будем получать данные из модели, инициализировать создание карты с помощью ранее созданной функции initMap, создавать маркеры с помощью функции initMarkers. Функция render будет вызываться повторно при каждом изменении виджета, например, при установке фильтра на дашборде. Поэтому в теле функции необходимо реализовать обновление объекта настроек:
async function render() {
    let modelData = window.DATA.data;
    await window.DG;
    if (!map) initMap(window.DG);
    
    setTimeout(
        () => {
            initMarkers(window.DG, map, modelData);
        },
        800
    )
};
  1. График отрисуется после нажатия кнопки “Выполнить”. Если результат устраивает, нажимаем кнопку “Опубликовать”. И далее можем размещать виджет на информационную панель, как любой другой коробочный виджет. В частности, для него будет работать кросс-фильтрация через системные фильтры и другие виджеты.

Итоги:

В результате всех действий мы построили интерактивную html-карту, которую при необходимости можно усложнять и дорабатывать под свои задачи, используя все возможности библиотеки.

По ссылке можно посмотреть готовый пример в нашей бесплатной free-версии.

Полный код HTML
<div class="container">
    <div id="map"></div>
</div>
<script src="https://maps.api.2gis.ru/2.0/loader.js?pkg=full"></script>
Полный код CSS
@import url('https://fonts.googleapis.com/css2?family=Madimi+One&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');

.container {
    width: 100%;
    height: 100%;
    display: flex;
    gap: .5rem;
    font-family: "Roboto", sans-serif;
    background: rgb(255, 255, 255);
    background: rgba( 255, 255, 255, 0.25 );
    border-radius: 8px;
    -webkit-box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    -moz-box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    box-shadow: 4px 4px 8px 0px rgba(34, 60, 80, 0.2);
    backdrop-filter: blur( 5px );
    -webkit-backdrop-filter: blur( 5px );
    border: 1px solid rgba( 255, 255, 255, 0.18 );
    padding: 1rem;
}

#map {
    border-radius: 15px;
    flex: 3;
}

.dg-attribution__copyright, .leaflet-control {
    opacity: 0;
}
Полный код JS
let map;
const initMap = (DG) => {
        map = DG.map('map', {
        center: [60.957223, 150.472756],
        zoom: 3
    });
}

let markers = [];
const initMarkers = (DG, map, data) => {
    if (markers.length) {
        markers.forEach(item => item.remove())
    }

    markers.length = 0;
    for (let i = 0; i < data.length; i++) {
        const tooltipText = `${data[i].attr_name.value}`
    
        markers.push(
            DG
            .marker([Number(data[i].calc__coord_0.value), Number(data[i].calc__coord_1.value)])
            .addTo(map)
            .bindPopup(tooltipText)
        )
    }
}

async function render() {
    let modelData = window.DATA.data;
    await window.DG;
    if (!map) initMap(window.DG);
    
    setTimeout(
        () => {
            initMarkers(window.DG, map, modelData);
        },
        800
    )
};
1 лайк