Adicionar marcadores e animação a um mapa 3D fotorrealista

1. Antes de começar

Neste tutorial, mostramos como adicionar e estilizar marcadores 3D no seu aplicativo. Você também vai aprender a animar seu aplicativo voando para e ao redor de locais específicos.

Este tutorial se baseia nos conceitos abordados no primeiro codelab. Conclua esse codelab para adquirir os conhecimentos básicos necessários para este app.

O que você aprenderá

"O mapa completo com marcadores.

Este aplicativo fornece uma visão geral dos principais escritórios do Google na Europa. Os usuários podem selecionar um escritório, entrar e contornar para explorar e, em seguida, diminuir o zoom para retornar à vista geral. Esses recursos, comumente encontrados em aplicativos de viagens e exploração, oferecem uma experiência mais imersiva aos usuários.

Neste codelab, você vai criar um app da Web em 3D que:

  • Carrega a API Maps JavaScript de forma dinâmica.
  • Adiciona marcadores 3D ao mapa.
  • Aplica estilos aos marcadores usando SVGs.
  • Adiciona a capacidade de voar para e ao redor dos marcadores.
  • Faz a abstração dos locais do código em uma matriz.

O que você vai aprender

  • Como os marcadores funcionam.
  • Como definir o estilo dos marcadores.
  • Como a animação funciona com as funções integradas.
  • Posicionar os locais da câmera em vez dos locais de ponto para um melhor enquadramento.
  • Truques úteis para capturar parâmetros da câmera e enquadrar melhor os itens.

Pré-requisitos

Você precisa se familiarizar com os itens aqui para concluir este codelab. Se você já conhece a Plataforma Google Maps, avance para o codelab.

Produtos obrigatórios da Plataforma Google Maps

Neste codelab, você usará os seguintes produtos da Plataforma Google Maps:

  • API Maps JavaScript

Outros requisitos para o codelab

Para concluir este codelab, você precisará das seguintes contas, serviços e ferramentas:

  • Uma conta do Google Cloud com o faturamento ativado.
  • Uma chave de API da Plataforma Google Maps com a API Maps JavaScript ativada.
  • Conhecimento básico de JavaScript, HTML e CSS.
  • Um editor de texto ou ambiente de desenvolvimento integrado de sua escolha para salvar e editar um arquivo.
  • Um navegador da Web para visualizar o arquivo enquanto você trabalha.

2. Começar a configuração

Configurar a Plataforma Google Maps

Caso você ainda não tenha uma conta do Google Cloud Platform e um projeto com faturamento ativado, veja como criá-los no guia da Plataforma Google Maps.

  1. No Console do Cloud, clique no menu suspenso do projeto e selecione o projeto que você quer usar neste codelab.

  1. Ative as APIs e os SDKs da Plataforma Google Maps necessários para este codelab no Google Cloud Marketplace. Para fazer isso, siga as etapas descritas neste vídeo ou nesta documentação.
  2. Gere uma chave de API na página Credenciais do Console do Cloud. Siga as etapas indicadas neste vídeo ou nesta documentação. Todas as solicitações à Plataforma Google Maps exigem uma chave de API.

3. Globo simples

Para começar a criar o aplicativo, é essencial estabelecer a configuração básica. Isso vai produzir uma visão "esfera azul" da Terra na forma mais essencial, conforme mostrado na imagem:

"Imagem mostrando o globo como ele foi configurado inicialmente.

Adicionar o código da página inicial

Para adicionar o globo ao site, você precisa incluir o seguinte código na página. Isso vai adicionar uma seção para o carregador da API Maps JavaScript e uma função de inicialização que cria o elemento do mapa 3D na página em que você vai adicionar o código dos marcadores.

Adicione sua própria chave (criada na seção Configurar) à página. Caso contrário, o elemento 3D não poderá ser inicializado.

<!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>

Depois disso, você pode começar a enquadrar o local de interesse, o que será feito na próxima etapa.

4. Quadro de primeira visualização

Agora que você criou um mapa com uma visualização do globo, a próxima etapa de implementação é definir o local de partida correto. Isso permite que o usuário tenha uma visão geral instantânea de onde está trabalhando.

Embora este exemplo se concentre nos escritórios do Google na Europa, você pode aplicar essa abordagem a qualquer lugar do mundo, de um país inteiro a um único quarteirão. A velocidade e a flexibilidade do produto permitem que você dimensione seu aplicativo de global para local com mudanças mínimas no código.

Você vai começar com o enquadramento inicial para que o mapa 3D fique assim:

&quot;O globo estava centralizado na Europa.

Enquadrar a câmera na Europa

Para conseguir a exibição mostrada, você precisa enquadrar a tela corretamente, como se estivesse posicionando uma câmera no espaço olhando para o local.

Para isso, vários parâmetros no controle do mapa podem ser usados para definir os detalhes da câmera. É possível ver como os parâmetros interagem no mundo "real" no diagrama. Especificamente, há o ponto central que a câmera está olhando e a distância de onde você está olhando (o alcance). Você também precisa definir a inclinação da perspectiva da câmera. Caso contrário, você vai olhar diretamente para a Terra.

&quot;Uma imagem mostrando os parâmetros da câmera.

A configuração final, heading, determina a direção da câmera. Ele é medido como o deslocamento do norte verdadeiro. Esses valores são aplicados ao elemento do mapa 3D como um objeto para configurar a exibição inicial. Isso pode ser visto no código com o construtor de elementos 3D atualizado.

map3D = new Map3DElement({
    center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
    range: 5814650,
    tilt: 33,
    heading: 4.36,
    mode: MapMode.HYBRID
});

Capturar parâmetros da câmera

Enquadrar uma visualização em um mapa 3D requer a colocação precisa da câmera, o que pode ser difícil de alcançar apenas com o código. Para simplificar esse processo, use este hack útil: adicione uma função à sua página que capture os parâmetros da câmera quando você clicar na visualização necessária. Os parâmetros serão exibidos no console, prontos para serem copiados nas configurações da câmera do objeto.

Você pode encontrar o código que pode querer usar mais tarde. Ele foi adicionado à amostra desta página mostrada, mas não estará na amostra de páginas subsequentes, porque não é necessário para o codelab. No entanto, é algo que você precisa lembrar se quiser criar demonstrações mais imersivas com um posicionamento melhor da câmera.

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();
});

Observe o uso da função stopCameraAnimation. Se a página estiver com zoom ou rotação, é útil interromper a animação para capturar a localização na tela naquele momento. Esse código permite fazer isso. Confira mais detalhes na documentação de stopCameraAnimation.

Exemplo de saída do clique, conforme mostrado no console.

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 }

O texto da câmera pode ser usado como uma entrada JSON em vários objetos nos Mapas 3D. A segunda saída é o local real do ponto em que o clique ocorreu, também útil para criar pontos ou qualquer coisa para o posicionamento de marcadores.

Com a página enquadrada corretamente, agora você pode adicionar marcadores. Siga para a próxima etapa para saber como fazer isso.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de 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. Marcador simples

Nesta seção, você vai aprender a adicionar seu primeiro marcador. Primeiro, você vai aprender detalhes gerais sobre marcadores.

Os mapas 3D oferecem suporte à criação de duas classes de marcadores diferentes, a Marker3DElement e a Marker3DInteractiveElement. A escolha é determinada pela ativação ou não dos cliques no marcador. Além disso, eles são essencialmente iguais. Portanto, primeiro você vai criar um Marker3DElement e depois "atualizar" para o Marker3DInteractiveElement nas próximas etapas.

Confira a solução completa para esta etapa aqui:

&quot;Um globo com um marcador mostrando a etapa concluída.

Adicionar altura aos marcadores

A primeira coisa a saber é que os marcadores são 3D, assim como tudo no mapa 3D. Isso significa que o local pode ter uma altura (altitude) e essa altura pode ser representativa como uma posição relativa ao nível do mar, ao solo, à malha ou fixada no solo e ignorando a altitude. Confira mais detalhes na seção "Constantes de altitude" na documentação de AltitudeMode.

Também é possível definir se o marcador é extrudido ou não usando o valor extruded. Isso vai determinar se o marcador terá uma pequena linha desenhada no chão para mostrar a posição real em relação à altura, o que é útil para escolher pontos no chão. Confira um exemplo disso com o local do Google no Reino Unido. Ambos são extrudados e têm a posição definida como uma altura absoluta. A primeira a 75 metros e a segunda a 125 metros.

Marcador a 75 metros

Marcador a 125 metros

Altitude de 75 metros.

Altitude de 125 metros.

Ocultar ou mostrar marcadores com oclusão e colisão

Embora isso não seja importante na nossa demonstração, porque as posições estão bem distantes, para marcadores que podem se sobrepor ou ficar atrás de edifícios, é possível controlar o que acontece com eles usando os valores collisionBehavior ou drawsWhenOccluded.

Para o comportamento de colisão, você tem as seguintes opções:

  • REQUIRED (padrão): sempre mostrar o marcador, independentemente do conflito.
  • OPTIONAL_AND_HIDES_LOWER_PRIORITY: só mostrar o marcador se ele não se sobrepuser a outros elementos. Em caso de conflito, o marcador com o maior zIndex vai aparecer. Se eles tiverem o mesmo zIndex, aquele com a posição vertical mais abaixo na tela será mostrado.
  • REQUIRED_AND_HIDES_OPTIONAL: sempre mostrar o marcador, independentemente do conflito, e ocultar todos os marcadores OPTIONAL_AND_HIDES_LOWER_PRIORITY ou rótulos que se sobrepuserem a ele.

As imagens mostram as diferenças na forma como os marcadores são mostrados com base no comportamento de colisão definido. Todos os marcadores são mostrados ao definir REQUIRED, mas se você usar REQUIRED_AND_HIDES_OPTIONAL, os marcadores mais baixos na tela serão exibidos. Você pode brincar com o zIndex para fazer com que outros marcadores apareçam na parte de cima, se quiser.

Marcadores sendo mostrados conforme necessário

Marcadores que ocultam outros marcadores

OBRIGATÓRIO

REQUIRED_AND_HIDES_OPTIONAL

Para a oclusão, você pode escolher se os marcadores serão desenhados atrás dos edifícios ou não. Isso é mostrado na imagem abaixo. Quando drawsWhenOccluded é definido como verdadeiro, os marcadores são mostrados com um pouco de desfoque quando desenhados atrás de edifícios. Quando definido como falso, os marcadores são ocultados quando estão atrás de um edifício. Confira mais detalhes na tabela a seguir:

Imagem mostrando o mapa ocultando marcadores obstruídos

Imagem mostrando o mapa com marcadores obstruídos

drawsWhenOccluded : false

drawsWhenOccluded : true

Como mencionado, os marcadores ocultos por colisão vão aparecer esmaecidos se a exibição de marcadores ocultos for permitida. Na imagem, é possível ver alguns dos marcadores ocultos pelos edifícios e outros ocultos por outros marcadores.

&quot;Uma imagem mostrando vários marcadores e o efeito da oclusão.

Consulte o exemplo de comportamento de colisão em um mapa 2D para mais detalhes.

Limpar a tela

Agora é hora de criar seu primeiro marcador. Para garantir que o usuário se concentre nos marcadores, desative os rótulos padrão no mapa 3D.

Defina o valor mode do elemento do mapa 3D como SATELLITE.

Para mais informações, consulte modo.

map3D = new Map3DElement({
    center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
    range: 5814650,
    tilt: 33,
    heading: 4.36,
    mode: MapMode.SATELLITE
});

O resultado é o seguinte mapa em 3D:

&quot;Imagem da Europa sem bordas e texto.

Adicionar o primeiro marcador

Com uma tela limpa, agora você pode adicionar o primeiro marcador. Os principais parâmetros incluem posição e rótulo.

Para adicionar um marcador, defina a posição dele. Também é possível incluir um rótulo, que aparece acima do marcador, e outros elementos, conforme descrito na documentação do Marker3DElement.

Para adicionar nosso marcador, adicione o seguinte código após a linha que oculta os rótulos padrão, conforme mostrado:

const marker = new Marker3DElement({
   position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
   label: 'Google UK',
   altitudeMode: 'ABSOLUTE',
   extruded: true,
});

map3D.append(marker);

Depois de criar o marcador, adicione-o ao mapa 3D usando o método de adição. Os marcadores são armazenados como uma matriz de elementos filhos no mapa 3D. Para modificar um marcador, acesse-o por meio dessa matriz.

Adicione Marker3DElement à lista de bibliotecas ao carregar a API Maps JavaScript para garantir que ela seja carregada.

const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");

Agora, quando a página for carregada, toda a Europa vai aparecer com um marcador acima do escritório de Londres. Como mostrado na animação, é possível aumentar o zoom manualmente para ver o marcador sobre o local criado.

“Animação mostrando zoom manual no Google UK.

Agora que você carregou o primeiro marcador, a próxima etapa é deixá-lo mais bonito.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de 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. Marcador SVG

Nesta etapa, você vai melhorar a aparência do marcador adicionando uma bandeira para representar o país em que ele está. Vamos ver como isso é feito. Para isso, você precisa conhecer o PinElement.

No final, você terá uma nova aparência, como mostrado:

&quot;Imagem com um marcador com uma bandeira do Reino Unido&quot;

Personalização básica com PinElement

Um dos elementos compartilhados entre os marcadores na API JavaScript, sejam mapas 2D ou 3D, é o PinElement. Enquanto você adiciona um Marker3DElement ao Map3DElement , você adiciona um PinElement ao Marker3DElement como um filho desse elemento.

O PinElement tem a capacidade básica de alterar o marcador normal para definir a cor da borda, do ponto interno (ou glifo) e do plano de fundo. Você pode conferir isso na imagem que mostra um marcador 2D.

“Imagem com opções para personalização de marcadores”

Também é possível definir um tamanho de marcador pelo elemento definindo o valor da escala (>1 é maior que o normal e <1 é menor como uma proporção).

Você também pode substituir o glifo por uma imagem ou um arquivo SVG se quiser dar um visual mais personalizado, mas mantendo o alfinete de mapa padrão do PinElement.

Além dos PinElements

Nesta etapa, você vai atualizar o PinElement padrão com uma flag svg e cores diferentes, mas também é possível mudar completamente a aparência de um marcador para que ele não se pareça com um alfinete no mapa. No marcador, também é possível inserir novos gráficos usando modelos, como HTMLImageElement e SVGElement. Confira mais detalhes sobre como fazer isso na documentação Marker3DElement-Slots.

Para saber o que é possível fazer, confira os exemplos a seguir que mostram como estilizar marcadores usando várias técnicas diferentes.

Imagem mostrando a personalização básica de marcadores.

Imagem mostrando a personalização de marcadores complexos.

Marcadores com personalização básica usando PinElement: consulte amostras.

Marcadores com personalização complexa usando modelo com SVG e imagens. Consulte amostras.

Adicionar o PinElement

Para mudar a aparência do marcador, a primeira coisa a ser feita é garantir que a biblioteca PinElement tenha sido adicionada à página. Para isso, adicione a seguinte linha de código após a importação da biblioteca maps3d:

const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');

Agora que o elemento foi carregado, o PinElement pode ser referenciado e criado. Analise o código, adicione-o entre o local em que o marcador é criado e anexe-o ao mapa 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);

Como você não está carregando apenas um marcador básico, é necessário fazer mais do que apenas configurar o PinElement, com a cor de plano de fundo e a escala associada.

Primeiro, é necessário fazer uma referência a uma imagem SVG para o ícone de bandeira, uma Union Jack, neste caso. Você pode encontrá-los em uma coleção como esta em https://flagicons.lipis.dev/.

Depois de colocar o ícone em um local que o site possa localizar, nesse caso, você pode codificar o local da imagem ou usar o local atual do site como o stub do diretório, conforme mostrado aqui com a variável base. Em seguida, você pode vincular isso ao local no servidor à bandeira certa, que aqui está em '/images/gb.svg'.

Isso cria um PinElement semelhante ao mostrado:

&quot;Marcador mostrando o símbolo da bandeira do Reino Unido.

Depois de colocar a bandeira e o código no lugar certo, você terá um mapa 3D assim:

&quot;Aumentando o zoom no novo marcador.

Agora que nosso marcador está pronto, ele também pode ser alterado para torná-lo clicável e permitir a adição de interatividade. Isso será feito na próxima etapa.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de API.

Além disso, não se esqueça de baixar o arquivo svg (ou png, à sua escolha) da bandeira e armazená-lo em um diretório que possa ser encontrado pela página (aqui, ele está armazenado na pasta de imagens).

<!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. Marcador interativo

Na última etapa, um marcador foi adicionado à página, mas, além de parecer bom, ele não faz muito e você ainda precisa interagir com o mapa 3D da mesma maneira. A próxima etapa é adicionar a capacidade de fazer algo com o marcador quando você clicar nele, permitindo que ele reaja à interação do usuário.

Para adicionar esse recurso, você precisa transformar o Marker3DElement em um Marker3DInteractiveElement. No final, você terá uma página semelhante, mas em que um clique no marcador vai abrir um alerta parecido com este:

&quot;Imagem mostrando a resposta quando clicada.

Primeiro, mude a classe do marcador

Para adicionar interatividade a um marcador, é necessário garantir que ele esteja usando a classe correta. O Marker3DInteractiveElement é o necessário, mas, como é uma extensão do Marker3DElement, não é preciso fazer nada além de carregar a nova classe e mudar o nome dela no construtor.

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,
});

Em segundo lugar, adicione o evento de clique ao marcador.

Em seguida, adicione um evento de clique ao marcador para processar a interação do usuário e responder. No snippet, é possível ver que o evento de clique foi adicionado ao marcador. Nesse caso, um alerta é acionado e exibe o texto que mostra o rótulo do marcador, obtido do destino do evento acionado, o que nos permite acessar a propriedade do rótulo. Adicione o código abaixo ao seu aplicativo logo após a construção do marcador.

marker.addEventListener('gmp-click', (event) => {
   alert('You clicked on : ' + event.target.label);
   event.stopPropagation();
});

O evento stopPropagation é usado para garantir que outros listeners de clique na pilha sejam disparados em objetos subjacentes, como a tela principal do mapa 3D.

Agora, ao executar o aplicativo, você vai receber o seguinte resultado:

&quot;Imagem mostrando a resposta quando clicada.

Com a capacidade de fazer algo quando o marcador é clicado, agora é possível adicionar uma animação à página na próxima etapa.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de 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. Voar para

Nesta etapa, você vai usar a capacidade de clicar no marcador para adicionar animação e ir até o local. Confira como isso funciona aqui.

&quot;Animação mostrando o marcador clicado e a aproximação do local.

Animação com flyCameraTo

Para adicionar isso à página, use o método flyCameraTo do Maps 3D, em que a câmera é animada entre o local em que você está e o local que você quer mostrar, interpolando entre os dois e animando o voo no Mapa 3D.

Ao usar flyCameraTo, é necessário especificar as FlyToAnimationOptions, que tem duas propriedades: endCamera, que é o local para onde a câmera deve apontar no final da animação, e durationMillis, que é a duração em milissegundos necessária para fazer a transição.

No exemplo, defina a câmera para olhar o edifício, que é a posição do marcador, com uma inclinação de 65 graus, um alcance de 500 metros e apontar para o norte com uma direção de 0 grau. Defina o tempo da animação como 12.500 milissegundos (12,5 segundos).

Substitua o evento de alerta atual na página pelo snippet flyCameraTo:

marker.addEventListener('gmp-click', (event) => {
   map3D.flyCameraTo({
       endCamera: {
           center: marker.position,
           tilt: 65,
           range: 500,
           heading: 0,
       },
       durationMillis: 12500,
   });

   event.stopPropagation();
});

Pronto. Agora você pode atualizar a página, clicar no marcador e ir para o Google UK, como mostrado na animação:

&quot;Animação mostrando o marcador clicado e a aproximação do local.

Nesta etapa, você adicionou um marcador clicável que leva a câmera ao local do marcador. Na próxima etapa, você vai adicionar a capacidade de mover a câmera ao redor do ponto para que ela orbite o local.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de 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. Voar por aí

O elemento final da nossa animação é usar o método flyCameraAround para animar uma órbita ao redor do edifício. No final, você terá uma animação que vai voar até o edifício e depois voar ao redor dele, como mostrado na animação. Provavelmente, isso é um pouco rápido para um exemplo real, mas é útil para mostrar como a ação funciona, sem ser muito longa. Você pode brincar com os tempos até encontrar um valor que funcione para você.

&quot;Animação mostrando um marcador sendo clicado e depois voando para e ao redor de um local.

Vamos voar!

O método flyCameraAround é semelhante à função flyCameraTo, porque usa várias opções como uma entrada que controla qual local orbitar, como parâmetros da câmera e o tempo em milissegundos que leva para orbitar. Por fim, você também pode especificar o número de rotações que podem ocorrer no período especificado. Confira todas as opções em FlyAroundAnimationOptions.

Mas espere um minuto!

Na animação, você pode ver que ela voa até o local e depois ao redor dele, encadeando as animações. Para fazer isso, use o evento gmp-animationend do Maps 3D para garantir que a animação atual seja concluída antes de acionar a próxima. Essa animação só precisa acontecer uma vez antes de parar.

Analise o código e insira-o após o código adicionado na seção anterior.

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();
});

A capacidade de detectar o evento gmp-animationend permite invocar o evento flyCameraAround. Definir o ponto de partida como o mesmo usado para a câmera final do método "voar para" significa uma transição suave (para não causar movimentos bruscos para um novo local). Novamente, o durationMillis é definido para controlar o tempo necessário para fazer a animação. Nesse caso, o método também recebe outra opção, rounds, que é definida como 1.

Isso significa que a câmera vai girar em torno do ponto uma vez a cada 5 segundos. Teste esses valores para encontrar o número ideal.

Nesse ponto, a animação vai terminar, mas você não quer que o evento gmp-animationend seja acionado novamente com esse código, o que resultaria em uma órbita infinita. Para evitar isso, uma opção para o listener com a configuração de once igual a true. Isso significa que o evento será removido após a conclusão, evitando o loop infinito.

Depois de adicionar isso, você poderá executar a solução e ver a animação voar ao redor do marcador no final, conforme mostrado na animação:

&quot;Animação mostrando um marcador voando em volta.

Nesta etapa, você adicionou um marcador que pode ser clicado. A câmera voa até o local do marcador e circula em torno dele. Na próxima etapa, é hora de começar a adicionar mais pontos e permitir que nos movamos entre eles.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de 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. Paris!

Embora Londres seja uma cidade incrível, ela parece um pouco solitária na página. Vamos começar a adicionar alguns novos locais, começando por Paris. Para fazer isso, uma matriz pode ser usada para armazenar todos os detalhes específicos do local e, em seguida, usar isso como entradas para as funções e variáveis que definem os parâmetros de exibição do marcador e também o voo para e em torno dos locais da câmera. O que, como mencionado, pode ser diferente do local do marcador para enquadrar melhor uma foto de um edifício, por exemplo.

&quot;Animação mostrando um clique e o voo para e em torno do Google França.

Matriz de local

Para não precisar programar todos os detalhes de um local específico, como a câmera de visualização, o ponto do marcador e as opções de exibição, use uma pequena matriz de objetos JSON para armazenar esses dados. Isso pode ser aplicado quando os marcadores são criados e usados no aplicativo. Você pode conferir este exemplo no snippet de código, criando uma variável chamada officeLocations para armazenar a matriz.

Adicione o código abaixo antes da função de inicialização. Além disso, a variável base foi movida para fora da função de inicialização para que possa ser aplicada a todos os locais de escritório.

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("/"));

Cada local de escritório tem as seguintes propriedades:

  • name :o nome do local.
  • câmera :a visualização inicial para procurar o local e voar por ele.
  • point :o local onde o marcador será colocado.
  • pin :os detalhes das propriedades de glifo e cor do marcador.

Um ângulo diferente

Observe que, no Reino Unido, o centro da câmera e o ponto do marcador são iguais (exceto a altitude), enquanto na França, a câmera e o ponto são diferentes. Isso ocorre porque, para o local na França, o marcador precisa estar em um local diferente da visualização inicial da câmera, que oferece uma visão melhor de todo o edifício ao voar para e ao redor do que poderia ser dado se o ponto do marcador fosse usado.

Voltar para a Europa

Uma função de ter mais pontos é que ela adiciona um requisito para poder se mover entre eles. Você pode usar um menu suspenso para permitir a seleção, mas, neste exemplo, a câmera volta para a visualização europeia sempre que o usuário seleciona outro local.

Para fazer isso, a visualização inicial precisa ser armazenada em uma variável que pode ser usada para redefinir a câmera para a visualização completa da Europa. Neste exemplo, adicione uma nova variável chamada europeCamera para armazenar o valor para uso posterior.

Atualizar a função de inicialização

A primeira edição que você precisa fazer é usar o objeto europeCamera como entrada ao criar o Map3DElement.

A segunda edição que você precisa fazer é agrupar a seção de criação de marcadores em um loop para atualizá-la com os parâmetros armazenados nas variáveis. Você pode conferir isso no código mostrado:

  • office.point :o local do marcador.
  • office.name :o nome do escritório usado para o rótulo do marcador.
  • office.camera :o local inicial da câmera.
  • office.pin :as opções PinElement para mostrar diferenças

Além disso, não se esqueça de usar um arquivo SVG ou uma imagem para a bandeira francesa.

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);
}

Uma segunda função gmp-animationend é adicionada após a animação flyCameraAround para processar o retorno à visualização europeia, usando a variável europeCamera armazenada. Como mostrado na animação:

&quot;Animação voando entre e ao redor de escritórios na França e no Reino Unido.

Nesta fase, o aplicativo foi estendido para ter dois locais e a capacidade de voar entre eles usando animação e uma matriz de local. Na próxima etapa, o restante dos locais de escritórios será adicionado à matriz.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de API.

Além disso, não se esqueça de baixar o arquivo svg (ou png, se preferir) da bandeira e armazená-lo em um diretório que possa ser encontrado pela página (aqui, ele está armazenado na pasta "imagens").

<!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. Mais lugares

Embora o aplicativo tenha todos os recursos necessários, o mapa 3D ainda parece um pouco vazio. Por isso, adicione mais alguns locais para que ele fique mais movimentado. Com o uso de uma matriz, é fácil continuar preenchendo novos locais com marcadores exclusivos. A última etapa é continuar adicionando marcadores até que a visualização abaixo apareça.

&quot;Uma imagem mostrando todos os escritórios.

Adicionar mais marcadores.

O Google tem vários escritórios em muitos países da Europa. Vamos adicionar alguns deles ao mapa. Basta atualizar a matriz. Ele pode ser originado de um serviço da Web ou de um arquivo estático em algum lugar. No nosso caso, por simplicidade, ele será mantido na mesma página.

Você pode adicionar quantos marcadores quiser, que são selecionados pela página e adicionados automaticamente à visualização. Não se esqueça de pegar as flags corretas e armazená-las no diretório de imagens (ou onde for conveniente).

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,
       },
   }
]

Depois disso, uma página completa como a mostrada na imagem vai aparecer, permitindo que o usuário clique em qualquer local e navegue por ele e em volta dele.

“Animação de voo entre escritórios na Espanha e na Suécia.

Parabéns, você concluiu o codelab. Vamos concluir na próxima seção e procurar outras coisas novas para tentar.

Solução da seção

Nesta etapa, a página concluída é fornecida como uma solução para verificar sua implementação. Se for copiar, use sua própria chave de API.

Além disso, não se esqueça de baixar o arquivo svg (ou png, se preferir) da bandeira e armazená-lo em um diretório que possa ser encontrado pela página (aqui, ele está armazenado na pasta "imagens").

<!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. Próximas etapas

Neste codelab, você aprendeu os conceitos básicos do que é possível fazer com a API Maps JavaScript 3D. Agora, tente incluir alguns destes recursos no mapa:

  • Adicione uma lista suspensa para permitir a seleção de um escritório.
  • Use algumas das outras opções de estilo de marcador para mostrar mais detalhes.
  • Confira as outras bibliotecas disponíveis para a API Maps JavaScript que ativam outros recursos, como o Places para mostrar a classificação de cada escritório usando o ID do lugar.

Para continuar aprendendo mais maneiras de trabalhar com a Plataforma Google Maps e o 3D na Web, confira estes links: