Тема
Переход с Leaflet
Leaflet бесплатен, но карта без тайлов пустая. tile.openstreetmap.org нельзя использовать в продакшене, зарубежные сервисы тайлов из РФ почти не оплатить, а Яндекс не продаёт подложку отдельно. EvaMaps — библиотека и тайлы по РФ и СНГ одной поставкой: подключили скрипт, и карта работает. До 5 000 загрузок карты в месяц бесплатно, без ключа и регистрации.
Имена методов взяты у Leaflet (setView, flyTo, fitBounds, addTo, on/off), поэтому перенос простой карты занимает минуты. Главное отличие — порядок координат.
Тайлы EvaMaps не подключаются в Leaflet
Тайлы работают только через SDK @evamaps/sdk, <eva-map> и iframe. Оставить Leaflet и поменять только адрес тайлов не получится — переносится код карты целиком.
Было и стало
html
<!-- Leaflet -->
<link rel="stylesheet" href="leaflet.css">
<script src="leaflet.js"></script>
<script>
const map = L.map('map').setView([55.7558, 37.6173], 13);
L.tileLayer('https://…/{z}/{x}/{y}.png', { attribution: '…' }).addTo(map);
L.marker([55.7558, 37.6173]).addTo(map).bindPopup('Наш офис');
</script>html
<!-- EvaMaps -->
<link rel="stylesheet" href="https://evamaps.ru/sdk/1/evamaps.css">
<script src="https://evamaps.ru/sdk/1/evamaps.js"></script>
<script>
const map = EvaMaps.create('map', { center: [37.6173, 55.7558], zoom: 13 });
EvaMaps.marker([37.6173, 55.7558])
.setPopup(EvaMaps.popup().setText('Наш офис'))
.addTo(map);
</script>Подложка, атрибуция, кнопки зума и линейка уже внутри create().
Координаты: [lng, lat]
У Leaflet [lat, lng] — широта первой. У EvaMaps, как в GeoJSON, [lng, lat] — долгота первой. Москва: Leaflet [55.7558, 37.6173], EvaMaps [37.6173, 55.7558].
Это самая частая ошибка при переходе: точка улетает в Индийский океан или в Сомали. Если координаты приходят из своей базы в порядке [lat, lng], разверните их один раз на входе: ([lat, lng]) => [lng, lat].
Зато GeoJSON читается без разворота — его порядок совпадает с нашим. Шкала зума та же, что у Leaflet и OSM: зум 13 там и здесь показывает одно и то же.
Таблица соответствия
| Leaflet | EvaMaps (скрипт evamaps.js) | Заметки |
|---|---|---|
L.map(id).setView(latlng, z) | EvaMaps.create(id, { center, zoom }) | Тайлы и атрибуция подключаются сами |
L.tileLayer(url).addTo(map) | не нужно | Тема подложки: theme: 'light' | 'dark' | 'gray', на лету map.setTheme('dark') |
map.setView, setZoom, zoomIn, zoomOut, panTo, panBy, flyTo, fitBounds | те же имена | flyTo(center, zoom, { duration }) |
map.getCenter(), getZoom(), getBounds() | те же имена | Возвращают [lng, lat] и LngLatBounds |
map.on('click', e => e.latlng) | map.on('click', e => e.lngLat) | e.lngLat — [lng, lat] |
map.remove() | map.destroy() | Снимает слушатели, DOM, таймеры, загрузки |
L.marker(latlng, { draggable }) | EvaMaps.marker(lngLat, { draggable }) | Плюс color, label (подпись рядом с меткой), title |
L.icon({ iconUrl, iconSize, iconAnchor }) | опция icon: { url, size, anchor } | Или icon: HTMLElement |
marker.bindPopup('<b>Офис</b>') | marker.setPopup(EvaMaps.popup().setText('Офис')) | Строки HTML не принимаются — см. ниже |
L.popup().setLatLng(ll).setContent(…).openOn(map) | EvaMaps.popup().setLngLat(ll).setText(…).openOn(map) | |
L.polyline, L.polygon, L.circle(ll, { radius }) | EvaMaps.polyline, EvaMaps.polygon, EvaMaps.circle(ll, радиусМетры, {…}) | Радиус круга — вторым аргументом |
L.geoJSON(data) | EvaMaps.geoJSON(data) | |
плагин Leaflet.markercluster | EvaMaps.cluster(points) | Встроено, плагин не нужен |
L.layerGroup([…]) | EvaMaps.layerGroup([…]) | |
L.control.layers(base, overlays) | EvaMaps.layersControl(base, overlays) | Темы подложки — EvaMaps.themeLayers() |
L.tileLayer.wms(url, {…}) | EvaMaps.wmsLayer({ url, layers, … }) | Чужой источник — на условиях его владельца |
L.imageOverlay(url, bounds) | EvaMaps.imageOverlay(url, bounds) | План этажа, схема территории |
scrollWheelZoom: false для встраивания | cooperative: true | Колесо с Ctrl/⌘, на телефоне двумя пальцами |
Из npm — тот же набор классами: import { create, Marker, Popup } from '@evamaps/sdk'. Полный справочник — SDK.
Балуны: текст вместо HTML
bindPopup('<b>…</b>') в Leaflet вставляет строку как HTML — так на сайты попадает XSS из данных меток. В EvaMaps балун принимает:
setText(text)— только текст, теги выводятся как есть;setLink(href)— ссылка, толькоhttp(s);setContent(node)— своя разметка, но DOM-узлом, который вы создали сами.
Чего в EvaMaps нет
Честно, чтобы не было сюрпризов после переноса:
- Плагинов Leaflet. Кластеры, GeoJSON, переключатель слоёв, WMS встроены. Остальное (рисование, тепловые карты, маршруты) — пока нет.
- Чужой подложки вместо нашей. Свои XYZ-тайлы и WMS можно добавить слоем поверх, но основа — тайлы EvaMaps.
- Retina-тайлов — в планах.
- Маршрутов и поиска адресов. Геокодер в разработке.
Остальные ограничения — на отдельной странице. Сравнение с MapLibre, Яндексом и 2ГИС — здесь.