用戶端網頁應用程式中的 Earth Engine API

本指南說明如何建構網頁,顯示 Earth Engine 即時運算的結果,並以互動式地圖呈現。適用對象為具備 HTML、CSS 和 JavaScript 初級或中級知識的使用者。

以下是您將在本指南中建立的互動式地圖示範。畫面顯示 Earth Engine 計算出的大峽谷地形坡度,並以不同深淺的灰色表示。您可以平移及縮放地圖,計算並顯示其他區域的結果。請注意,您必須登入才能使用試用版。

建立單頁應用程式 (SPA) 時,通常會使用這裡所述的方法。在 SPA 中,整個應用程式都可在網頁瀏覽器中使用,無須從伺服器重新載入網頁。因此,這類應用程式不需要開發及代管自訂伺服器端元件。

由於應用程式的程式碼會在使用者網頁瀏覽器中執行 (也稱為用戶端執行),開發人員不應直接在應用程式中嵌入服務帳戶私密金鑰等機密憑證。應用程式使用者必須使用已註冊 Earth Engine 存取權的帳戶進行驗證。

這份指南說明如何:

  1. 顯示按鈕,讓使用者透過 Earth Engine 帳戶登入。
  2. 在 Earth Engine 中定義基本分析。
  3. 嵌入互動式地圖,使用 Maps JavaScript API 顯示結果。

必要條件

設定 Cloud 專案

  1. 開始之前,請按照「設定已啟用 Earth Engine 的 Cloud 專案」中的操作說明進行。請記下「設定 OAuth 2.0」一節中取得的用戶端 ID。由於您的應用程式會允許使用者登入自己的 Google 帳戶,因此您可以略過「建立及註冊服務帳戶」一節。
  2. 為專案啟用 Maps JavaScript API

取得 Maps API 金鑰

請參閱 Maps JavaScript API 說明文件中的「取得 API 金鑰」,瞭解如何取得 API 金鑰,以便在網頁應用程式中使用 Maps JavaScript API。

強烈建議您按照「限制 API 金鑰」一節中的操作說明,確保只有經授權的要求才能使用 API 金鑰。

建立應用程式

步驟 1:建立 HTML 網頁

首先,請定義基本 HTML 網頁,如下所示:

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Set the size of the div element that contains the map. */
      #map-container {
        height: 400px;
        width: 100%;
        background-color: #eee;
      }
    </style>
  </head>
  <body>
    <!-- The "Sign in with Google" button, initially hidden. -->
    <input
      id="g-sign-in"
      type="image"
      src="https://developers.google.com/identity/images/btn_google_signin_light_normal_web.png"
      onclick="onSignInButtonClick()"
      alt="Sign in with Google"
      hidden
    />

    <!-- Element where map will be added. -->
    <div id="map-container"></div>
    <script>
      // JavaScript code goes here.
    </script>
  </body>
</html>

這個基本 HTML 會執行下列幾項動作:

  • 使用 CSS 樣式定義初始化時顯示的地圖大小和背景顏色。
  • 定義「使用 Google 帳戶登入」按鈕,在點選時呼叫 onSignInButtonClick() 函式。我們將在下一節中以 JavaScript 定義這個函式。
  • 定義空白元素,初始化後會包含地圖。
  • 新增空白的 <script> 區塊,用於保留下方定義的 JavaScript 程式碼。

步驟 2:在 JavaScript 中定義行為

在後續步驟中,JavaScript 程式碼可以直接放在 <script> 標記內。

定義回呼以設定 API 和地圖

定義使用者登入後要執行的函式。使用者通過驗證後,才能初始化及叫用 Earth Engine API。我們很快就會發布更多相關消息。

這個範例會初始化 Earth Engine 和 Maps API,建立可依需求計算地形坡度的圖塊來源,並將圖塊來源新增至地圖,做為 Maps JavaScript API 顯示的疊加層:

// Initializes Maps JavaScript API and Earth Engine API, instructing the map
// to pull tiles from Earth Engine and to overlay them on the map.
function setUpMap() {
  // Hide the sign-in button.
  document.getElementById("g-sign-in").setAttribute("hidden", "true");

  // Initialize the Earth Engine API. Must be called once before using the API.
  ee.initialize(null, null, null, null, null, 'my-project');

  // Get a reference to the placeholder DOM element to contain the map.
  const mapContainerEl = document.getElementById("map-container");

  // Create an interactive map inside the placeholder DOM element.
  const embeddedMap = new google.maps.Map(mapContainerEl, {
    // Pan and zoom initial map viewport to Grand Canyon.
    center: {lng: -112.8598, lat: 36.2841},
    zoom: 9,
  });

  // Obtain reference to digital elevation model and apply algorithm to
  // calculate slope.
  const srtm = ee.Image("CGIAR/SRTM90_V4");
  const slope = ee.Terrain.slope(srtm);

  // Create a new tile source to fetch visible tiles on demand and display them
  // on the map.
  const mapId = slope.getMap({min: 0, max: 60});
  const tileSource = new ee.layers.EarthEngineTileSource(mapId);
  const overlay = new ee.layers.ImageOverlay(tileSource);
  embeddedMap.overlayMapTypes.push(overlay);
}

定義登入按鈕點擊事件的處理常式

接著,新增函式,在點選登入按鈕時顯示登入彈出式視窗。如果成功,系統會呼叫 setUp() 方法。

// Handles clicks on the sign-in button.
function onSignInButtonClick() {
  // Display popup allowing the user to sign in with their Google account and to
  // grant appropriate permissions to the app.
  ee.data.authenticateViaPopup(setUpMap);
}

這個回呼會透過 onclick 屬性與上述 HTML 中的按鈕建立關聯。請注意,在本範例中,登入按鈕會在網頁載入時隱藏。在下一節中,我們會先檢查使用者是否已登入,再顯示按鈕。

定義主要進入點

現在要定義網頁載入時首先執行的頂層程式碼。這會使用 Earth Engine 的內建驗證輔助函式 ee.data.authenticateViaPopup(),檢查使用者是否已登入。如果使用者已登入,函式會要求適當的權限,並在成功時呼叫 setUp() 來初始化 Earth Engine 和 Maps API。

如果使用者未登入,系統會顯示登入按鈕。使用者可以點選按鈕觸發 onSignInButtonClick(),這會顯示彈出式視窗並呼叫 setUp(),啟動登入程序。

// If the user is signed in, display a popup requesting permissions needed to
// run the app, otherwise show the sign-in button.
ee.data.authenticateViaOauth(
  // The OAuth Client ID defined above.
  CLIENT_ID,
  // Callback invoked immediately when user is already signed in.
  setUpMap,
  // Show authentication errors in a popup.
  alert,
  // Request permission to only read and compute Earth Engine data on behalf of
  // user.
  /* extraScopes = */ ['https://www.googleapis.com/auth/earthengine.readonly'],
  // Show sign-in button if reusing existing credentials fails.
  () => document.getElementById("g-sign-in").removeAttribute("hidden"),
  // Don't require ability to write and access Cloud Platform on behalf of the
  // user.
  /* opt_suppressDefaultScopes = */ true
);

歡迎親自體驗

本指南提供的完整解決方案如下。程式碼範例右上角有三個按鈕。按一下最左側的按鈕,即可在 JSFiddle 中開啟範例。

YOUR_API_KEYYOUR_CLIENT_ID 替換為在必要條件中取得的 Maps API 金鑰和 OAuth 用戶端 ID (您可以點選下方程式碼中的這些預留位置,系統就會自動插入)。此外,請將 'my-project' 替換為您的 Google Cloud 雲端專案 ID。

<!-- Load Maps JavaScript API. For production apps, append you own ?key=YOUR_API_KEY. -->

<script src="https://maps.googleapis.com/maps/api/js?key="></script>
<script src="https://ajax.googleapis.com/ajax/libs/earthengine/0.1.365/earthengine-api.min.js"></script>
<!-- The "Sign in with Google" button, initially hidden. -->
<input
  id="g-sign-in"
  type="image"
  src="https://developers.google.com/identity/images/btn_google_signin_light_normal_web.png"
  onclick="onSignInButtonClick()"
  alt="Sign in with Google"
  hidden
/>

<!-- Element where map will be added. -->
<div id="map-container"></div>
/* Set the size of the div element that contains the map. */
  #map-container {
    height: 400px;
    width: 100%;
    background-color: #eee;
  }
// The OAuth Client ID from the Google Developers Console.
// REMINDER: Be sure to add a valid ID here!
const CLIENT_ID = "";

// Initializes Maps JavaScript API and Earth Engine API, instructing the map
// to pull tiles from Earth Engine and to overlay them on the map.
function setUpMap() {
  // Hide the sign-in button.
  document.getElementById("g-sign-in").setAttribute("hidden", "true");

  // Initialize the Earth Engine API. Must be called once before using the API.
  ee.initialize(null, null, null, null, null, 'my-project');

  // Get a reference to the placeholder DOM element to contain the map.
  const mapContainerEl = document.getElementById("map-container");

  // Create an interactive map inside the placeholder DOM element.
  const embeddedMap = new google.maps.Map(mapContainerEl, {
    // Pan and zoom initial map viewport to Grand Canyon.
    center: {lng: -112.8598, lat: 36.2841},
    zoom: 9,
  });

  // Obtain reference to digital elevation model and apply algorithm to
  // calculate slope.
  const srtm = ee.Image("CGIAR/SRTM90_V4");
  const slope = ee.Terrain.slope(srtm);

  // Create a new tile source to fetch visible tiles on demand and display them
  // on the map.
  const mapId = slope.getMap({min: 0, max: 60});
  const tileSource = new ee.layers.EarthEngineTileSource(mapId);
  const overlay = new ee.layers.ImageOverlay(tileSource);
  embeddedMap.overlayMapTypes.push(overlay);
}

// Handles clicks on the sign-in button.
function onSignInButtonClick() {
  // Display popup allowing the user to sign in with their Google account and to
  // grant appropriate permissions to the app.
  ee.data.authenticateViaPopup(setUpMap);
}

// If the user is signed in, display a popup requesting permissions needed to
// run the app, otherwise show the sign-in button.
ee.data.authenticateViaOauth(
  // The OAuth Client ID defined above.
  CLIENT_ID,
  // Callback invoked immediately when user is already signed in.
  setUpMap,
  // Show authentication errors in a popup.
  alert,
  // Request permission to only read and compute Earth Engine data on behalf of
  // user.
  /* extraScopes = */ ['https://www.googleapis.com/auth/earthengine.readonly'],
  // Show sign-in button if reusing existing credentials fails.
  () => document.getElementById("g-sign-in").removeAttribute("hidden"),
  // Don't require ability to write and access Cloud Platform on behalf of the
  // user.
  /* opt_suppressDefaultScopes = */ true
);
<!DOCTYPE html>
<html>
  <head>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/earthengine/0.1.365/earthengine-api.min.js"></script>
    <style>
      /* Set the size of the div element that contains the map. */
      #map-container {
        height: 400px;
        width: 100%;
        background-color: #eee;
      }
    </style>
  </head>
  <body>
    <!-- The "Sign in with Google" button, initially hidden. -->
    <input
      id="g-sign-in"
      type="image"
      src="https://developers.google.com/identity/images/btn_google_signin_light_normal_web.png"
      onclick="onSignInButtonClick()"
      alt="Sign in with Google"
      hidden
    />

    <!-- Element where map will be added. -->
    <div id="map-container"></div>
    <script>
      // The OAuth Client ID from the Google Developers Console.
      const CLIENT_ID = "YOUR_CLIENT_ID";
      
      // Initializes Maps JavaScript API and Earth Engine API, instructing the map
      // to pull tiles from Earth Engine and to overlay them on the map.
      function setUpMap() {
        // Hide the sign-in button.
        document.getElementById("g-sign-in").setAttribute("hidden", "true");
      
        // Initialize the Earth Engine API. Must be called once before using the API.
        ee.initialize(null, null, null, null, null, 'my-project');
      
        // Get a reference to the placeholder DOM element to contain the map.
        const mapContainerEl = document.getElementById("map-container");
      
        // Create an interactive map inside the placeholder DOM element.
        const embeddedMap = new google.maps.Map(mapContainerEl, {
          // Pan and zoom initial map viewport to Grand Canyon.
          center: {lng: -112.8598, lat: 36.2841},
          zoom: 9,
        });
      
        // Obtain reference to digital elevation model and apply algorithm to
        // calculate slope.
        const srtm = ee.Image("CGIAR/SRTM90_V4");
        const slope = ee.Terrain.slope(srtm);
      
        // Create a new tile source to fetch visible tiles on demand and display them
        // on the map.
        const mapId = slope.getMap({min: 0, max: 60});
        const tileSource = new ee.layers.EarthEngineTileSource(mapId);
        const overlay = new ee.layers.ImageOverlay(tileSource);
        embeddedMap.overlayMapTypes.push(overlay);
      }
      
      // Handles clicks on the sign-in button.
      function onSignInButtonClick() {
        // Display popup allowing the user to sign in with their Google account and to
        // grant appropriate permissions to the app.
        ee.data.authenticateViaPopup(setUpMap);
      }
      
      // If the user is signed in, display a popup requesting permissions needed to
      // run the app, otherwise show the sign-in button.
      ee.data.authenticateViaOauth(
        // The OAuth Client ID defined above.
        CLIENT_ID,
        // Callback invoked immediately when user is already signed in.
        setUpMap,
        // Show authentication errors in a popup.
        alert,
        // Request permission to only read and compute Earth Engine data on behalf of
        // user.
        /* extraScopes = */ ['https://www.googleapis.com/auth/earthengine.readonly'],
        // Show sign-in button if reusing existing credentials fails.
        () => document.getElementById("g-sign-in").removeAttribute("hidden"),
        // Don't require ability to write and access Cloud Platform on behalf of the
        // user.
        /* opt_suppressDefaultScopes = */ true
      );
    </script>
  </body>
</html>