Для реализации гео-аналитики в Analytic Workspace есть виджет “Карта”. Подробнее о нем, можно прочитать в документации и в базе знаний. С помощью этого виджета есть возможность строить аналитику по регионам России через раскраску областей в зависимости от значений параметра.
Но, что, если этих возможностей недостаточно и есть запрос на более расширенный функционал? В этом случае на помощь придет html-виджет. В этой статье рассмотрим, как его можно создать.
Будем использовать библиотеку 2gis для визуализации карт. При помощи этой библиотеки можно:
- создавать интерактивные карты, не ограничиваясь только Россией;
- показывать на карте различные объекты (метки, попапы, геометрические объекты);
- производить поиск на карте: определять координаты геообъектов по их названиям и названия по координатам.
Для примера построим карту Дальнего Востока и отобразим на ней точки с достопримечательностями.
Будем использовать датасет, содержащий координаты точек с достопримечательностями и названия этих достопримечательностей.
Перейдем к построению виджета.
- Сначала создадим виджет, добавив в область агрегатов поля с координатами и названиями достопримечательностей, и выберем для него тип “HTML”. В виджете HTML есть 3 вкладки: HTML, CSS и JS. Будем заполнять их по порядку.
- Вкладка 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>
- Вкладка 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;
}
- Вкладка 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)
)
}
}
- Объявим функцию
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
)
};
- График отрисуется после нажатия кнопки “Выполнить”. Если результат устраивает, нажимаем кнопку “Опубликовать”. И далее можем размещать виджет на информационную панель, как любой другой коробочный виджет. В частности, для него будет работать кросс-фильтрация через системные фильтры и другие виджеты.
Итоги:
В результате всех действий мы построили интерактивную 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
)
};