שירות גובה

סקירה כללית

שירות הגובה מספק נתוני גובה למיקומים על פני כדור הארץ, כולל מיקומי עומק בקרקעית האוקיינוס (שמחזירים ערכים שליליים). במקרים שבהם ל-Google אין נתוני גובה מדויקים במיקום המדויק שביקשתם, השירות יבצע אינטרפולציה ויחזיר ערך ממוצע על סמך ארבעת המיקומים הקרובים ביותר.

אובייקט ElevationService מספק ממשק פשוט לשאילתות לגבי מיקומים בכדור הארץ כדי לקבל נתוני גובה. בנוסף, אפשר לבקש נתוני גובה מדגמיים לאורך נתיבים, כדי לחשב את שינויי הגובה במרחקים שווים לאורך מסלולים. אובייקט ElevationService מתקשר עם שירות הגובה של Google Maps API שמקבל בקשות לגובה ומחזיר נתוני גובה.

בעזרת שירות הגובה מעל פני הים, אפשר לפתח אפליקציות לטיולים רגליים ולרכיבה על אופניים, אפליקציות למיקום בנייד או אפליקציות לסקרים ברזולוציה נמוכה.

תחילת העבודה

לפני שמשתמשים בשירות הגובה ב-Maps JavaScript API, צריך לוודא קודם ש-Elevation API מופעל במסוף Google Cloud, באותו פרויקט שהגדרתם עבור Maps JavaScript API.

כדי לראות את רשימת ממשקי ה-API המופעלים:

  1. נכנסים ל מסוף Google Cloud.
  2. לוחצים על הלחצן Select a project, בוחרים את אותו פרויקט שהגדרתם עבור Maps JavaScript API ולוחצים על Open.
  3. ברשימת ממשקי ה-API במרכז הבקרה, מחפשים את Elevation API.
  4. אם ה-API מופיע ברשימה, הכול מוכן. אם ה-API לא מופיע ברשימה: מפעילים אותו:
    1. בחלק העליון של הדף, לוחצים על ENABLE API (הפעלת ה-API) כדי להציג את הכרטיסייה Library (ספרייה). לחלופין, בתפריט צד, לוחצים על ספרייה.
    2. מחפשים את Elevation API ובוחרים אותו מתוך רשימת התוצאות.
    3. לוחצים על הפעלה. בסיום התהליך, Elevation API יופיע ברשימת ממשקי ה-API במרכז הבקרה.

תמחור ומדיניות

תמחור

למידע על התמחור ומדיניות השימוש בשירות הגובה ב-JavaScript, אפשר לעיין במאמר בנושא שימוש וחיוב ב-Elevation API.

מדיניות

השימוש בשירות Elevation חייב להתבצע בהתאם למדיניות שמתוארת לגבי Elevation API.

בקשות לקביעת גובה

הגישה לשירות Elevation היא אסינכרונית, כי Google Maps API צריך לבצע קריאה לשרת חיצוני. לכן, צריך להעביר שיטת callback לביצוע עם השלמת הבקשה. שיטת הקריאה החוזרת הזו צריכה לעבד את התוצאות. חשוב לשים לב ששירות הגובה מחזיר קוד סטטוס (ElevationStatus) ומערך של אובייקטים נפרדים מסוג ElevationResult.

הספק ElevationService מטפל בשני סוגים של בקשות:

  • בקשות למיקומים נפרדים באמצעות השיטה getElevationForLocations(), שמועברת לה רשימה של מיקום אחד או יותר באמצעות אובייקט LocationElevationRequest.
  • בקשות לנתוני גובה בסדרה של נקודות מחוברות לאורך נתיב באמצעות השיטה getElevationAlongPath(), שמועברות לה קבוצה מסודרת של קודקודי נתיב באובייקט PathElevationRequest. כשמבקשים נתוני גובה לאורך נתיבים, צריך להעביר גם פרמטר שמציין כמה דגימות רוצים לקחת לאורך הנתיב.

בנוסף, כל אחת מהשיטות האלה צריכה להעביר שיטת callback כדי לטפל באובייקטים ElevationResult ו-ElevationStatus שמוחזרים.

בקשות לגובה של מיקום

ליטרל של אובייקט LocationElevationRequest מכיל את השדה הבא:

{
  locations[]: LatLng
}

locations (חובה) מגדיר את המיקומים על פני כדור הארץ שמהם יוחזרו נתוני הגובה. הפרמטר הזה מקבל מערך של LatLng.

אפשר להעביר כל מספר של קואורדינטות בתוך מערך, כל עוד לא חורגים ממכסות השירות. שימו לב: כשמעבירים כמה קואורדינטות, יכול להיות שרזולוציית הנתונים שיוחזרו תהיה נמוכה יותר מאשר כשמבקשים נתונים של קואורדינטה אחת.

בקשות לדוגמה לשינויים בגובה פני הקרקע לאורך המסלול

PathElevationRequest ליטרל של אובייקט מכיל את השדות הבאים:

{
  path[]: LatLng,
  samples: Number
}

הסבר על השדות האלה מופיע בהמשך:

  • path (חובה) מגדיר נתיב על פני כדור הארץ שאליו רוצים להחזיר נתוני גובה. הפרמטר path מגדיר קבוצה של שני זוגות או יותר של {latitude,longitude} מסודרים באמצעות מערך של שני אובייקטים LatLng או יותר.
  • samples (חובה) מציין את מספר נקודות הדגימה לאורך נתיב שעבורן יוחזרו נתוני גובה. הפרמטר samples מחלק את הנתיב שצוין path לקבוצה מסודרת של נקודות במרחקים שווים לאורך הנתיב.

בדומה לבקשות מיקום, הפרמטר path מציין קבוצה של ערכים של קו רוחב וקו אורך. עם זאת, בניגוד לבקשה למיקום, path מציין קבוצה מסודרת של קודקודים. במקום להחזיר נתוני גובה בקודקודים, המערכת דוגמת בקשות של נתיבים לאורך הנתיב, כאשר כל דגימה נמצאת במרחק שווה מהדגימות האחרות (כולל נקודות הקצה).

תשובות לגבי גובה

לכל בקשה תקינה, שירות הגובה יחזיר לקריאה החוזרת שהוגדרה קבוצה של אובייקטים ElevationResult יחד עם אובייקט ElevationStatus.

סטטוסים של גובה

כל בקשה של נתוני גובה מחזירה קוד ElevationStatus בפונקציית הקריאה החוזרת שלה. הקוד status הזה יכיל אחד מהערכים הבאים:

  • OK מציין שהבקשה לשירות בוצעה בהצלחה
  • INVALID_REQUEST מציין שבקשת השירות לא תקינה
  • OVER_QUERY_LIMIT מציין שהשולח חרג מהמכסה
  • REQUEST_DENIED שמציין שהשירות לא השלים את הבקשה, כנראה בגלל פרמטר לא תקין
  • UNKNOWN_ERROR שמציין שגיאה לא ידועה

כדאי לבדוק שההתקשרות חזרה הצליחה על ידי בדיקת קוד הסטטוס הזה של OK.

תוצאות של גובה

אם הפעולה בוצעה ללא שגיאות, הארגומנט results של פונקציית הקריאה החוזרת יכיל קבוצה של אובייקטים מסוג ElevationResult. האובייקטים האלה מכילים את הרכיבים הבאים:

  • רכיב location (שמכיל אובייקטים מסוג LatLng) של המיקום שעבורו מחושבים נתוני הגובה. הערה: בבקשות של נתיבים, קבוצת הרכיבים location תכיל את הנקודות שנדגמו לאורך הנתיב.
  • רכיב elevation שמציין את הגובה של המיקום במטרים.
  • ערך resolution, שמציין את המרחק המקסימלי בין נקודות הנתונים שמהן בוצעה האינטרפולציה של הגובה, במטרים. המאפיין הזה לא יופיע אם הרזולוציה לא ידועה. שימו לב שנתוני הגובה הופכים גסים יותר (ערכי resolution גדולים יותר) כשמעבירים כמה נקודות. כדי לקבל את ערך הגובה הכי מדויק של נקודה מסוימת, צריך לשלוח שאילתה לגביה בנפרד.

דוגמאות לגובה

הקוד הבא מתרגם קליק על מפה לבקשת גובה באמצעות האובייקט LocationElevationRequest:

TypeScript

async function init(): Promise<void> {
    const [{ InfoWindow }, { ElevationService }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('elevation'),
    ]);

    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    const elevator = new ElevationService();
    const infowindow = new InfoWindow();

    infowindow.open(innerMap);

    // Add a listener for the click event. Display the elevation for the LatLng of
    // the click inside the infowindow.
    innerMap.addListener('click', (event: google.maps.MapMouseEvent) => {
        displayLocationElevation(event.latLng!, elevator, infowindow, innerMap);
    });
}

function displayLocationElevation(
    location: google.maps.LatLng,
    elevator: google.maps.ElevationService,
    infowindow: google.maps.InfoWindow,
    map: google.maps.Map
) {
    // Format numeric values to two decimal places
    const formatter = new Intl.NumberFormat(undefined, {
        maximumFractionDigits: 2,
    });

    // Initiate the location request
    elevator
        .getElevationForLocations({
            locations: [location],
        })
        .then(({ results }) => {
            if (results[0]) {
                const { elevation, location: resultLocation } = results[0];
                infowindow.setPosition(resultLocation);
                infowindow.setContent(
                    `The elevation at ${String(resultLocation)} <br>is ${formatter.format(elevation)} meters.`
                );
            } else {
                infowindow.setPosition(location);
                infowindow.setContent('No results found');
            }

            infowindow.open(map);
        })
        .catch((e: unknown) => {
            infowindow.setContent(
                `Elevation service failed due to: ${String(e)}`
            );
        });
}

void init();

JavaScript

async function init() {
    const [{ InfoWindow }, { ElevationService }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('elevation'),
    ]);

    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    const elevator = new ElevationService();
    const infowindow = new InfoWindow();

    infowindow.open(innerMap);

    // Add a listener for the click event. Display the elevation for the LatLng of
    // the click inside the infowindow.
    innerMap.addListener('click', (event) => {
        displayLocationElevation(event.latLng, elevator, infowindow, innerMap);
    });
}

function displayLocationElevation(location, elevator, infowindow, map) {
    // Format numeric values to two decimal places
    const formatter = new Intl.NumberFormat(undefined, {
        maximumFractionDigits: 2,
    });

    // Initiate the location request
    elevator
        .getElevationForLocations({
            locations: [location],
        })
        .then(({ results }) => {
            if (results[0]) {
                const { elevation, location: resultLocation } = results[0];
                infowindow.setPosition(resultLocation);
                infowindow.setContent(
                    `The elevation at ${String(resultLocation)} <br>is ${formatter.format(elevation)} meters.`
                );
            } else {
                infowindow.setPosition(location);
                infowindow.setContent('No results found');
            }

            infowindow.open(map);
        })
        .catch((e) => {
            infowindow.setContent(
                `Elevation service failed due to: ${String(e)}`
            );
        });
}

void init();
לצפייה בדוגמה

בדוגמה הבאה מוצג אופן בניית קו רב-קודקודים על סמך קבוצת קואורדינטות, והצגת נתוני גובה לאורך הנתיב באמצעות Google Visualization API. (חובה לטעון את ה-API הזה באמצעות Google Common Loader). בקשת העלאה בנויה באמצעות: PathElevationRequest:

TypeScript

// Load the Visualization API and the columnchart package.
// @ts-ignore TODO update to newest visualization library
google.load("visualization", "1", { packages: ["columnchart"] });

function initMap(): void {
  // The following path marks a path from Mt. Whitney, the highest point in the
  // continental United States to Badwater, Death Valley, the lowest point.
  const path = [
    { lat: 36.579, lng: -118.292 }, // Mt. Whitney
    { lat: 36.606, lng: -118.0638 }, // Lone Pine
    { lat: 36.433, lng: -117.951 }, // Owens Lake
    { lat: 36.588, lng: -116.943 }, // Beatty Junction
    { lat: 36.34, lng: -117.468 }, // Panama Mint Springs
    { lat: 36.24, lng: -116.832 },
  ]; // Badwater, Death Valley

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 8,
      center: path[1],
      mapTypeId: "terrain",
    }
  );

  // Create an ElevationService.
  const elevator = new google.maps.ElevationService();

  // Draw the path, using the Visualization API and the Elevation service.
  displayPathElevation(path, elevator, map);
}

function displayPathElevation(
  path: google.maps.LatLngLiteral[],
  elevator: google.maps.ElevationService,
  map: google.maps.Map
) {
  // Display a polyline of the elevation path.
  new google.maps.Polyline({
    path: path,
    strokeColor: "#0000CC",
    strokeOpacity: 0.4,
    map: map,
  });

  // Create a PathElevationRequest object using this array.
  // Ask for 256 samples along that path.
  // Initiate the path request.
  elevator
    .getElevationAlongPath({
      path: path,
      samples: 256,
    })
    .then(plotElevation)
    .catch((e) => {
      const chartDiv = document.getElementById(
        "elevation_chart"
      ) as HTMLElement;

      // Show the error code inside the chartDiv.
      chartDiv.innerHTML = "Cannot show elevation: request failed because " + e;
    });
}

// Takes an array of ElevationResult objects, draws the path on the map
// and plots the elevation profile on a Visualization API ColumnChart.
function plotElevation({ results }: google.maps.PathElevationResponse) {
  const chartDiv = document.getElementById("elevation_chart") as HTMLElement;

  // Create a new chart in the elevation_chart DIV.
  const chart = new google.visualization.ColumnChart(chartDiv);

  // Extract the data from which to populate the chart.
  // Because the samples are equidistant, the 'Sample'
  // column here does double duty as distance along the
  // X axis.
  const data = new google.visualization.DataTable();

  data.addColumn("string", "Sample");
  data.addColumn("number", "Elevation");

  for (let i = 0; i < results.length; i++) {
    data.addRow(["", results[i].elevation]);
  }

  // Draw the chart using the data within its DIV.
  chart.draw(data, {
    height: 150,
    legend: "none",
    // @ts-ignore TODO update to newest visualization library
    titleY: "Elevation (m)",
  });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// Load the Visualization API and the columnchart package.
// @ts-ignore TODO update to newest visualization library
google.load("visualization", "1", { packages: ["columnchart"] });

function initMap() {
  // The following path marks a path from Mt. Whitney, the highest point in the
  // continental United States to Badwater, Death Valley, the lowest point.
  const path = [
    { lat: 36.579, lng: -118.292 }, // Mt. Whitney
    { lat: 36.606, lng: -118.0638 }, // Lone Pine
    { lat: 36.433, lng: -117.951 }, // Owens Lake
    { lat: 36.588, lng: -116.943 }, // Beatty Junction
    { lat: 36.34, lng: -117.468 }, // Panama Mint Springs
    { lat: 36.24, lng: -116.832 },
  ]; // Badwater, Death Valley
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 8,
    center: path[1],
    mapTypeId: "terrain",
  });
  // Create an ElevationService.
  const elevator = new google.maps.ElevationService();

  // Draw the path, using the Visualization API and the Elevation service.
  displayPathElevation(path, elevator, map);
}

function displayPathElevation(path, elevator, map) {
  // Display a polyline of the elevation path.
  new google.maps.Polyline({
    path: path,
    strokeColor: "#0000CC",
    strokeOpacity: 0.4,
    map: map,
  });
  // Create a PathElevationRequest object using this array.
  // Ask for 256 samples along that path.
  // Initiate the path request.
  elevator
    .getElevationAlongPath({
      path: path,
      samples: 256,
    })
    .then(plotElevation)
    .catch((e) => {
      const chartDiv = document.getElementById("elevation_chart");

      // Show the error code inside the chartDiv.
      chartDiv.innerHTML = "Cannot show elevation: request failed because " + e;
    });
}

// Takes an array of ElevationResult objects, draws the path on the map
// and plots the elevation profile on a Visualization API ColumnChart.
function plotElevation({ results }) {
  const chartDiv = document.getElementById("elevation_chart");
  // Create a new chart in the elevation_chart DIV.
  const chart = new google.visualization.ColumnChart(chartDiv);
  // Extract the data from which to populate the chart.
  // Because the samples are equidistant, the 'Sample'
  // column here does double duty as distance along the
  // X axis.
  const data = new google.visualization.DataTable();

  data.addColumn("string", "Sample");
  data.addColumn("number", "Elevation");

  for (let i = 0; i < results.length; i++) {
    data.addRow(["", results[i].elevation]);
  }

  // Draw the chart using the data within its DIV.
  chart.draw(data, {
    height: 150,
    legend: "none",
    // @ts-ignore TODO update to newest visualization library
    titleY: "Elevation (m)",
  });
}

window.initMap = initMap;
לצפייה בדוגמה