本指南介绍了如何构建网页,以显示在 Earth Engine 中实时计算的互动式地图结果。适用于掌握了 HTML、CSS 和 JavaScript 的初级或中级知识的人士。
以下是您将在本指南中创建的互动式地图的演示。该地图显示了在 Earth Engine 中计算出的科罗拉多大峡谷的地形坡度,以不同深浅的灰色表示。您可以平移和缩放地图,以计算和显示其他区域的结果。请注意,您必须登录才能使用演示。
此处介绍的方法通常用于创建单页应用 (SPA)。在 SPA 中,整个应用可在 Web 浏览器中使用,而无需从服务器重新加载网页。因此,这些应用不需要开发和托管自定义服务器端组件。
由于应用的代码将在用户的网络浏览器中运行(也称为客户端执行),因此开发者不应将服务账号私钥等敏感凭据直接嵌入到应用中。相反,应用的用户必须使用自己的账号进行身份验证,这些账号已注册 Earth Engine 访问权限。
在本指南中,您将了解如何完成以下操作:
- 显示一个按钮,允许用户使用其 Earth Engine 账号登录。
- 在 Earth Engine 中定义基本分析。
- 嵌入互动式地图,以使用 Maps JavaScript API 显示结果。
前提条件
设置 Cloud 项目
- 在开始之前,请按照设置已启用 Earth Engine 的 Cloud 项目中的说明操作。记下“设置 OAuth 2.0”部分中获得的客户端 ID。由于您的应用将允许用户使用自己的 Google 账号登录,因此您可以跳过“创建和注册服务账号”部分。
- 为您的项目启用 Maps JavaScript API。
获取地图 API 密钥
如需了解如何获取 API 密钥,以便在 Web 应用中使用 Maps JavaScript API,请参阅 Maps JavaScript API 文档中的获取 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_KEY 和 YOUR_CLIENT_ID 替换为在前提条件中获取的地图 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>