1. Прежде чем начать
В этом руководстве рассказывается, как добавлять и стилизовать 3D-маркеры в вашем приложении. Вы также узнаете, как анимировать свое приложение, летая в определенные места и вокруг них.
Это руководство основано на концепциях, рассмотренных в первой лаборатории кода . Если вы еще этого не сделали, пройдите эту лабораторную работу по коду, чтобы получить фундаментальные знания, необходимые для этого приложения.
Что ты будешь делать
Это приложение предоставляет обзор основных офисов Google в Европе. Пользователи могут выбрать офис, летать вокруг него и исследовать его, а затем уменьшать масштаб, чтобы вернуться к общему виду. Эти функции, обычно встречающиеся в приложениях для путешествий и исследований, предлагают пользователям более захватывающий опыт.
В этой лаборатории кода вы создадите 3D-веб-приложение, которое выполняет следующие действия:
- Динамически загружает Maps JavaScript API.
- Добавляет 3D-маркеры на карту.
- Стилизует маркеры с использованием SVG.
- Добавляет возможность летать к маркерам и вокруг них.
- Абстрагирует местоположения из кода в массив.
Что вы узнаете
- Как работают маркеры.
- Как стилизовать маркеры.
- Как анимация работает со встроенными функциями.
- Расположение камер вместо точечных для лучшего кадрирования.
- Полезные советы по захвату параметров камеры для лучшего кадрирования объектов.
Предварительные условия
Для завершения этой лаборатории кода вам необходимо ознакомиться с представленными здесь элементами. Если вы уже знакомы с работой с платформой Google Maps, переходите к Codelab.
Необходимые продукты платформы Google Карт
В этой лаборатории кода вы будете использовать следующие продукты платформы Google Maps:
- API JavaScript Карт
Другие требования для этой лаборатории кода
Для выполнения этой лаборатории кода вам потребуются следующие учетные записи, службы и инструменты:
- Аккаунт Google Cloud с включенной оплатой.
- Ключ API платформы Google Карт с включенным API JavaScript Карт.
- Базовые знания JavaScript, HTML и CSS.
- Текстовый редактор или IDE по вашему выбору, чтобы сохранить изменения в файле для просмотра.
- Веб-браузер для просмотра файла во время работы.
2. Настройте
Настройте платформу Google Карт
Если у вас еще нет учетной записи Google Cloud Platform и проекта с включенной оплатой, ознакомьтесь с руководством по началу работы с платформой Google Maps, чтобы создать учетную запись для выставления счетов и проект.
- В Cloud Console щелкните раскрывающееся меню проекта и выберите проект, который вы хотите использовать для этой лаборатории кода.
- Включите API и SDK платформы Google Maps, необходимые для этой лаборатории кода, в Google Cloud Marketplace . Для этого выполните действия, описанные в этом видео или этой документации .
- Создайте ключ API на странице «Учетные данные» Cloud Console. Вы можете выполнить действия, описанные в этом видео или в этой документации . Для всех запросов к платформе Google Maps требуется ключ API.
3. Простой глобус
Чтобы начать создание приложения, важно установить базовую настройку. Это создаст «голубой мраморный» вид Земли в ее наиболее существенной форме, как показано на изображении:
Добавьте код стартовой страницы
Чтобы добавить глобус на сайт, вам необходимо добавить на свою страницу следующий код. При этом будет добавлен раздел для загрузчика API Javascript Карт и функция инициализации, которая создает элемент Map 3D на странице, на которой вы добавите код для маркеров.
Обязательно добавьте на страницу свой собственный ключ (созданный в разделе «Настройка »), иначе 3D-элемент невозможно будет инициализировать.
<!DOCTYPE html>
<html>
<head>
<title>Step 1 - Simple Globe</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");
map3D = new Map3DElement({
mode: MapMode.HYBRID,
});
document.body.append(map3D);
}
init();
</script>
</body>
</html>
После этого вы готовы приступить к обрамлению интересующего вас места, что вы и сделаете на следующем шаге.
4. Первый вид кадра
Теперь, когда вы создали карту с видом глобуса, вашим следующим шагом будет определение правильного начального местоположения. Это позволяет вашему пользователю получить мгновенный обзор того, где он работает.
Хотя этот пример посвящен офисам Google в Европе, вы можете применить этот подход к любому месту по всему миру — от всей страны до отдельного городского квартала. Скорость и гибкость продукта позволяют масштабировать ваше приложение от глобального до локального с минимальными изменениями кода.
Вы начнете с первоначального кадрирования, чтобы 3D-карта выглядела следующим образом:
Наведите камеру на Европу
Чтобы получить изображение, как показано, вам необходимо правильно его кадрировать, как если бы вы размещали камеру в пространстве, смотрящую на это место сверху вниз.
Для этого можно использовать ряд параметров элемента управления картой для установки сведений о камере. Посмотреть, как взаимодействуют параметры в «реальном» мире, можно на схеме. В частности, есть центральная точка, на которую смотрит камера, и расстояние от того места, куда вы смотрите ( диапазон ). Вам также необходимо установить наклон перспективы камеры (иначе вы будете смотреть прямо на Землю).
Последняя настройка, заголовок , определяет направление камеры. Оно измеряется как смещение от строгого севера. Эти значения применяются к элементу 3D-карты как объекту для настройки начального отображения. Вы можете увидеть это в коде с обновленным конструктором 3D-элементов.
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.HYBRID
});
Захват параметров камеры
Создание изображения на 3D-карте требует точного размещения камеры, чего может быть сложно добиться с помощью одного лишь кода. Чтобы упростить этот процесс, воспользуйтесь этим полезным приемом: добавьте на свою страницу функцию, которая фиксирует параметры камеры, когда вы нажимаете на нужный вид. Параметры будут выведены на консоль и готовы к копированию в настройки камеры вашего объекта.
Вы можете найти код, который, возможно, захотите использовать позже, он добавлен в образец на этой странице, хотя его не будет в образце последующих страниц, поскольку он не нужен для лаборатории кода, но об этом следует помнить, если вы хотите создавать более захватывающие демонстрации за счет лучшего позиционирования камеры.
map3D.addEventListener('gmp-click', (event) => {
console.log("camera: { center: { lat: " + map3D.center.lat + ", lng : " + map3D.center.lng + ", altitude: " + map3D.center.altitude + " }, range: " + map3D.range + ", tilt: " + map3D.tilt + " ,heading: " + map3D.heading + ", }");
console.log("{ lat: " + event.position.lat + ", lng : " + event.position.lng + ", altitude: " + event.position.altitude + " }");
// Stop the camera animation when the map is clicked.
map3D.stopCameraAnimation();
});
Обратите внимание на использование функции stopCameraAnimation
. Если страница увеличивается или вращается по орбите, полезно иметь возможность остановить анимацию, чтобы можно было зафиксировать местоположение на дисплее в этот момент. Этот фрагмент кода позволяет вам это сделать. Более подробная информация находится в документации к stopCameraAnimation
.
Пример вывода по клику, как показано в консоли.
camera: { center: { lat: 51.39870122020001, lng : -0.08573187165829443, altitude: 51.66845062662254 }, range: 716.4743880553578, tilt: 50.5766672986501 ,heading: -1.048260134782318, }
step2.html:40 { lat: 51.398158351120536, lng : -0.08561139388593597, altitude: 51.860469133677626 }
Текст камеры можно использовать в качестве входных данных JSON для различных объектов в 3D-картах. Второй выходной результат — это фактическое местоположение точки, в которой произошел щелчок, что также полезно для создания точек или чего-либо еще для позиционирования маркеров.
Теперь, когда страница оформлена правильно, вы можете добавлять маркеры. Перейдите к следующему шагу, чтобы узнать, как это сделать.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
<!DOCTYPE html>
<html>
<head>
<title>Step 2 - Europe View</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.HYBRID,
});
map3D.addEventListener('gmp-click', (event) => {
console.log("camera: { center: { lat: " + map3D.center.lat + ", lng : " + map3D.center.lng + ", altitude: " + map3D.center.altitude + " }, range: " + map3D.range + ", tilt: " + map3D.tilt + " ,heading: " + map3D.heading + ", }");
console.log("{ lat: " + event.position.lat + ", lng : " + event.position.lng + ", altitude: " + event.position.altitude + " }");
map3D.stopCameraAnimation();
});
document.body.append(map3D);
}
init();
</script>
</body>
</html>
5. Простой маркер
В этом разделе вы узнаете, как добавить свой первый маркер. Сначала вы узнаете общие сведения о маркерах.
3D-карты поддерживают создание двух разных классов маркеров: класса Marker3DElement и класса Marker3DInteractiveElement , выбор которых определяется тем, хотите ли вы включить щелчки маркера или нет. В остальном они по сути одинаковы, поэтому сначала вы создадите Marker3DElement , а затем «обновите» его до Marker3DInteractiveElement на будущих этапах.
Полное решение для этого шага можно увидеть здесь:
Добавьте немного высоты вашим маркерам
Первое, что нужно знать, это то, что маркеры, как и все остальное на 3D-карте, трехмерные. Это означает, что местоположение может иметь высоту (высоту), и эта высота может быть репрезентативной в виде положения относительно уровня моря, земли, сетки или набора для привязки к земле и игнорирования местоположения по высоте. Более подробную информацию можно посмотреть в разделе «Константы высоты» документации AltitudeMode .
Вы также можете указать, будет ли маркер выдавливаться или нет, используя значение выдавливания . Это определит, будет ли маркер иметь небольшую линию, направленную к земле, чтобы показать фактическое положение относительно высоты, что полезно для выбора точек на земле. Вы можете увидеть пример этого на примере местоположения Google в Великобритании. Оба вытянуты, и их положение установлено на абсолютную высоту. Первый на 75 метрах, второй на 125 метрах.
Высота 75 метров. | Высота 125 метров. |
Скрыть или показать маркеры с окклюзией и столкновением
Хотя в нашей демонстрации это может быть неважно, поскольку позиции расположены довольно далеко друг от друга, для тех маркеров, которые могут перекрываться друг с другом или могут находиться за зданиями, вы можете контролировать то, что с ними происходит, с помощью значений CollisionBehavior или DrawWhenOccluded .
Для поведения при столкновении у вас есть следующие параметры:
-
REQUIRED
: (по умолчанию) Всегда отображать маркер независимо от столкновения. -
OPTIONAL_AND_HIDES_LOWER_PRIORITY
Отображать маркер, только если он не перекрывается с другими маркерами. Если два маркера этого типа перекрываются, отображается тот, у которогоzIndex
выше. Если они имеют одинаковыйzIndex
, отображается тот, у которого вертикальная позиция экрана ниже. -
REQUIRED_AND_HIDES_OPTIONAL
Всегда отображать маркер независимо от коллизии и скрывать любыеOPTIONAL_AND_HIDES_LOWER_PRIORITY
маркеры или метки, которые могут перекрываться с маркером.
Различия в том, как отображаются маркеры в зависимости от определенного поведения при столкновении, показаны на изображениях. Все маркеры отображаются при настройке REQUIRED
, но если вы используете REQUIRED_AND_HIDES_OPTIONAL
, тогда в этом случае будут отображаться маркеры, расположенные ниже на экране (вы можете поиграть с zIndex, чтобы другие маркеры отображались поверх, если хотите).
НЕОБХОДИМЫЙ | REQUIRED_AND_HIDES_OPTIONAL |
Для окклюзии вы можете выбрать, будут ли маркеры отображаться за зданиями или нет. Это показано на следующем изображении. Если drawsWhenOccluded
установлено значение true, маркеры отображаются слегка затемненными при рисовании за зданиями, а если установлено значение false, маркеры скрываются, когда они находятся за зданием. Более подробную информацию можно найти в следующей таблице:
| |
Как уже упоминалось, маркеры, скрытые столкновением, будут отображаться затемненными, если разрешено рисование перекрытых маркеров. На изображении вы можете увидеть некоторые маркеры, скрытые зданиями, а некоторые — другими маркерами.
Дополнительные сведения см. в примере поведения при столкновении на 2D-карте.
Очистить холст
Теперь пришло время создать ваш первый маркер. Чтобы пользователь мог сосредоточиться на маркерах, вы можете отключить метки по умолчанию на 3D-карте.
Установите значение mode
элемента 3D-карты на SATELLITE
.
Дополнительную информацию см. в режиме .
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE
});
В результате получается следующая 3D-карта:
Добавьте первый маркер
Теперь, когда холст чистый, вы можете добавить первый маркер. Ключевые параметры включают положение и метку.
Чтобы добавить маркер, установите положение маркера. Вы также можете включить метку, которая появится над маркером, и другие элементы, как описано в документации Marker3DElement .
Чтобы добавить наш маркер, добавьте следующий код после строки, которая скрывает метки по умолчанию, как показано:
const marker = new Marker3DElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
map3D.append(marker);
После создания маркера добавьте его на 3D-карту с помощью метода добавления. Помните, что маркеры хранятся как массив дочерних элементов на трехмерной карте. Чтобы изменить маркер, вам потребуется доступ к нему через этот массив.
Убедитесь, что Marker3DElement
загружен из API JavaScript Карт, добавив его в список библиотек при загрузке API.
const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
Теперь при загрузке страницы вся Европа будет видна маркером над лондонским офисом. Как показано на анимации, вы можете вручную увеличить масштаб, чтобы увидеть маркер над созданным местоположением.
Теперь, когда вы загрузили свой первый маркер, следующим шагом будет улучшение его внешнего вида.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
<!DOCTYPE html>
<html>
<head>
<title>Step 3 - Simple Marker</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
map3D.append(marker);
document.body.append(map3D);
}
init();
</script>
</body>
</html>
6. SVG-маркер
На этом этапе вы улучшите внешний вид маркера, изменив его, добавив к маркеру флаг, обозначающий страну, в которой он находится. Давайте посмотрим, как это делается, и для этого вам нужно познакомиться с PinElement .
В итоге у вас будет новый вид, как показано:
Базовая настройка с помощью PinElement
Одним из элементов, общих для маркеров в API Javascript, будь то 2D или 3D-карты, является PinElement . Добавляя Marker3DElement к Map3DElement , вы добавляете PinElement к Marker3DElement как дочерний элемент этого элемента.
PinElement содержит возможность на базовом уровне изменять обычный маркер, чтобы установить цвет его границы, цвет внутренней точки (или глифа) и цвет фона. Вы можете увидеть это на изображении, показывающем 2D-маркер.
Вы также можете установить размер маркера через элемент, задав его значение масштаба (>1 — больше обычного, а <1 — меньше в пропорции).
Вы также можете заменить глиф изображением или файлом svg, если хотите придать ему более индивидуальный вид, но при этом сохранить стандартный вид булавки карты PinElement.
За пределами PinElements
На этом этапе вы собираетесь обновить стандартный PinElement
, добавив флаг svg и другие цвета, но также полезно знать, что вы можете полностью изменить внешний вид маркера, чтобы он даже не выглядел как пин-код на карте. В маркере вы также можете вставлять новую графику с помощью шаблонов, таких как HTMLImageElement и SVGElement. Более подробную информацию об этом можно узнать в документации Marker3DElement-Slots .
Чтобы увидеть, что в полной мере возможно, взгляните на следующие примеры, в которых показаны примеры стилизации маркеров с использованием различных методов.
Маркеры с базовой настройкой через PinElement, см. примеры . | Маркеры со сложной настройкой через шаблон, через SVG и изображения, см. примеры . |
Добавьте PinElement
Чтобы изменить внешний вид маркера, первое, что необходимо сделать, — это убедиться, что на страницу добавлена библиотека PinElement. Это делается путем добавления следующей строки кода после импорта библиотеки maps3d
:
const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
Теперь элемент загружен, и на PinElement можно ссылаться и создавать. Посмотрите на код, добавьте его между местом создания маркера и добавьте маркер на 3D-карту.
const marker = new Marker3DElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const markerPin = new PinElement({
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
});
marker.append(markerPin);
map3D.append(marker);
Поскольку вы не просто загружаете базовый вывод, необходимо сделать ряд вещей, помимо простой настройки PinElement с соответствующим цветом фона и масштабом.
Сначала необходимо создать ссылку на изображение svg для значка флага, в данном случае «Юнион Джек». Вы можете получить их из такой коллекции, как эта, на https://flagicons.lipis.dev/ .
Если у вас есть значок, вы можете поместить его в место, где сайт сможет найти его. В этом случае вы можете либо жестко запрограммировать местоположение изображения, либо использовать текущее местоположение сайта в качестве заглушки каталога, как показано здесь с базовой переменной. Затем вы можете связать это с местоположением на сервере с правым флагом, который здесь находится в разделе «/images/gb.svg» .
Это создает PinElement, который выглядит так, как показано:
Итак, как только вы поместите флаг в нужное место и поместите код в нужное место, у вас должна получиться 3D-карта, которая выглядит следующим образом:
Теперь наш маркер полностью оформлен, его также можно изменить, чтобы сделать его кликабельным, чтобы добавить интерактивность. Это будет сделано на следующем этапе.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
Также не забывайте, что вам нужно будет получить файл флага svg (или png по вашему выбору!) и сохранить его в каталоге, который может быть найден на вашей странице (здесь он хранится в папке изображений).
<!DOCTYPE html>
<html>
<head>
<title>Step 4 - SVG Marker</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const markerPin = new PinElement({
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
});
marker.append(markerPin);
map3D.append(marker);
document.body.append(map3D);
}
init();
</script>
</body>
</html>
7. Интерактивный маркер
На последнем этапе на страницу был добавлен маркер, но он не только хорошо выглядит, но и мало что дает, и вам все равно придется взаимодействовать с 3D-картой таким же образом. Следующим шагом будет добавление возможности делать что-либо с маркером при щелчке по нему, что позволит маркеру реагировать на взаимодействие с пользователем.
Чтобы добавить эту функцию, вам необходимо преобразовать Marker3DElement в Marker3DInteractiveElement. В конце у вас будет похожая страница, но внутри которой при щелчке маркера теперь появится всплывающее предупреждение, и оно будет выглядеть примерно так:
Сначала измените класс маркера
Чтобы добавить интерактивность маркеру, вам необходимо убедиться, что он использует правильный класс. Marker3DInteractiveElement — это то, что необходимо, но поскольку он является расширением Marker3DElement, вам не нужно ничего делать, кроме загрузки нового класса и изменения имени класса в конструкторе.
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DInteractiveElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
Во-вторых, добавьте событие щелчка к маркеру.
Затем добавьте к маркеру событие щелчка, чтобы обрабатывать взаимодействие с пользователем и отвечать на него. Во фрагменте вы можете видеть, что событие щелчка добавлено к маркеру. В этом случае выдается предупреждение и появляется текст, отображающий метку из маркера, полученного из цели запущенного события, что позволяет нам получить доступ к свойству метки. Добавьте следующий код в свое приложение сразу после создания маркера.
marker.addEventListener('gmp-click', (event) => {
alert('You clicked on : ' + event.target.label);
event.stopPropagation();
});
Примечание. Событие stopPropagation используется, чтобы гарантировать, что любые другие прослушиватели кликов в стеке активируются на базовых объектах, таких как основной холст 3D-карты.
Итак, теперь, когда вы запустите приложение, вы должны получить следующий результат:
Благодаря возможности делать что-либо при нажатии на маркер теперь можно добавить анимацию на страницу на следующем этапе.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
<!DOCTYPE html>
<html>
<head>
<title>Step 5 - Interactive Marker</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DInteractiveElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
alert('You clicked on : ' + event.target.label);
event.stopPropagation();
});
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const markerPin = new PinElement({
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
});
marker.append(markerPin);
map3D.append(marker);
document.body.append(map3D);
}
init();
</script>
</body>
</html>
8. Лететь в
На этом этапе вы будете использовать возможность щелкнуть маркер добавленной анимации, чтобы перелететь к ее местоположению. Вы можете увидеть это в действии здесь.
Анимация с помощью FlyCameraTo
Чтобы добавить это на страницу, вы будете использовать метод FlyCameraTo 3D-карт, где камера анимирует между местоположением камеры, в котором вы находитесь, и местоположением камеры, которое вы хотите просмотреть, интерполируя между ними и анимируя полет в 3D-карте.
При использовании FlyCameraTo вам необходимо указать FlyToAnimationOptions , который имеет два свойства: endCamera , которое представляет собой местоположение, на которое камера должна указывать в конце анимации, и длительностьMillis , которая представляет собой продолжительность в миллисекундах, необходимую для выполнения перехода.
В примере настройте камеру так, чтобы она смотрела на здание, которое находится в положении маркера, с наклоном 65 градусов, дальностью 500 метров и направлением на север с курсом 0 градусов. Установите время анимации 12500 миллисекунд (12,5 с).
Замените текущее событие оповещения на странице фрагментом FlyCameraTo:
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 12500,
});
event.stopPropagation();
});
Вот и все, теперь вы сможете обновить страницу, щелкнуть маркер и перелететь в Google UK, как показано на анимации:
На этом этапе вы добавили кликабельный маркер, который перемещает камеру к месту расположения маркера. На следующем шаге вы добавите возможность управлять камерой вокруг точки, чтобы она вращалась вокруг этого местоположения.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
<!DOCTYPE html>
<html>
<head>
<title>Step 6 - Zoom To</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DInteractiveElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 12500,
});
event.stopPropagation();
});
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const markerPin = new PinElement({
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
});
marker.append(markerPin);
map3D.append(marker);
document.body.append(map3D);
}
init();
</script>
</body>
</html>
9. Летайте вокруг
Последний элемент нашей анимации — использование метода FlyCameraAround для анимации орбиты вокруг здания. В конце концов у вас будет анимация, которая подлетит к зданию, а затем облетит его, как показано на анимации. Это, вероятно, немного быстро для реального примера, но полезно показать, как работает действие, не слишком длинное, вы можете поиграть с таймингами, пока не получите значение, которое вам подходит.
Давайте полетим вокруг!
Метод FlyCameraAround аналогичен функции FlyCameraTo в том, что он принимает ряд параметров в качестве входных данных, которые определяют, какое место следует обходить, а также параметры камеры и время в миллисекундах, необходимое для ее выхода на орбиту. Наконец, вы также можете указать количество вращений, которые могут произойти за указанное время. Вы можете увидеть все параметры здесь, в FlyAroundAnimationOptions.
Но подождите одну минуту!
В анимации вы можете увидеть, как анимация летит к локации, а затем облетает ее, образуя цепочку анимаций. Для этого вы используете событие gmp-animationend 3D Maps, чтобы убедиться, что текущая анимация завершилась, прежде чем запускать следующую. Эта анимация должна происходить только один раз, прежде чем остановиться.
Взгляните на код, вставьте его после кода, добавленного в предыдущем разделе.
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 5000,
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraAround({
camera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 5000,
rounds: 1
});
}, { once: true });
event.stopPropagation();
});
Добавление возможности прослушивания события gmp-animationend позволяет ему затем вызывать событие FlyCameraAround . Установка той же начальной точки, которая использовалась для конечной камеры метода полета, означает плавный переход (чтобы не вызывать резких движений в новом месте). Опять же, параметр periodMillis настроен для контроля продолжительности времени, необходимого для анимации. В этом случае метод также принимает еще один параметр rounds
, которому присваивается значение 1.
Это означает, что камера будет вращаться вокруг точки один раз в 5 секунд. Вы можете поэкспериментировать с этими значениями, чтобы найти число, которое подойдет именно вам.
На этом этапе анимация завершится, но поскольку вы не хотите, чтобы событие gmp-animationend сработало снова с этим фрагментом кода, это приведет к бесконечному перемещению по орбите. Чтобы избежать этого, для прослушивателя можно установить параметр Once равный true . Это означает, что событие будет удалено после завершения, что позволяет избежать бесконечного цикла.
Как только это будет добавлено, вы сможете запустить решение и увидеть, как анимация теперь облетает маркер в конце, как показано на анимации:
На этом этапе вы добавили маркер, по которому можно щелкнуть, затем камера перемещается к месту маркера и вокруг него. На следующем этапе пришло время начать добавлять больше точек и позволить нам перемещаться между ними.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
<!DOCTYPE html>
<html>
<head>
<title>Step 7 - Zoom Around</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
const europeCamera = {
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
};
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
...europeCamera,
mode: MapMode.SATELLITE,
});
const marker = new Marker3DInteractiveElement({
position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
label: 'Google UK',
altitudeMode: 'ABSOLUTE',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 5000,
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraAround({
camera: {
center: marker.position,
tilt: 65,
range: 500,
heading: 0,
},
durationMillis: 5000,
rounds: 1
});
}, { once: true });
event.stopPropagation();
});
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const markerPin = new PinElement({
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
});
marker.append(markerPin);
map3D.append(marker);
document.body.append(map3D);
}
init();
</script>
</body>
</html>
10. Париж!
Хотя Лондон — замечательный город, на странице он кажется немного одиноким, поэтому давайте начнем добавлять несколько новых мест, начиная с Парижа. Для этого можно использовать массив для хранения всех деталей, специфичных для местоположения, а затем использовать его в качестве входных данных для функций и переменных, которые устанавливают параметры отображения маркера, а также полет к местоположениям камер и вокруг них. Которое, как уже упоминалось, может отличаться от местоположения маркерной точки, например, для того, чтобы лучше сфотографировать здание камерой.
Массив местоположений
Чтобы не задавать жестко код всех деталей о конкретном месте, таких как камера просмотра, точка маркера и параметры отображения, вы можете использовать небольшой массив объектов json для хранения этих данных. Затем это можно применить при создании и использовании маркеров в приложении. Вы можете увидеть этот пример во фрагменте кода, где создается переменная с именем officeLocations
для хранения массива.
Добавьте следующий код непосредственно перед функцией init. Также обратите внимание, что базовая переменная была вынесена за пределы функции init, чтобы ее можно было применять ко всем офисам.
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const europeCamera = {
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
};
const officeLocations = [
{
"name": "Google France",
"camera": {
"center": { lat: 48.877276, lng: 2.329978, altitude: 48 },
"range": 178,
"tilt": 57.48,
"heading": -17,
},
"point": { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
"pin": {
"background": 'white',
"glyph": new URL(base + '/images/fr.svg'),
"scale": 1.0,
},
},
{
"name": "Google UK",
"camera": {
"center": { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
"range": 500,
"tilt": 56.21672368296945,
"heading": -31.15763027564165,
},
"point": { lat: 51.5332, lng: -0.1260, altitude: 75 },
"pin": {
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
},
}]
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
Каждое местоположение офиса имеет следующие свойства:
- name : название локации.
- Камера: начальный вид для просмотра места для полета туда и обратно.
- точка: место для размещения маркера.
- pin: сведения о цвете маркера и свойствах глифа.
Другой ракурс
Здесь вы можете заметить, что для Великобритании центр камеры и точка маркера одинаковы (кроме высоты), тогда как для Франции камера и точка различаются. Это связано с тем, что для местоположения во Франции маркер должен находиться в другом месте, чем исходный вид с камеры, что дает лучший обзор всего здания при полете туда и вокруг, чем тот, который мог бы быть получен, если бы использовалась точка маркера.
Вернитесь в Европу
Одна из функций наличия большего количества точек заключается в том, что добавляется требование иметь возможность перемещаться между ними. Вы можете использовать раскрывающийся список, чтобы разрешить выбор, но в этом примере камера каждый раз будет возвращаться к европейскому виду, чтобы пользователь мог выбрать другое местоположение.
Для этого исходный вид необходимо сохранить в переменной, которую можно использовать для сброса настроек камеры на весь вид Европы. В этом примере добавьте новую переменную с именем europeCamera
, чтобы сохранить ее для дальнейшего использования.
Обновите функцию инициализации
Первое изменение, которое вам нужно сделать, — это использовать объект europeCamera
в качестве входных данных при создании Map3DElement
.
Второе редактирование, которое вам нужно сделать, — это обернуть раздел создания маркера в цикл, чтобы обновить его с помощью параметров, хранящихся в переменных, вы можете увидеть их в показанном коде:
- office.point : местоположение маркера.
- office.name: название офиса, используемое для метки маркера.
- office.camera: исходное местоположение камеры.
- office.pin: параметры PinElement для различий в отображении.
Также не забудьте получить SVG-файл или изображение французского флага!
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
...europeCamera,
mode: MapMode.SATELLITE,
});
officeLocations.forEach(office => {
const marker = new Marker3DInteractiveElement({
position: office.point,
label: office.name,
altitudeMode: 'ABSOLUTE',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: office.camera,
durationMillis: 5000,
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraAround({
camera: office.camera,
durationMillis: 5000,
rounds: 1
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraTo({
endCamera: europeCamera,
durationMillis: 5000,
});
}, { once: true });
}, { once: true });
event.stopPropagation();
});
const markerPin = new PinElement(office.pin);
marker.append(markerPin);
map3D.append(marker);
});
document.body.append(map3D);
}
Обратите внимание, что после анимации flyCameraAround
добавляется вторая функция gmp-animationend для обработки возврата к европейскому виду с использованием сохраненной переменной europeCamera
. Как показано в анимации:
На этом этапе приложение было расширено и теперь имеет две локации и возможность летать между ними с помощью анимации и массива локаций. На следующем этапе в массив будут добавлены остальные офисные локации.
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
Также не забывайте, что вам нужно будет получить файл svgs (или png-файл по вашему выбору) с флагом и сохранить его в каталоге, который может быть найден на вашей странице (здесь он хранится в папке изображений).
<!DOCTYPE html>
<html>
<head>
<title>Step 8 - Paris!</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const europeCamera = {
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
};
const officeLocations = [
{
"name": "Google France",
"camera": {
"center": { lat: 48.877276, lng: 2.329978, altitude: 48 },
"range": 178,
"tilt": 57.48,
"heading": -17,
},
"point": { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
"pin": {
"background": 'white',
"glyph": new URL(base + '/images/fr.svg'),
"scale": 1.0,
},
},
{
"name": "Google UK",
"camera": {
"center": { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
"range": 500,
"tilt": 56.21672368296945,
"heading": -31.15763027564165,
},
"point": { lat: 51.5332, lng: -0.1260, altitude: 75 },
"pin": {
"background": 'white',
"glyph": new URL(base + '/images/gb.svg'),
"scale": 1.0,
},
}]
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
...europeCamera,
mode: MapMode.SATELLITE,
});
officeLocations.forEach(office => {
const marker = new Marker3DInteractiveElement({
position: office.point,
label: office.name,
altitudeMode: 'ABSOLUTE',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: office.camera,
durationMillis: 5000,
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraAround({
camera: office.camera,
durationMillis: 5000,
rounds: 1
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraTo({
endCamera: europeCamera,
durationMillis: 5000,
});
}, { once: true });
}, { once: true });
event.stopPropagation();
});
const markerPin = new PinElement(office.pin);
marker.append(markerPin);
map3D.append(marker);
});
document.body.append(map3D);
}
init();
</script>
</body>
</html>
11. Больше мест
Хотя приложение теперь имеет все необходимые функции, 3D-карта по-прежнему выглядит немного скудной, поэтому теперь вы добавите еще несколько мест, чтобы сделать ее немного более загруженной. Благодаря использованию массива легко заполнять новые локации своими уникальными маркерами. Последний шаг — продолжать добавлять маркеры, пока не появится следующее представление.
Добавление дополнительных маркеров.
У Google есть несколько офисов во многих странах Европы, поэтому давайте добавим некоторые из них на карту. Это просто вопрос обновления массива. Это может быть получено из веб-сервиса или передано из какого-либо статического файла, в нашем случае для простоты оно будет храниться на той же странице.
Вы можете добавить столько маркеров, сколько захотите, которые будут подхвачены страницей, а затем автоматически добавлены в представление. Не забудьте получить правильные флаги и сохранить их в каталоге изображений (или где вам удобно).
const officeLocations = [
{
name: "Google France",
camera: {
center: { lat: 48.877276, lng: 2.329978, altitude: 48 },
range: 178,
tilt: 57.48,
heading: -17,
},
point: { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
pin: {
background: 'white',
glyph: new URL(base + '/images/fr.svg'),
scale: 1.0,
},
},
{
name: "Google UK",
camera: {
center: { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 51.5332, lng: -0.1260, altitude: 75 },
pin: {
background: 'white',
glyph: new URL(base + '/images/gb.svg'),
scale: 1.0,
},
},
{
name: "Google Belgium",
camera: {
center: { lat: 50.83930408436509, lng: 4.38052394507952, altitude: 64.38932203802196},
range: 466.62899893119175,
tilt: 43.61569474716178,
heading: 51.805907046332074,
},
point: { lat: 50.8392653, lng: 4.3808751, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/be.svg'),
scale: 1.0,
},
},
{
name: "Google Czechia",
camera: {
center: {
lat: 50.07004093853976,
lng: 14.402871475443956,
altitude: 223.39574818495532
},
range: 522.0365799222782,
tilt: 62.39511972890614,
heading: -39.150149539328304,
},
point: { lat: 50.0703122, lng: 14.402668199999999, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/cz.svg'),
scale: 1.0,
},
},
{
name: "Google Denmark",
details: "2, Sankt Petri Passage 5, 1165 København",
camera: {
center: {
lat: 55.680359539635866,
lng: 12.570460204526002,
altitude: 30.447654757346044
},
range: 334.8786935049066,
tilt: 55.38819319004654,
heading: 149.63867461295067,
},
point: { lat: 55.6804504, lng: 12.570279099999999, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/dk.svg'),
scale: 1.0,
},
},
,
{
name: "Google Greece",
camera: {
center: {
lat: 38.038634694028055,
lng: 23.802924946201266,
altitude: 196.45884670344995
},
range: 343.57226336076565,
tilt: 54.97375927639567,
heading: -33.26775344055724,
},
point: { lat: 38.038619, lng: 23.8031622, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/gr.svg'),
scale: 1.0,
},
},
{
name: "Google Germany",
camera: {
center: {
lat: 53.55397683312404,
lng: 9.986350507286808,
altitude: 44.83610870143956
},
range: 375.3474077822466,
tilt: 71.35078443829818,
heading: -160.76930098951416,
},
point: { lat: 53.5540227, lng: 9.9863, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/de.svg'),
scale: 1.0,
},
},
{
name: "Google Ireland",
camera: {
center: { lat: 53.339816899999995, lng: -6.2362644, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 53.339816899999995, lng: -6.2362644, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ie.svg'),
scale: 1.0,
},
},
{
name: "Google Italy",
camera: {
center: {
lat: 45.486361346538224,
lng: 9.18995496294455,
altitude: 138.55834058400072
},
range: 694.9398023590038,
tilt: 57.822470255679114,
heading: 84.10194883488619,
},
point: { lat: 45.4863064, lng: 9.1894762, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/it.svg'),
scale: 1.0,
},
},
{
name: "Google Lithuania",
camera: {
center: {
lat: 54.698040606567965,
lng: 25.30965338542576,
altitude: 111.80276944294413
},
range: 412.5808304977545,
tilt: 43.50793332082195,
heading: -29.181098269421028,
},
point: { lat: 54.6981204, lng: 25.3098617, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/at.svg'),
scale: 1.0,
},
},
{
name: "Google Netherlands",
camera: {
center: {
lat: 52.33773837150874,
lng: 4.871754560171063,
altitude: 53.68063996154723
},
range: 473.1982259177312,
tilt: 56.216523350388634,
heading: 71.78252318033718,
},
point: { lat: 52.337801, lng: 4.872065999999999, altitude: 100 },
pin: {
background: 'white',
glyph: new URL(base + '/images/nl.svg'),
scale: 1.0,
},
},
{
name: "Google Norway",
camera: {
center: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/no.svg'),
scale: 1.0,
},
},
{
name: "Google Poland",
camera: {
center: { lat: 52.22844380000001, lng: 20.9851819, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 52.22844380000001, lng: 20.9851819, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/pl.svg'),
scale: 1.0,
},
},
{
name: "Google Portugal",
camera: {
center: {
lat: 38.7240122810727,
lng: -9.150628263172639,
altitude: 55.299662291551044
},
range: 337.7474313328639,
tilt: 56.79772652682846,
heading: 176.0722118222208,
},
point: { lat: 38.723915999999996, lng: -9.150629, altitude: 35 },
pin: {
background: 'white',
glyph: new URL(base + '/images/pt.svg'),
scale: 1.0,
},
},
{
name: "Google Romania",
camera: {
center: {
lat: 44.43076650172983,
lng: 26.109700164718586,
altitude: 125.57895810814505
},
range: 364.25249956711923,
tilt: 38.517539223834326,
heading: -38.81294924429363,
},
point: { lat: 44.4309897, lng: 26.1095719, altitude: 75 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ro.svg'),
scale: 1.0,
},
},
{
name: "Google Spain",
camera: {
center: {
lat: 40.450078762608875,
lng: -3.6930085080020856,
altitude: 753.6446342341894
},
range: 845.7279793010093,
tilt: 46.752510050599746,
heading: 4.718779524265234,
},
point: { lat: 40.450294199999995, lng: -3.6927915, altitude: 175 },
pin: {
background: 'white',
glyph: new URL(base + '/images/es.svg'),
scale: 1.0,
},
},
{
name: "Google Sweden",
camera: {
center: {
lat: 59.33313751316038,
lng: 18.054618219238293,
altitude: 16.728213706832868
},
range: 377.5210725830039,
tilt: 63.59478230626709,
heading: 98.53138488367703,
},
point: { lat: 59.3332093, lng: 18.0536386, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/se.svg'),
scale: 1.0,
},
},
{
name: "Google Switzerland",
camera: {
center: {
lat: 47.365411056285275,
lng: 8.525063594405356,
altitude: 419.2348376754488
},
range: 166.74918737631742,
tilt: 59.31431457129067,
heading: -32.620415961949206,
},
point: { lat: 47.365452, lng: 8.5249253, altitude: 100 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ch.svg'),
scale: 1.0,
},
}
]
После того, как вы это сделаете, должна появиться полная страница, подобная показанному на изображении, которая позволит пользователю щелкнуть любое место и пролететь к нему и вокруг него, а затем вернуться обратно!
Поздравляем, вы завершили работу над кодом, давайте завершим работу в следующем разделе и поищем, что еще можно попробовать!
Решение раздела
На этом этапе заполненная страница предоставляется в качестве решения для проверки вашей реализации. (При копировании убедитесь, что вы используете свой собственный ключ API).
Также не забывайте, что вам нужно будет получить файл svgs (или png-файл по вашему выбору) с флагом и сохранить его в каталоге, который может быть найден на вашей странице (здесь он хранится в папке изображений).
<!DOCTYPE html>
<html>
<head>
<title>Step 9 - More Places!</title>
<style>
body {
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<script>
(g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
key: "<INSERT API KEY>",
v: "alpha",
// Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
// Add other bootstrap parameters as needed, using camel case.
});
</script>
<script>
let map3D = null;
const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));
const europeCamera = {
center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
range: 5814650,
tilt: 33,
heading: 4.36,
};
const officeLocations = [
{
name: "Google France",
details: "8 Rue de Londres, 75009 Paris, France",
camera: {
center: { lat: 48.877276, lng: 2.329978, altitude: 48 },
range: 178,
tilt: 57.48,
heading: -17,
},
point: { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
pin: {
background: 'white',
glyph: new URL(base + '/images/fr.svg'),
scale: 1.0,
},
},
{
name: "Google UK",
details: "6 Pancras Square, London N1C 4AG, UK",
camera: {
center: { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 51.5332, lng: -0.1260, altitude: 75 },
pin: {
background: 'white',
glyph: new URL(base + '/images/gb.svg'),
scale: 1.0,
},
},
{
name: "Google Belgium",
details: "Chau. d'Etterbeek 180, 1040 Brussel",
camera: {
center: { lat: 50.83930408436509, lng: 4.38052394507952, altitude: 64.38932203802196},
range: 466.62899893119175,
tilt: 43.61569474716178,
heading: 51.805907046332074,
},
point: { lat: 50.8392653, lng: 4.3808751, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/be.svg'),
scale: 1.0,
},
},
{
name: "Google Czechia",
details: "Stroupežnického 3191/17, 150 00 Praha 5-Smíchov",
camera: {
center: {
lat: 50.07004093853976,
lng: 14.402871475443956,
altitude: 223.39574818495532
},
range: 522.0365799222782,
tilt: 62.39511972890614,
heading: -39.150149539328304,
},
point: { lat: 50.0703122, lng: 14.402668199999999, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/cz.svg'),
scale: 1.0,
},
},
{
name: "Google Denmark",
details: "2, Sankt Petri Passage 5, 1165 København",
camera: {
center: {
lat: 55.680359539635866,
lng: 12.570460204526002,
altitude: 30.447654757346044
},
range: 334.8786935049066,
tilt: 55.38819319004654,
heading: 149.63867461295067,
},
point: { lat: 55.6804504, lng: 12.570279099999999, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/dk.svg'),
scale: 1.0,
},
},
,
{
name: "Google Greece",
details: "Fragkokklisias 6, Athina 151 25",
camera: {
center: {
lat: 38.038634694028055,
lng: 23.802924946201266,
altitude: 196.45884670344995
},
range: 343.57226336076565,
tilt: 54.97375927639567,
heading: -33.26775344055724,
},
point: { lat: 38.038619, lng: 23.8031622, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/gr.svg'),
scale: 1.0,
},
},
{
name: "Google Germany",
details: "ABC-Straße 19, 20354 Hamburg",
camera: {
center: {
lat: 53.55397683312404,
lng: 9.986350507286808,
altitude: 44.83610870143956
},
range: 375.3474077822466,
tilt: 71.35078443829818,
heading: -160.76930098951416,
},
point: { lat: 53.5540227, lng: 9.9863, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/de.svg'),
scale: 1.0,
},
},
{
name: "Google Ireland",
details: "Gordon House, 4 Barrow St, Grand Canal Dock, Dublin 4, D04 V4X7",
camera: {
center: { lat: 53.339816899999995, lng: -6.2362644, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 53.339816899999995, lng: -6.2362644, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ie.svg'),
scale: 1.0,
},
},
{
name: "Google Italy",
details: "Isola Building C, Via Federico Confalonieri, 4, 20124 Milano",
camera: {
center: {
lat: 45.486361346538224,
lng: 9.18995496294455,
altitude: 138.55834058400072
},
range: 694.9398023590038,
tilt: 57.822470255679114,
heading: 84.10194883488619,
},
point: { lat: 45.4863064, lng: 9.1894762, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/it.svg'),
scale: 1.0,
},
},
{
name: "Google Lithuania",
details: "Vilnius Tech Park, Antakalnis st. 17, 2nd building, LT-10312, Vilnius",
camera: {
center: {
lat: 54.698040606567965,
lng: 25.30965338542576,
altitude: 111.80276944294413
},
range: 412.5808304977545,
tilt: 43.50793332082195,
heading: -29.181098269421028,
},
point: { lat: 54.6981204, lng: 25.3098617, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/at.svg'),
scale: 1.0,
},
},
{
name: "Google Netherlands",
details: "Claude Debussylaan 34, 1082 MD Amsterdam",
camera: {
center: {
lat: 52.33773837150874,
lng: 4.871754560171063,
altitude: 53.68063996154723
},
range: 473.1982259177312,
tilt: 56.216523350388634,
heading: 71.78252318033718,
},
point: { lat: 52.337801, lng: 4.872065999999999, altitude: 100 },
pin: {
background: 'white',
glyph: new URL(base + '/images/nl.svg'),
scale: 1.0,
},
},
{
name: "Google Norway",
details: "Bryggegata 6, 0250 Oslo",
camera: {
center: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/no.svg'),
scale: 1.0,
},
},
{
name: "Google Poland",
details: "Rondo Daszynskiego 2, 00-843 Warsaw",
camera: {
center: { lat: 52.22844380000001, lng: 20.9851819, altitude: 38.777415761228006 },
range: 500,
tilt: 56.21672368296945,
heading: -31.15763027564165,
},
point: { lat: 52.22844380000001, lng: 20.9851819, altitude: 25 },
pin: {
background: 'white',
glyph: new URL(base + '/images/pl.svg'),
scale: 1.0,
},
},
{
name: "Google Portugal",
details: "R. Duque de Palmela 37 Piso 4, 1250-097 Lisboa",
camera: {
center: {
lat: 38.7240122810727,
lng: -9.150628263172639,
altitude: 55.299662291551044
},
range: 337.7474313328639,
tilt: 56.79772652682846,
heading: 176.0722118222208,
},
point: { lat: 38.723915999999996, lng: -9.150629, altitude: 35 },
pin: {
background: 'white',
glyph: new URL(base + '/images/pt.svg'),
scale: 1.0,
},
},
{
name: "Google Romania",
details: "Bulevardul Corneliu Coposu 6-8, București 030167",
camera: {
center: {
lat: 44.43076650172983,
lng: 26.109700164718586,
altitude: 125.57895810814505
},
range: 364.25249956711923,
tilt: 38.517539223834326,
heading: -38.81294924429363,
},
point: { lat: 44.4309897, lng: 26.1095719, altitude: 75 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ro.svg'),
scale: 1.0,
},
},
{
name: "Google Spain",
details: "Torre Picasso, Pl. Pablo Ruiz Picasso, 1, Tetuán, 28020 Madrid",
camera: {
center: {
lat: 40.450078762608875,
lng: -3.6930085080020856,
altitude: 753.6446342341894
},
range: 845.7279793010093,
tilt: 46.752510050599746,
heading: 4.718779524265234,
},
point: { lat: 40.450294199999995, lng: -3.6927915, altitude: 175 },
pin: {
background: 'white',
glyph: new URL(base + '/images/es.svg'),
scale: 1.0,
},
},
{
name: "Google Sweden",
details: "Kungsbron 2, 111 22 Stockholm",
camera: {
center: {
lat: 59.33313751316038,
lng: 18.054618219238293,
altitude: 16.728213706832868
},
range: 377.5210725830039,
tilt: 63.59478230626709,
heading: 98.53138488367703,
},
point: { lat: 59.3332093, lng: 18.0536386, altitude: 50 },
pin: {
background: 'white',
glyph: new URL(base + '/images/se.svg'),
scale: 1.0,
},
},
{
name: "Google Switzerland",
details: "Brandschenkestrasse 110, 8002 Zürich",
camera: {
center: {
lat: 47.365411056285275,
lng: 8.525063594405356,
altitude: 419.2348376754488
},
range: 166.74918737631742,
tilt: 59.31431457129067,
heading: -32.620415961949206,
},
point: { lat: 47.365452, lng: 8.5249253, altitude: 100 },
pin: {
background: 'white',
glyph: new URL(base + '/images/ch.svg'),
scale: 1.0,
},
}
]
async function init() {
const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');
map3D = new Map3DElement({
...europeCamera,
mode: MapMode.SATELLITE,
});
officeLocations.forEach(office => {
const marker = new Marker3DInteractiveElement({
position: office.point,
label: office.name,
altitudeMode: 'RELATIVE_TO_GROUND',
extruded: true,
});
marker.addEventListener('gmp-click', (event) => {
map3D.flyCameraTo({
endCamera: office.camera,
durationMillis: 2000,
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraAround({
camera: office.camera,
durationMillis: 2000,
rounds: 1
});
map3D.addEventListener('gmp-animationend', () => {
map3D.flyCameraTo({
endCamera: europeCamera,
durationMillis: 2000,
});
}, { once: true });
}, { once: true });
event.stopPropagation();
});
const markerPin = new PinElement(office.pin);
marker.append(markerPin);
map3D.append(marker);
});
document.body.append(map3D);
}
init();
</script>
</body>
</html>
12. Следующие шаги
В этой лаборатории кода вы рассмотрели основы того, что можно делать с помощью 3D в Maps JavaScript API. Затем попробуйте добавить на карту некоторые из этих объектов:
- Добавьте раскрывающийся список, чтобы можно было выбрать офис.
- Используйте некоторые другие параметры стиля маркера, чтобы показать больше бликов!
- Ознакомьтесь с дополнительными библиотеками, доступными для Maps JavaScript API, которые включают дополнительные функции, такие как Places, позволяющие отображать рейтинг каждого офиса с использованием его идентификатора места!
Чтобы продолжить изучение дополнительных способов работы с платформой Google Maps и 3D в Интернете, перейдите по этим ссылкам:
- Исследование фотореалистичных 3D-карт в документации Maps JavaScript
- Черпайте вдохновение из демо-версии 3D Maps
- Проведите еще одну лабораторную работу по разработке кода платформы Google Maps.
- Ознакомьтесь с проектами платформы Google Maps с открытым исходным кодом на GitHub.
- Прочтите блог платформы Google Карт.