建立第一個擬真 3D 地圖

1. 事前準備

本程式碼研究室旨在協助您瞭解如何使用 Maps JavaScript 中的擬真 3D 地圖,建立第一個 3D 地圖。您將瞭解載入 Maps JavaScript API 的正確元件、顯示第一個 3D 地圖,以及在其中繪製地圖功能的基本概念。

建構目標

您要建立的第一個地圖。

在本程式碼研究室中,您將建構一個 3D 網頁應用程式,執行以下操作:

  • 動態載入 Maps JavaScript API。
  • 以多倫多的加拿大國家電視塔為中心,顯示 3D 地圖。
  • 在某個位置周圍顯示邊界。
  • 關閉 3D 地圖上的搜尋點。
  • 將邊界延伸至涵蓋位置。

課程內容

  • 開始使用 Google 地圖平台。
  • 使用動態程式庫匯入功能,從 JavaScript 程式碼動態載入 Maps JavaScript API。
  • 使用 Map3DElement 類別載入 3D 地圖。
  • 使用多邊形和擠出效果在地圖上繪製圖形。

2. 先決條件

您必須熟悉這裡的項目,才能完成本程式碼研究室。如果您已經熟悉 Google 地圖平台的使用方式,請直接前往程式碼研究室!

必要的 Google 地圖平台產品

在本程式碼研究室中,您將使用下列 Google 地圖平台產品:

  • Maps JavaScript API

沒錯,只要這樣就能在網頁中加入 3D 地圖,非常簡單!

本程式碼研究室的其他規定

如要完成本程式碼研究室,您需要下列帳戶、服務和工具:

  • 已啟用計費功能的 Google Cloud 帳戶
  • 已啟用 Maps JavaScript API 的 Google 地圖平台 API 金鑰
  • 具備 JavaScript、HTML 和 CSS 的基本知識
  • 您選擇的文字編輯器或 IDE,用於儲存要查看的編輯檔案
  • 網路瀏覽器,可用於在工作時查看檔案

3. 做好準備

設定 Google 地圖平台

如果您尚未建立 Google Cloud Platform 帳戶,以及已啟用帳單功能的專案,請參閱「開始使用 Google 地圖平台」指南,建立帳單帳戶和專案。

  1. Cloud 控制台中,點選專案下拉式選單,然後選取要用於本程式碼研究室的專案。

  1. Google Cloud Marketplace 中啟用本程式碼研究室所需的 Google 地圖平台 API 和 SDK。如要進行這項操作,請按照這部影片這份說明文件中的步驟操作。
  2. 在 Cloud 控制台的「憑證」頁面中產生 API 金鑰。您可以按照這部影片這份說明文件中的步驟操作。所有 Google 地圖平台要求都需要 API 金鑰。

4. 載入 Maps JavaScript API

完成「設定」一節的所有步驟後,您就可以開始建立第一張 3D 地圖。

建立您能想像到的最簡單的網頁。

首先,我們會建立一個非常基本的網頁來代管所有程式碼。您可以在任何編輯器或平台中執行這項操作。

 <!DOCTYPE html>
 <html>
   <head>
    <title>3D Maps Codelab</title>
     <style>
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
   </head>
   <body>
   </body>
 </html>

加入程式碼,並將檔案儲存至可存取的位置,例如 3dmap.html,然後在網路瀏覽器中開啟檔案,查看網頁目前的狀態,並檢查是否有任何錯誤。

和 2D 地圖一樣,3D 地圖的基礎是 Maps JavaScript API,因此您必須先載入該 API。

您可以透過多種方式執行這項操作,請參閱說明文件中的「載入 Maps JavaScript API」一節。

在本示範中,我們將使用較新穎的動態程式庫匯入方法,因為這個方法可讓您只控制需要載入的元素,節省下載大小和啟動時間。

新增動態載入器

如要使用動態載入器,請務必在網頁中加入下列指令碼標記,並在適當位置加入您自己的 API 金鑰 (您已在步驟 2 中取得)。將這個指令碼標記放在基本網頁的 body 區段之間。

  <script async defer>
    (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: "YOUR_API_KEY",
      v: "alpha",
    });
  </script>

請注意,在產品發布階段,我們使用的是 API 的Alpha 分支,因此可以存取 3D 地圖。這類版本包含產品的大部分實驗功能,讓您在開發期間測試搶先體驗版程式碼,以便在發布時使用。

您現在應該有包含動態載入器的基本網頁 (如果您開啟網頁,檢視畫面會是空白,但不應有任何錯誤),現在可以新增 3D 地圖了。

如果您的程式碼無法運作,您可以參考步驟 6 的結果,找出問題所在。

如要找出網頁無法運作的原因,請查看瀏覽器中的錯誤控制台,找出錯誤原因。錯誤頁面提供不同瀏覽器的操作說明,並說明各種錯誤訊息,以及 API 無法運作的常見原因。這是在整個開發過程中,用來找出任何實作項目可能發生的問題的好資源。

5. 顯示地圖

我們現在已準備就緒,可以將第一個 3D 地圖加入頁面!

3D 地圖是使用 google.maps.maps3d.Map3DElement 類別建立,可讓我們建立及使用 3D 地圖例項。在本程式碼研究室中,我們將直接使用 3D 地圖物件,而非透過 HTML 標記。

建立初始化函式並載入程式庫

首先,我們會建立函式,將元素載入頁面。請查看程式碼,我們會先建立非同步函式,以便在繼續執行其餘程式碼之前,確保整個元素都已載入。然後在網頁載入時執行 init 函式。

請在網頁內文的載入指令碼後方加入這段程式碼。

  <script>
    async function init() {
      const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");
    }
    init();
  </script>

請注意,我們使用 await 運算式,確保在繼續之前已載入程式庫。

建立 3D 地圖元素並指定位置

接下來,我們需要指定要顯示地圖檢視畫面的地點。對於 3D 地圖,您可以使用多種不同的參數來設定檢視畫面。這些是指虛擬相機參數,可用來說明您在場景中看到的內容。

我們來建立一個類似下圖的 CN Tower 檢視畫面。

您要建立的第一個地圖。

首先,我們需要指定要查看的座標。這些畫面由兩個不同的檢視畫面組成

  1. 我們要查看的點,包括其海拔高度。
  2. 虛擬相機觀看該點的距離和方向。

請參考下圖,瞭解這些設定的運作方式。

顯示地圖元素設定的圖片。

元素的中心是指您正在觀看的點,範圍是指您與物體的距離,傾斜度則是您觀看圖片的角度。您也可以設定物件的標頭和傾斜度,以便控制這些項目,但我們在這裡不會使用這個功能。

接下來,我們將在匯入程式庫後,在初始化區段中新增以下程式碼,並在頁面上建立 3D 地圖。

  const map3DElement = new Map3DElement({
      center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
      range: 1000,
      tilt: 60,
      mode: MapMode.HYBRID,
  });

  document.body.append(map3DElement);

首先建立元素並設定適當的位置參數,然後在頁面上新增元件 (如果有現有的 div,我們可以將元件指派給該 div)。

您的程式碼現在應如以下範例所示:

<!DOCTYPE html>
<html>

<head>
    <title>3D Maps Codelab</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script async defer>
        (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: "YOUR_API_KEY",
            v: "alpha",
        });
    </script>
    <script>
        async function init() {
            const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");

            const map3DElement = new Map3DElement({
                center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
                range: 1000,
                tilt: 60,
                mode: MapMode.HYBRID
            });

            document.body.append(map3DElement);
        }

        init();
    </script>
</body>
</html>

我們現在可以儲存檔案,並在瀏覽器中開啟頁面,確認網頁運作正常。我們應該會看到攝影機向下俯瞰塔樓,如圖所示。請先試玩一下,然後再在塔樓上方新增一個方塊。

您要建立的第一個地圖。

6. 新增及擠出地形特徵

我們現在有了 3D 地圖,讓我們為使用者標示物件,讓他們知道這是感興趣的項目。在本例中,我們將使用多邊形和擠出函式,在 CN 塔周圍建立方塊,讓畫面看起來像下圖所示。

顯示具有立體多邊形的地點。

隱藏雜亂內容

首先,您可能會發現我們已關閉 POI 功能。在這張地圖中,我們希望焦點是塔本身,因此需要移除其他視覺元素。

為此,我們需要新增程式碼變更來隱藏標籤。將地圖的模式行更新為「衛星」,即可隱藏點。

  mode: MapMode.SATELLITE,

設定這個屬性會停用地圖上的標籤,這不僅包括搜尋點,也包括道路和邊界線,並建立「清晰」的位置檢視畫面。

新增多邊形並設定樣式

下一步是將多邊形加入頁面。這項操作可分兩個步驟完成。首先,我們需要載入包含必要資訊的函式,然後指定多邊形的樣式詳細資料,例如顏色或是否顯示在其他地圖項目後方。

首先,我們會使用以下程式碼行,將必要的類別新增至頁面。

  const { Polygon3DElement, AltitudeMode } = await google.maps.importLibrary("maps3d");

這會將 Polygon3DElementAltitudeMode 類別載入至頁面,這些類別是將多邊形物件新增至檢視畫面所需的。

多邊形可以設定多種不同的選項來控制檢視畫面,包括筆劃寬度、顏色 (名稱或 16 進位值) 和邊界與填充設定的不透明度,以及是否要在其他地物或建築物後方顯示多邊形 (例如繪製遮蔽區段)。詳情請參閱 Polygon3DElement 類別的說明文件。

我們需要設定的另一個功能,是讓多邊形以擠出方式繪製。也就是在設定的高度繪製多邊形,然後將其延伸到地面。這會為多邊形提供高度,就像一個方塊 (如上圖所示)。這也需要我們在多邊形上設定高度模式,因此我們需要載入上述的 AltitudeMode 常數。為了擠出多邊形,請將這項屬性設為 ABSOLUTERELATIVE_TO_GROUND,以便從多邊形頂點的高度取得正確位置。

程式碼會建立常值物件,其中包含這些屬性,可用來建立 Polygon3DElement 物件,如下所示:

  const polygonOptions = {
    strokeColor: "#EA433580",
    strokeWidth: 4,
    fillColor: "#0000FF80",
    altitudeMode: "ABSOLUTE",
    extruded: true,
    drawsOccludedSegments: true,
  }

  const towerPolygon = new google.maps.maps3d.Polygon3DElement(polygonOptions);

我們已建立多邊形物件,因此也必須設定地理座標。多邊形可同時具有內部和外部座標,這取決於多邊形的表示方式。innerCoordinates 會提供多邊形內部切除的形式,而 outerCoordinates 則會定義多邊形的外部邊界。由於這是多邊形,而不是線條,因此座標必須從同一個點開始和結束,才能形成完整的形狀。

您可以使用 LatLng 或 LatLngAltitude 物件或字面值陣列指定座標,我們可以看到這項功能在基本多邊形中運作。

  towerPolygon.outerCoordinates = [
    { lat: 43.6427196, lng: -79.3876802, altitude: 600 },
    { lat: 43.6421742, lng: -79.3869184, altitude: 600 },
    { lat: 43.643001, lng: -79.3866475, altitude: 600 },
    { lat: 43.6427196, lng: -79.3876802, altitude: 600 }
  ];

我們已設定多邊形的樣式和座標,現在可以將多邊形加入頁面了。多邊形是地圖元素的子項元素,需要新增至網頁中現有的地圖物件。在頁面中加入下列程式碼。

  map3DElement.append(towerPolygon);

完成後,您應該會看到以下完整實作項目,如下所示 (但會顯示您自己的 API 金鑰)。我們可以執行網頁並查看結果。

<!DOCTYPE html>
<html>

<head>
    <title>3D Maps Codelab</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <script async defer>
        (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: "YOUR_API_KEY",
            v: "alpha",
        });
    </script>
    <script>
        async function init() {
            const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");

            const map3DElement = new Map3DElement({
                center: { lat: 43.6425, lng: -79.3871, altitude: 400 },
                range: 1000,
                tilt: 60,
                mode: MapMode.SATELLITE,
            });

            const { Polygon3DElement, AltitudeMode } = await google.maps.importLibrary("maps3d");

            const polygonOptions = {
                strokeColor: "#EA433580",
                strokeWidth: 4,
                fillColor: "#0000FF80",
                fillOpacity: 0.2,
                altitudeMode: "ABSOLUTE",
                extruded: true,
                drawsOccludedSegments: true,
            }

            const towerPolygon = new google.maps.maps3d.Polygon3DElement(polygonOptions);

            towerPolygon.outerCoordinates = [
                { lat: 43.6427196, lng: -79.3876802, altitude: 600 },
                { lat: 43.6421742, lng: -79.3869184, altitude: 600 },
                { lat: 43.643001, lng: -79.3866475, altitude: 600 },
                { lat: 43.6427196, lng: -79.3876802, altitude: 600 }
            ];

            map3DElement.append(towerPolygon);

            document.body.append(map3DElement);
        }
        
        init();
    </script>

</body>
</html>

如果程式碼正確,您應該會看到包含下列 3D 地圖和多邊形的頁面。

程式碼完成後應有的檢視畫面。

您已成功使用 Google 地圖平台建立第一個 3D 地圖,包括載入 Maps JavaScript API、建立 3D 地圖,以及新增外推多邊形。

7. 接下來要做什麼?

在本程式碼研究室中,您已瞭解如何運用 Maps JavaScript API 執行基本操作。接著,請嘗試在地圖中加入下列部分功能:

  • 新增按鈕,切換開啟/關閉 POI。
  • 新增一些線條,顯示往返不同地點的路線。
  • 設定一些邊界限制,控制使用者可將檢視畫面移動到哪裡。
  • 請查看 Maps JavaScript API 提供的其他程式庫,這些程式庫可啟用其他服務,例如 Places 或 Directions。

如要進一步瞭解如何使用 Google 地圖平台和 3D 網路服務,請參閱下列連結: