Связывание панорам в Google Maps JavaScript API реализуется через механизм графа переходов между точками обзора Street View, где каждая панорама рассматривается как узел, а возможные переходы — как ориентированные рёбра, описывающие направление движения пользователя по виртуальному пространству.
В основе Street View лежит структура, в которой каждая панорама имеет
уникальный идентификатор pano, а также набор доступных
переходов к соседним точкам. Эти переходы формируют навигационную сеть,
позволяющую пользователю перемещаться по пространству без явного задания
маршрута.
Ключевой элемент модели — объект, описывающий связи:
pano соседних панорамПри стандартной работе Google Maps API этот граф формируется автоматически, однако при использовании кастомных панорам разработчик полностью контролирует структуру связей.
В объекте StreetViewPanoramaData поле links
описывает возможные направления перехода:
{
location: {
pano: "pano_1",
description: "Точка обзора 1"
},
links: [
{
description: "К панораме 2",
pano: "pano_2",
heading: 90
},
{
description: "К панораме 3",
pano: "pano_3",
heading: 180
}
],
copyright: "Custom Data",
imageDate: "2024-01"
}
Каждый элемент массива links задаёт:
pano — идентификатор целевой панорамы heading — направление поворота камеры для корректного визуального перехода description — текстовое описание перехода
Именно через этот массив формируется интерактивная навигация, отображаемая в интерфейсе стрелками и кликабельными зонами.
Для управления связями между панорамами используется функция
setPanoProvider, позволяющая динамически возвращать данные
для конкретного pano.
const panorama = new google.maps.StreetViewPanorama(
document.getElementById("pano"),
{
pano: "pano_1",
visible: true
}
);
const panoramaData = {
pano_1: {
location: { pano: "pano_1", description: "Стартовая точка" },
links: [
{ pano: "pano_2", heading: 90, description: "Вперёд" }
]
},
pano_2: {
location: { pano: "pano_2", description: "Вторая точка" },
links: [
{ pano: "pano_1", heading: 270, description: "Назад" },
{ pano: "pano_3", heading: 180, description: "Дальше" }
]
}
};
panorama.setPanoProvider((pano) => {
return panoramaData[pano] || null;
});
Такой подход позволяет строить полностью контролируемые графы навигации, включая нелинейные структуры, циклы и ветвления.
Связи между панорамами не обязаны быть статическими. Они могут формироваться на основе:
Пример динамической генерации связей:
function getLinksForPano(panoId) {
const neighbors = computeNeighbors(panoId);
return neighbors.map(neighbor => ({
pano: neighbor.id,
heading: neighbor.bearing,
description: `Переход к ${neighbor.name}`
}));
}
При таком подходе граф панорам фактически строится «на лету», что позволяет реализовывать интерактивные туры и адаптивные навигационные системы.
При клике по ссылке переход инициируется автоматически, но его можно
перехватить через событие pano_changed и управлять логикой
переключения:
panorama.addListener("pano_changed", () => {
const currentPano = panorama.getPano();
console.log("Текущая панорама:", currentPano);
});
Для принудительного перехода используется метод
setPano:
panorama.setPano("pano_3");
Это позволяет реализовать сценарии, где навигация не ограничивается пользовательским выбором, а управляется внешней логикой приложения.
Параметр heading играет ключевую роль в визуальной
согласованности переходов. Он определяет ориентацию камеры при переходе
к новой панораме.
Корректное значение heading обеспечивает:
Расчёт направления может выполняться на основе координат:
function calculateHeading(lat1, lng1, lat2, lng2) {
const toRad = (v) => (v * Math.PI) / 180;
const dLng = toRad(lng2 - lng1);
const y = Math.sin(dLng) * Math.cos(toRad(lat2));
const x =
Math.cos(toRad(lat1)) * Math.sin(toRad(lat2)) -
Math.sin(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.cos(dLng);
const brng = Math.atan2(y, x);
return ((brng * 180) / Math.PI + 360) % 360;
}
При увеличении количества панорам система превращается в ориентированный граф, где:
pano)links)Такой граф может быть:
Связывание панорам позволяет реализовывать нестандартные модели поведения:
Интерактивные туры Переходы задаются автором тура и ограничивают свободу перемещения.
Гео-игры Каждый переход может зависеть от условий, например, от выполненных задач.
Виртуальные экскурсии Связи формируются по заранее заданному маршруту с контролируемой логикой движения.
Если панорама не содержит links, навигация становится
конечной. В таких случаях часто используется:
if (!data.links || data.links.length === 0) {
console.log("Дальнейшие переходы отсутствуют");
}
Связи могут расширяться метаданными, которые не используются API напрямую, но применяются в логике приложения:
links: [
{
pano: "pano_5",
heading: 120,
description: "В музей",
type: "indoor",
locked: false
}
]
Такая структура позволяет строить сложные сценарии с ограничениями доступа и условной навигацией.
При работе с несколькими экземплярами Street View возможна синхронизация переходов:
primaryPanorama.addListener("pano_changed", () => {
const pano = primaryPanorama.getPano();
secondaryPanorama.setPano(pano);
});
Это используется в интерфейсах сравнения или многоканального просмотра, где важно сохранять одинаковую точку обзора.
При проектировании связей важно учитывать:
Грамотно спроектированный граф обеспечивает предсказуемое и логичное перемещение пользователя внутри виртуального пространства.