Google Maps

Архитектура Leaflet построена вокруг слоёв (layers), где базовая карта чаще всего подключается через тайловые серверы. Подключение сторонних картографических провайдеров сводится к подмене источника тайлов, сохранению системы координат Web Mercator и корректной обработке уровней масштабирования.

Работа с внешними картографическими платформами требует понимания разницы между:

  • Tile-based картами (растровые или векторные тайлы)
  • JavaScript API карт (рендеринг через собственный движок)
  • Hybrid-подходами, где API оборачивается в слой Leaflet

Google Maps относится ко второй категории, что создаёт ограничения при прямом использовании внутри Leaflet.


Ограничения использования Google Maps как слоя

Google Maps API не предоставляет прямого доступа к тайловым слоям в формате, совместимом с L.TileLayer. Основные ограничения:

  • отсутствие официального tile endpoint для сторонних библиотек
  • юридические ограничения на использование тайлов вне Google Maps API
  • обязательное использование API-ключа и соблюдение quota
  • контроль отрисовки через собственный JS-движок

По этой причине прямое подключение через стандартный слой Leaflet технически и юридически некорректно.


Подход через Google Maps JavaScript API

Интеграция возможна через создание синхронизированного контейнера, где Google Maps выступает как фон, а Leaflet — как слой управления геометрией.

Пример архитектуры:

  • Google Maps создаётся как отдельный объект google.maps.Map
  • Leaflet используется для оверлеев (markers, polygons)
  • координаты синхронизируются вручную
const gmap = new google.maps.Map(document.getElementById("gmap"), {
  center: { lat: 55.75, lng: 37.62 },
  zoom: 10,
  disableDefaultUI: true
});

const map = L.map("leaflet", {
  center: [55.75, 37.62],
  zoom: 10
});

map.on("move", () => {
  const center = map.getCenter();
  gmap.setCenter({ lat: center.lat, lng: center.lng });
  gmap.setZoom(map.getZoom());
});

Такой подход используется при необходимости сохранить функциональность Google-рендера и добавить гибкость Leaflet.


Использование Google-тайлов через GridLayer

В экосистеме Leaflet существуют сторонние плагины, эмулирующие tile layer Google Maps через API-запросы. Один из распространённых подходов — googleMutant.

Он создаёт слой, который визуально повторяет Google Maps, но управляется Leaflet.

const map = L.map("map").setView([55.75, 37.62], 10);

L.gridLayer.googleMutant({
  type: "roadmap"
}).addTo(map);

Поддерживаемые режимы:

  • roadmap
  • satellite
  • terrain
  • hybrid

API-ключ и ограничения

При использовании Google Maps требуется обязательная авторизация через API key.

Ключ:

  • привязывается к проекту в Google Cloud
  • ограничивается по доменам
  • имеет квоты на загрузку карт

Пример подключения API:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>

Важно учитывать:

  • превышение квоты приводит к блокировке рендера
  • без биллинга часть функций недоступна
  • ключ нельзя использовать публично без ограничений

Синхронизация координатных систем

И Leaflet, и Google Maps используют Web Mercator (EPSG:3857), что упрощает взаимодействие, но не устраняет различия:

  • различие в пиксельной интерпретации zoom level
  • отличия в проекционных округлениях
  • различия в поведении при wrap-around (longitude repetition)

При синхронизации необходимо учитывать:

  • преобразование LatLng ↔︎ Pixel
  • выравнивание zoom scale
  • компенсацию смещения при pan-операциях

Overlay-модель Leaflet поверх Google Maps

Часто используется схема, где Google Maps полностью скрыт под Leaflet-оверлеями.

Компоненты:

  • Google Maps: визуальный фон
  • Leaflet: интерактивные элементы
  • DOM-синхронизация через прозрачный контейнер
#gmap {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

#leaflet {
  position: absolute;
  top: 0;
  left: 0;
  background: transparent;
}

Маркеры и геометрия в гибридной модели

Leaflet обеспечивает работу с:

  • маркерами
  • полигонами
  • кругами
  • GeoJSON-слоями

Пример добавления слоя поверх Google Maps:

L.marker([55.75, 37.62]).addTo(map);

L.polygon([
  [55.76, 37.60],
  [55.76, 37.64],
  [55.74, 37.64]
]).addTo(map);

Эти элементы не зависят от источника базовой карты.


Производительность при комбинировании систем

Совмещение Google Maps и Leaflet приводит к увеличению нагрузки:

  • двойной рендеринг DOM/WebGL
  • дублирование событий pointer/mouse
  • рост потребления памяти
  • конфликт таймингов анимации pan/zoom

Оптимизация включает:

  • отключение ненужных контролов Google Maps
  • минимизацию Leaflet-слоёв
  • использование requestAnimationFrame для синхронизации
  • отключение инерции прокрутки

Альтернативные стратегии интеграции

Вместо использования Google Maps внутри Leaflet часто применяются альтернативные tile-провайдеры:

  • OpenStreetMap tile servers
  • Mapbox tiles
  • self-hosted raster tiles
  • vector tiles через WebGL

Leaflet изначально лучше адаптирован к tile-based архитектуре, поэтому интеграция сторонних API обычно реализуется через слой абстракции, а не через прямую интеграцию движков.


Событийная модель при гибридном использовании

События Leaflet:

  • move
  • zoom
  • click
  • drag

События Google Maps:

  • bounds_changed
  • center_changed
  • zoom_changed

При синхронизации требуется ручное связывание:

map.on("moveend", () => {
  const c = map.getCenter();
  gmap.setCenter({ lat: c.lat, lng: c.lng });
});

Проблема циклических обновлений решается флагами блокировки:

let syncing = false;

map.on("move", () => {
  if (syncing) return;
  syncing = true;
  gmap.setCenter(map.getCenter());
  syncing = false;
});