- PVSM.RU - https://www.pvsm.ru -
Вам когда-нибудь нужно было отображать крупные массивы данных с привязкой к карте? Мне на работе понадобилось отображать заказы сгруппированные по широте и долготе. И не просто статической таблицей, а динамической, с разной детализацией для разного приближения карты.
К сожалению (или к счастью?), готовых решений я не нашёл. Google Карты позволяют накладывать маркеры и фигуры на карты, но эти способы представляют слишком мало информации. С Яндекс картами оказалось не лучше. Но Карты Гугл имеют механизм пользовательских наложений с HTML-содержанием. И для инкапсуляции этой работы с картами и наложениями я создал JavaScript библиотеку GMapsTable. Возможно, кому-нибудь она окажется интересной или полезной. Рабочий пример. [1]
Чтобы не возникло путаницы, параметр zoom будем называть приближением карты, а scale — масштабом. Первый относится к Google Maps API, а второй к описываемой библиотеке.
Итак, что у нас есть? Какой-нибудь источник данных (например, сервер с базой данных, обрабатывающий и посылающий данные в формате JSON) и веб-страничка с JavaScript, которая запрашивает данные и визуализирует их на Картах Гугл.
Данные имеют аккумулятивную природу (в моём случае каждой области можно поставить в соответствие: число заказов, клиентов и среднюю сумму). Поэтому данные могут и должны отображаться с разной детализацией для разных приближений.
Основное содержание HTML страницы для GMapsTable:
..в <head>:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY"></script>
<script src="http://www.aivanf.com/static/gmt/gmapstable.js"></script>
..в <body>:
<div id="map"></div>
GMapsTable позволяет абстрагироваться от взаимодействия с GoogleMaps API. Вам нужно лишь предоставить подходящий объект с данными. Время перейти к JavaScript'y! Чтобы использовать GMapsTable, нужно получить объект DataContainer для Вашего div'a карты:
// Аргумент: ID div'а
// и словарь параметров GoogleMaps,
// это не обязательно
var container = new DataContainer("map", {
zoom: 9,
center: {lat: 55.7558, lng: 37.6173},
mapTypeId: 'roadmap'
});
Затем нужно передать две функции:
container.dataLoader = function (scale, borders) {
... вызвать container.processData(some_data);
}
container.scaler = function (zoom) {
... return какое-нибудь число;
}
Но что именно писать внутри функций?.. Для начала разберёмся, как работает GMapsTable.
DataContainer
занимается отображением Ваших данных и заботится о том, когда оно должно быть обновлено. В самом начале и когда изменяются приближение и границы "камеры", он пробует использовать сохранённые данные, а если их нет, то вызывает функцию dataLoader
. Вам нужно сгенерировать объект с данными и передать его функции DataContainer.processData. Структура объекта должна быть такая:
data: {
minLat: float,
difLat: float,
minLon: float,
difLon: float,
scale: int,
table: [
[value, value, ...],
[value, value, ...],
...
],
tocache: boolean
}
Значением (value
) может быть число, строка или любой объект, если вы укажите собственную функцию форматирования ячейки таблицы. Масштаб (sale
) это целое число, говорящее, на сколько частей должны делиться единицы широты и долготы. Параметр tocache
указывает, должны ли данные для текущего масштаба быть сохранены и более не запрашиваться.
data: {
minLat: 55.0,
difLat: 2.0,
minLon: 37.0,
difLon: 1.0,
scale: 2,
table: [
[1, 3, 0, 1],
[0, 1, 2, 0]
],
tocache: true
}
Здесь данные покрывают область от 55.0, 37.0 до 57.0, 38.0 и делят каждую единицу широты и долготы на 2 части (получается, одна клетка широты-долготы делится на 4 части). Также здесь указано, что для данного масштаба это полные данные, и они должны быть сохранены для использования в дальнейшем.
Приближение (zoom
) это параметр Google Maps API, целое число между 1 (карта мира) и 22 (улица). Запрашивать и хранить данные для каждой единицы приближения неудобно и нецелесообразно, поэтому GMapsTable переводит их в масштаб (scale
) — число, указывающее, на сколько частей нужно делить единицу широты и долготы.
Чтобы отображение при изменении масштаба было моментальным, GMapsTable хранит наборы данных для некоторых (либо всех) масштабов. Например, у меня была база данных с координатами почти со всей России — около 42 тысяч ячеек для масштаба 10 (500 КБ, довольно легко хранится и обрабатывается у меня в десктопном браузере) и 17 миллионов для масштаба 200 (несколько МБ, вызывает значительные подвисания). Поэтому сервер оценивает число ячеек всех данных, и если их немного, отправляет данные из всей БД, иначе только для запрошенного региона. Получается такой алгоритм:
Границы (bounds
) — это объект JavaScript с полями minlat, maxlat, minlon, maxlon
— текущими границами Google Maps и хорошим отступом про запас.
В Вашей реализации dataLoader
Вы можете смело игнорировать аргументы, если нет нужды использовать разную детализацию для разных масштабов или если Ваши данные не покрывают такой большой регион. Просто передайте данные и их границы по широте и долготе и scale
, на сколько разбиваете единицы широты-долготы. Но для полноты картины я предлагаю такое поведение функции dataLoader
(или сервера, к которому она обращается):
Вы можете указать такие параметры для DataContainer:
1) scaler(zoom)
— переводит приближение из GoogleMaps в масштаб для GMapsTable. Оба целые числа.
2) dataLoader(scale, borders)
— вызывается, когда нужны новые данные. Должен передать объект данных в DataContainer.processData(data)
.
Параметр borders
это объект JavaScript с полями minlat, maxlat, minlon, maxlon
— текущими границами Google Maps и хорошим отступом про запас.
3) tableBeforeInit(map, table, data)
— вызывается перед тем, как таблица начинает заполняться ячейками. Аргумент map
это объект Google Maps, table
это HTML элемент таблицы, а data
— предоставленный Вами объект данных для текущего масштаба.
4) cellFormatter(td, val)
— вызывается для заполнения ячейки. td
это HTML element, ячейка таблицы. val
это данные из Вашего объекта данных.
5) boundsChangedListener(zoom)
— вызывается, когда изменяются границы Google Maps.
6) minZoomLevel
, maxZoomLevel
— переменные для минимального и максимального приближения карты. Целые числа между 1 (карта мира) и 22 (улица).
Для успешной работы DataContainer необходимы только первые две функции.
Полный и хорошо прокомментированный пример использования: HTML-страничка [1] и JS-код [2].
А также есть GMapsTable в GitHub [3].
Автор: AivanF
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/257879
Ссылки в тексте:
[1] Рабочий пример.: http://www.aivanf.com/static/gmt/example.html
[2] JS-код: http://www.aivanf.com/static/gmt/example.js
[3] GMapsTable в GitHub: https://github.com/AivanF/GMapsTable
[4] Источник: https://habrahabr.ru/post/330920/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.