В Google Maps JavaScript API географические координаты (широта и долгота) не используются напрямую для отрисовки объектов на экране. Перед отображением они преобразуются в промежуточную систему координат, основанную на проекции Меркатора, а затем — в пиксельные координаты текущего viewport’а карты.
Базовая идея заключается в разделении трёх уровней представления данных:
Каждый из этих уровней имеет собственную систему отсчёта и масштабирования, зависящий от zoom и размера тайлов.
В основе Google Maps лежит Web Mercator Projection (EPSG:3857). Она преобразует сферические координаты в плоскость, сохраняя углы, но искажая площади.
Преобразование широты выполняется через логарифмическую функцию:
y = (( + ))
где φ — широта в радианах.
Долгота преобразуется линейно:
x =
где λ — долгота в радианах.
После нормализации координаты приводятся к диапазону [0, 1], что позволяет работать с ними независимо от конкретного масштаба карты.
В Google Maps вся поверхность Земли на zoom level 0 представлена как один квадратный тайл 256×256 пикселей.
При увеличении масштаба используется экспоненциальное разбиение:
N = 2^z
где z — уровень масштабирования (zoom), а N — количество тайлов по оси X и Y.
Мировые координаты вычисляются как:
x = ^z
y = ^z
Эта система координат называется world coordinate space и является промежуточным слоем между географией и экраном.
Экранные координаты зависят не только от масштаба, но и от текущего центра карты.
Если обозначить:
то экранная координата вычисляется как:
screen = worldPoint - centerPoint +
Таким образом, центр карты всегда фиксируется в середине viewport’а, а все остальные точки смещаются относительно него.
В Google Maps JavaScript API доступ к преобразованиям координат
осуществляется через объект MapCanvasProjection, который
предоставляется внутри OverlayView.
Ключевые методы:
fromLatLngToPoint(latLng)fromPointToLatLng(point)getWorldWidth()Пример получения пиксельных координат:
class CustomOverlay extends google.maps.OverlayView {
onAdd() {}
draw() {
const projection = this.getProjection();
const point = projection.fromLatLngToPoint(
new google.maps.LatLng(55.751244, 37.618423)
);
const scale = Math.pow(2, this.getMap().getZoom());
const pixelX = point.x * scale;
const pixelY = point.y * scale;
const div = this.div;
div.style.left = pixelX + "px";
div.style.top = pixelY + "px";
}
onRemove() {}
}
Здесь важно учитывать, что fromLatLngToPoint возвращает
координаты в нормализованном пространстве, а масштабирование выполняется
отдельно через 2^zoom.
Каждый уровень масштабирования удваивает детализацию карты. Это означает, что одна и та же географическая точка будет иметь разные пиксельные координаты в зависимости от zoom.
Формально:
P_{zoom} = P_{base} ^z
где:
Это объясняет, почему любые кастомные оверлеи должны пересчитываться при изменении масштаба карты.
При перемещении карты происходит изменение центра viewport’а, что приводит к перерасчёту всех экранных координат.
Если обозначить:
то итоговая позиция:
P = (W - C) +
Любое смещение карты напрямую влияет на вычисление позиции всех объектов, включая маркеры, полигоны и кастомные DOM-слои.
В современных версиях API используется следующая последовательность:
const projection = overlay.getProjection();
const worldPoint = projection.fromLatLngToPoint(
new google.maps.LatLng(lat, lng)
);
const scale = Math.pow(2, map.getZoom());
const pixel = {
x: worldPoint.x * scale,
y: worldPoint.y * scale
};
При этом важно учитывать, что getProjection() становится
доступным только после вызова onAdd или draw
внутри OverlayView.
Обратная операция используется для обработки кликов и взаимодействия с картой.
const worldPoint = {
x: pixelX / scale,
y: pixelY / scale
};
const latLng = projection.fromPointToLatLng(worldPoint);
Это позволяет интерпретировать координаты мыши как географические значения, что критично для интерактивных слоёв.
При высоких zoom-уровнях начинают проявляться ограничения точности чисел с плавающей запятой. Это особенно заметно при работе с:
Для уменьшения ошибок применяется локальная система координат относительно центра карты, а не абсолютные мировые координаты.
DOM-оверлеи позволяют напрямую управлять пиксельным позиционированием без привязки к стандартным маркерам.
class HtmlOverlay extends google.maps.OverlayView {
constructor(position, element) {
super();
this.position = position;
this.element = element;
}
draw() {
const projection = this.getProjection();
const scale = Math.pow(2, this.getMap().getZoom());
const point = projection.fromLatLngToDivPixel(this.position);
this.element.style.transform =
`translate(${point.x}px, ${point.y}px)`;
}
}
Метод fromLatLngToDivPixel учитывает текущий viewport и
возвращает готовые координаты для DOM.
Каждый тайл размером 256×256 пикселей является базовой единицей отображения. При zoom z карта представляет собой сетку:
= 2^z
Таким образом, вся система координат фактически представляет собой огромную декартову сетку, в которой каждый пиксель может быть однозначно сопоставлен с географической точкой через обратную проекцию Меркатора.
Проецирование координат на пиксели используется во всех нестандартных слоях:
В таких системах производительность напрямую зависит от частоты пересчёта projection и оптимизации переходов между world space и screen space.
Для уменьшения нагрузки при частых изменениях карты применяется:
worldPointzoom_changed и
center_changedЭто позволяет избежать постоянного вызова тригонометрических функций и логарифмов, которые являются вычислительно дорогими при массовом рендеринге объектов.