Дьявол в деталях: интерактивная карта на OpenLayers. Часть 1.
Поделились опытом создания интерактивной карты на JS-библиотеке OpenLayers. Рассказали, как создать карту, настроить её и сделать маркеры.
2К открытий8К показов
Антон Ефременков, Senior web developer ITentika и спикер HolyJS, делится своим опытом создания интерактивной карты на основе библиотеки OpenLayers.
В конце прошлого года в нашу компанию обратился заказчик, которому необходимо было разработать систему для управления транспортной сетью города (автобусы, троллейбусы, трамваи, более экзотический транспорт – всё вместе). Это вполне себе энтерпрайз-проект, с командой разработки более 30 человек, в рамках которого надо было реализовать действительно большое количество задач. Их всех сейчас я перечислять, конечно же, не буду (это слишком долго и уныло). Остановлюсь на одной группе задач – той, что связана с отображением карты города и разными режимами работы с ней.
Что нам нужно было реализовать:
- отобразить карту города (сам город назвать не смогу – NDA).
- добавлять на карту остановки ТС (и отображать остановки по заданным координатам)
- отображать ТС в режиме реального времени
- прокладывать на карте маршрут, по которому будет идти ТС
- рисовать на карте геометрические фигуры и искать объекты, попавшие внутрь фигуры
- выделять на карте объект и видеть сопутствующую информацию
Описание проблемы
На тот момент у нас была более чем хорошая экспертиза, связанная с использованием библиотеки Leaflet для отрисовки различных карт и взаимодействия с ними. И всё было бы хорошо, но…
Наш заказчик – это одна из гос. компаний, и им довольно принципиально, какие именно сторонние программные продукты мы используем. Так получилось, что нпм-пакет лифлета можно спокойно установить и сейчас (берёте и устанавливаете, проблем нет), но если вы захотите почитать документацию по этой библиотеке, вы увидите, что жителям нашей страны этот сайт не доступен.
В ходе нашего ресёрча мы отобрали всего 2 кандидата – Mapbox и OpenLayers.
Первый кандидат обладает шикарным функционалом, но, к сожалению, платный – и это, почему-то, очень не понравилось нашему заказчику. Второй кандидат был, своего рода, тёмной лошадкой – ни у кого в компании не было опыта использования этой библиотеки, да к тому же и статистика использования этой библиотеки вызывает один большой вопрос “а что с ними не так?..”
Мы изучили примеры, размещённые на сайте OpenLayers, и они показались нам вполне убедительными. В общем, мы поверили в возможности этой библиотеки и в то, что она реально умеет работать с картой, поэтому мы решили сделать PoC с основными фичами именно на OpenLayers.
PoC
Пара слов о том стеке, что мы выбрали. На бэке у нас был .NET и PostgreSQL вместе с PostGIS и pgRouting (для хранения информации об объектах на карте). Карту города нам выдавал MapServer, саму карту импортировали с OpenStreetMap. Ну а для браузерной части мы выбрали Angular и библиотеку OpenLayers (к сожалению, никакой ангулярной обёртки для неё нет).
1. Создание и настройка карты
Если сравнивать OpenLayers с Leaflet, то сразу могу сказать, что в случае работы с OpenLayers кода приходится писать несколько больше, но не криминально.
Как видно на коде ниже, мы можем задать начальную координату для центровки карты и начальный уровень зума. Также мы можем создать любое количество доступных котролов и передать их создаваемой карте (к примеру, мы для всех карт создавали шкалу с масштабом, с помощью всего одной строчки кода).
Для отображения карты города в качестве некой “подложки” мы используем TileLayer, где прописываем url нашего MapServer’a.
Также мы можем использовать дефолтные элементы интерактивности (к примеру, перемещение по карте и зум), дополнив их некоторыми другими, при необходимости.
2. Работа с векторными слоями
Мы должны уметь отображать на карте объекты разного типа, и для этого мы решили использовать векторные слои, отображаемые поверх нашей карты-подложки.
Для каждого типа объектов мы используем свой векторный слой – для того, чтобы можно было довольно легко скрыть/отобразить все объекты нужного нам типа. При необходимости, мы можем прописать дженерик-тип для того, чтобы максимально явно указать, для чего именно предназначен слой.
3. Стилизация маркеров
Маркер – это точка на карте, имеющая вид какой-либо геометрической фигуры, или же определённой иконки. В OpenLayers у нас есть два базовых варианта стилизации таких маркеров. Для создания маркеров первого типа мы используем Style с такими примитивами как Fill и Stroke, ну а для отображения иконки мы используем Style с объектом Icon.
4. Рисуем фигуры
Зная координаты, мы можем создать объект фигуры и поместить его на нужный векторный слой. Но есть и более интересный вариант: с помощью Draw – объекта из семейства interactions – мы можем перевести карту в режим рисования геометрических фигур, задав тип нужной нам фигуры. В нашем арсенале есть как геометрические примитивы, так и более сложные фигуры (точка, прямая, ломаная линия, круг, …). А ещё мы можем рисовать правильные многоугольники, передав соответствующую геометрическую функцию.
5. Изменяем фигуры
Отдельно хочу остановиться на одной интерактивности OpenLayers, которая меня действительно приятно удивила. По техническому заданию, мы должны уметь не только рисовать геометрические фигуры, но ещё и изменять их (и сохранять новые координаты, конечно же). В библиотеке Leaflet такой функциональности “из коробки” нет, для этого приходится или использовать дополнительные плагины, или писать свою собственную реализацию. В OpenLayers же это поведение настраивается буквально тремя строчками кода – с помощью объекта Modify.
Спустя некоторое время, наш PoC был готов, и результат более чем убедил нас в том, что OpenLayers подходит для наших целей, и все поставленные задачи мы сможем реализовать.
Заранее оговорюсь, что и дизайнер, и большая часть разработчиков нашей команды из Питера, поэтому наши макеты и тестовые координаты представлены на карте именно этого славного города =)
Что ж, мы решили перейти к следующему этапу. И, конечно же, встретили первые проблемы.
Проблемы лейблов
Согласно ТЗ, мы должны уметь отображать маркеры транспортных средств, и они должны были выглядеть так, как показано на картинке слева. Но после первой итерации мы получили совсем другую картинку. Ту, что справа.
Нам не удалось ни скруглить рамку, ни наложить тень, ни выставить нормальные отступы… Почему? Потому что OpenLayers рисуют все объектны на canvas’e, а там наши возможности очень и очень ограничены, поскольку большинство CSS-свойств попросту отсутствует.
Что же мы, в итоге, можем задать? Список невелик:
- Fill и Stroke (примитивы для заливки цветом и отображения рамки)
- Image (непосредственно, иконка маркера на карте)
- Text (подпись маркера, которой, в том числе, можно навесить свои Fill и Stroke)
С самого начала мы и планировали построить наши маркеры именно вокруг объекта Text. Что ж, не вышло =)
Дизайн этой части системы был уже согласован с заказчиком, поэтому нам пришлось искать решение задачи, без каких-либо надежд обойтись “облегчённой” версией маркеров.
В OpenLayers есть возможность “собрать” визуальное оформление точки на карте из нескольких частей – просто задав массив стилей, применяемых к этой точке. За это мы и зацепились. Теперь у нас несколько стилей, и в совокупности они образуют маркер транспортного средства:
Конечно, я не могу сказать, что это самое элегантное решение, и, исходя из способа получения backWidth (ширины нашей подложки, с фоном и тенью), решение выглядит довольно хрупким. Но у него есть два существенных плюса:
- Оно работает! (что уже не маловажно)
- Нам понятен порядок слоёв, и мы можем им управлять, если это понадобится.
Также к минусам можно отнести некоторые “тормозюльки” при довольно большом количестве ТС на карте. Но об этом чуть позже…)
Так или иначе, мы решили поставленную задачу и добились намеченной цели.
А теперь, дорогой читатель, вопрос к тебе: как думаешь, что могло пойти не так? Да-да, всё верно. У нас случился Его Величество Редизайн. Да, даже на этой стадии проекта. Войдя во вкус, наш заказчик захотел внести “несколько“ изменений в макет. Как видно на картинке ниже, сами маркеры теперь разноцветные (в зависимости от типа ТС), а также внутри такого маркера отображается сопутствующая информация (о статусе ТС, к примеру):
Это вылилось в ещё более сложный и хрупкий способ собрать все стили. На картинке ниже можно увидеть, что у нас добавилось логики, ну и увеличилось количество слоёв: :
Тем не менее, задача была решена, и мы достигли очень важного этапа жизни нашего проекта: мы окончательно убедились в том, что выбранная библиотека нам подходит, и все поставленные задачи могут быть реализованы с её помощью. Ну а первые результаты можно увидеть на этом видео:
Мы показали это демо заказчику, и это действительно был успех! В приподнятом настроении мы взялись за реализацию следующего модуля, и… конечно же, столкнулись с новыми сложностями, обусловленными использованием OpenLayers.
Но об этом – во второй части.
Вторая часть https://tproger.ru/articles/dyavol-v-detalyah-interaktivnaya-karta-na-openlayers-chast-2
2К открытий8К показов