WorldWindJS Example Lesson 4

WorldWind web app with Layer Mgmt and Search.

by Bruce Schubert

HTML

<!doctype html>
<html lang="en">

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <title>WorldWindJS Example</title>

    <!-- Bootstrap 4.0 CSS compiled and minified -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <!-- Font Awesome icons (see: https://fontawesome.com/icons?d=gallery) -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.10/css/all.css" integrity="sha384-+d0P83n9kaQMCwj8F4RJB66tzIwOKmrdb46+porD/OvrJ+37WqIM7UoBtwHO6Nlg" crossorigin="anonymous">

    <!-- Custom styles and overrides -->
    <link href="custom.css" rel="stylesheet">
  </head>

  <body>

    <nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark">

      <!--Branding icon and text-->
      <a class="navbar-brand" href="https://worldwind.arc.nasa.gov/web target=_blank">
                <img src="images/nasa-logo_32.png" width="30" height="30" class="d-inline-block align-top" alt="">
                WorldWindJS
            </a>

      <!--Hamburger menu displayed on small screens/windows-->
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#main-menu" aria-controls="main-menu" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

      <!--Main menu content-->
      <div class="collapse navbar-collapse" id="main-menu">
        <ul class="navbar-nav mr-auto">
          <!--Layers-->
          <li class="nav-item">
            <a class="nav-link" data-toggle="collapse" href="#layers" role="button">
                            <span class="fas fa-list" aria-hidden="true"></span>
                            <span class="d-md-none d-lg-inline" aria-hidden="true">Layers</span>
          ...

CSS

body {
  /*Account for the height of the navbar component*/
  padding-top: 3.5rem;
}

/*Sets the size and style of the globe container*/

.globe {
  width: 100%;
  height: calc(100vh - 3.5rem);
  background-color: black;
}

/*Sets the position of a container displayed over the globe container*/

.globe-overlay {
  position: absolute;
  width: 100%;
  top: 3.5rem;
}

Sets the background color of Cards displayed over the globe .globe-card {
  background: rgba(255, 255, 255, 0.7);
}

/*When the modal fills the screen it has no margin on top and bottom*/

/*Centers the modal*/

.modal-dialog {
  margin: 0 auto;
}

/*Sets the maximum height of the entire modal to 100% of the screen height*/

.modal-content {
  max-height: 100vh;
}

/*Sets the maximum height of the modal body to 90% of the screen height*/

.modal-body {
  max-height: 90vh;
}

/*Sets the height of a modal's canvas to 30% or 200px*/

.modal-body-canvas {
  max-height: 200px;
  height: 30vh;
}

/*Sets the height of a modal's canvas to 60% minus the height of a footer*/

.modal-body-table {
  max-height: calc(60vh - 71px);
  overflow-y: auto;
}

/* Prevents an element, like a <div/> from consuming user input */

.noninteractive {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  pointer-events: none;
}

/* Allows an element to receive user input */

/* Useful if a parent element is using .noniteractive */

.interactive {
  -webkit-touch-callout: auto !important;
  -webkit-user-select: auto !important;
  -khtml-user-select: auto !important;
  -moz-user-select: auto !important;
  -ms-user-select: auto !important;
  -o-user-select: auto !important;
  pointer-events: auto !important;
}

JavaScript

$(document).ready(function() {
  "use strict";

  // Set the Bing API key for Bing Maps
  // Without your own key you will be using a limited WorldWind developer's key.
  // See: https://www.bingmapsportal.com/ to register for your own key and then enter it below:
  const BING_API_KEY = "";
  if (BING_API_KEY) {
    // Initialize WorldWind properties before creating the first WorldWindow
    WorldWind.BingMapsKey = BING_API_KEY;
  } else {
    console.error("app.js: A Bing API key is required to use the Bing maps in production. Get your API key at https://www.bingmapsportal.com/");
  }
  // Set the MapQuest API key used for the Nominatim service.
  // Get your own key at https://developer.mapquest.com/
  // Without your own key you will be using a limited WorldWind developer's key.
  const MAPQUEST_API_KEY = "";

  /**
   * The Globe encapsulates the WorldWindow object (wwd) and provides application
   * specific logic for interacting with layers.
   * @param {String} canvasId The ID of the canvas element that will host the globe
   * @returns {Globe}
   */
  class Globe {
    constructor(canvasId, projectionName) {
      // Create a WorldWindow globe on the specified HTML5 canvas
      this.wwd = new WorldWind.WorldWindow(canvasId);

      // Projection support
      this.roundGlobe = this.wwd.globe; // The default is a 3D globe
      this.flatGlobe = null;
      if (projectionName) {
        this.changeProjection(projectionName);
      }

      // Holds the next unique id to be assigned to a layer
      this.nextLayerId = 1;

      // Holds a map of category and observable timestamp pairs
      this.categoryTimestamps = new Map();


      // Add a BMNGOneImageLayer background layer. We're overriding the default 
      // minimum altitude of the BMNGOneImageLayer so this layer always available.
      this.addLayer(new WorldWind.BMNGOneImageLayer(), {
        category: "background",
        minActiveAltitude: 0
      });

    }

    /**
     * Returns the...