<html>
<link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" type="text/css" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>

  <!-- Add references to the Azure Maps Map Drawing Tools JavaScript and CSS files. -->
  <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/drawing/0/atlas-drawing.min.css" type="text/css" />
  <script src="https://atlas.microsoft.com/sdk/javascript/drawing/0/atlas-drawing.min.js"></script>

<body>
  <div id="map"></div>
  
  <img id="loadingIcon" src="https://assets.codepen.io/1717245/loadingIcon.gif" title="Loading" style="position:absolute;left:calc(50% - 25px);top:calc(50% - 25px);display:none;" />
  
  <div id="legend">
		<div style="font-size:14px;font-weight:bold;">Elevation</div>
		<div style="float:left">
			<div class="colorSquare" style="background-color:#d7191c"></div>
			<div class="colorSquare" style="background-color:#fdae61"></div>
			<div class="colorSquare" style="background-color:#ffffbf"></div>
			<div class="colorSquare" style="background-color:#a6d96a"></div>
			<div class="colorSquare" style="background-color:#1a9641"></div>
		</div>
		<div style="float:left;margin:9px 5px 0 5px;">
			<div class="colorSquare">200m</div>
			<div class="colorSquare">150m</div>
			<div class="colorSquare">100m</div>
			<div class="colorSquare">50m</div>
		</div>
	</div>
  
  <div style="position:absolute;top:0px;left:calc(50% - 100px);background-color:white;padding:5px;">Draw rectangle on the map</div>
</body>

</html>
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

#map {
  width: 100%;
  height: 100%;
}

#legend {
	position: absolute;
	top: 10px;
	right: 10px;
	background-color: white;
	border-radius: 10px;
	padding: 10px;
	font-size: 11px;
}

.colorSquare {
	width: 16px;
	height: 16px;
	text-align: center;
}
var map, datasource, layer, drawingManager;

var elevationBoundsUrl = 'https://{azMapsDomain}/elevation/lattice/json?api-version=1.0&bounds={bounds}&rows={rows}&columns={columns}';

var maxSamples = 2000;
var colors = ['#006837', '#1a9850', '#66bd63', '#a6d96a', '#d9ef8b', '#ffffbf', '#fee08b', '#fdae61', '#f46d43', '#d73027', '#a50026'];

//Initialize a map instance.
map = new atlas.Map('map', {
  center: [-119.949, 46.53],
  zoom: 12,
  style: 'satellite',
  view: "Auto",
  //Add your Azure Maps subscription client ID to the map SDK. 
  authOptions: {
    authType: "anonymous",
    clientId: "04ec075f-3827-4aed-9975-d56301a2d663", //Your Azure Maps account Client ID is required to access your Azure Maps account.

    getToken: function (resolve, reject, map) {
      //URL to your authentication service that retrieves an Azure Active Directory Token.
      var tokenServiceUrl = "https://azuremapscodesamples.azurewebsites.net/Common/TokenService.ashx";

      fetch(tokenServiceUrl).then(r => r.text()).then(token => resolve(token));
    }
  }
});

//Wait until the map resources are ready.
map.events.add('ready', function () {
  //Create a data source for the route line.
  datasource = new atlas.source.DataSource();
  map.sources.add(datasource);

  //Create a layer for rendering the elevation points.
  layer = new atlas.layer.BubbleLayer(datasource, null, {
    color: [
      'interpolate',
      ['linear'],
      ['get', 'elevation'],
      400, '#006837',
      450, '#1a9850',
      500, '#66bd63',
      550, '#a6d96a',
      600, '#d9ef8b',
      650, '#ffffbf',
      700, '#fee08b',
      750, '#fdae61',
      800, '#f46d43',
      850, '#d73027',
      900, '#a50026'
    ],

    //Don't outline the bubbles. This will make them blend together to create a heat map like visual.
    strokeWidth: 0
  });
  map.layers.add(layer);

  //Create an instance of the drawing manager and display the line drawing option of the drawing toolbar.
  drawingManager = new atlas.drawing.DrawingManager(map, {
    toolbar: new atlas.control.DrawingToolbar({
      buttons: ['draw-rectangle'],
      position: 'top-left',
      style: 'light'
    })
  });

  ///Clear the map and drawing canvas when the user enters into a drawing mode.
  map.events.add('drawingmodechanged', drawingManager, drawingModeChanged);

  //Monitor for when a rectangle drawing has been completed.
  map.events.add('drawingcomplete', drawingManager, getElevations);
});

function drawingModeChanged(mode) {
  //Clear the drawing canvas and data source.
  if (mode.startsWith('draw')) {
    drawingManager.getSource().clear();
    datasource.clear();
  }
}

function getElevations(rectangle) {
  //Exit drawing mode and clear the drawing canvas.
  drawingManager.setOptions({ mode: 'idle' });
  drawingManager.getSource().clear();

  //Get the bounding box of the rectangle.
  var bbox = rectangle.getBounds();

  //Get the width and height of the bounding box in meters.
  var nw = atlas.data.BoundingBox.getNorthWest(bbox);
  var width = atlas.math.getDistanceTo(nw, atlas.data.BoundingBox.getNorthEast(bbox));
  var height = atlas.math.getDistanceTo(nw,  atlas.data.BoundingBox.getSouthWest(bbox));

  //In this sample we want to create an evenly distributed grid, so aspect ratio will be used to determine the number of requires rows/columns.
  var aspectRatio = width / height;   

  //The square root of the max number of samples, gives use the number of row/columns for a perfect square. Apply the square root of the aspect ratio to this to handle rectangles.
  var numRows = Math.floor(Math.sqrt(maxSamples / aspectRatio));
  var numColumns = Math.floor(Math.sqrt(maxSamples * aspectRatio));

  //Format line coordinates as "SouthwestCorner_Longitude,SouthwestCorner_Latitude,NortheastCorner_Longitude,NortheastCorner_Latitude"
  var bounds = bbox.join(',');

  var url = elevationBoundsUrl.replace('{bounds}', bounds).replace('{rows}', numRows).replace('{columns}', numColumns);

  //Show loading icon.
  document.getElementById('loadingIcon').style.display = '';

  processRequest(url).then(response => {
    if (response.error) {
      alert(response.error.message);
      return;
    }

    var points = [];
    var minElv = Infinity;
    var maxElv = -Infinity;

    //Loop through the elevations, create point features with an elevation property and calculate min/max elevation.
    response.data.forEach(c => {
      points.push(new atlas.data.Feature(new atlas.data.Point([c.coordinate.longitude, c.coordinate.latitude]), {
        elevation: c.elevationInMeter
      }));

      if (c.elevationInMeter < minElv) {
        minElv = c.elevationInMeter;
      }

      if (c.elevationInMeter > maxElv) {
        maxElv = c.elevationInMeter;
      }
    });

    //Calculate a new style expression based on the 
    updateStyle(minElv, maxElv);

    //Overwrite the points to the data source.
    datasource.setShapes(points);

    //Hide loading icon.
    document.getElementById('loadingIcon').style.display = 'none';
  });
}

function updateStyle(minElv, maxElv) {
  //Get the difference between min/max elevation.
  var de = maxElv - minElv;

  //If the difference is 0, set de to 1 to prevent devide by zero issues.
  if (de === 0) {
    de = 1;
  }

  var elvStep = de / colors.length;

  var exp = [
    'interpolate',  //This will cause the colors from each data point to create a gradient between points.
    ['linear'],
    ['get', 'elevation'],
  ];

  for (var i = 0; i < colors.length; i++) {
    //Set the elevation interval and its color.
    exp.push(minElv + elvStep * i, colors[i]);
  }

  layer.setOptions({ color: exp });

  //Create legend, with highest value first.

  //Determine a reasonable value to round by.
  var roundFactor = (de < 10) ? 10 : 1;

  var colorSquares = [];
  var elvSteps = [];

  for (var i = colors.length; i >= 0; i--) {
    colorSquares.push(`<div class="colorSquare" style="background-color:${colors[i]}"></div>`);
    elvSteps.push(`<div class="colorSquare">${Math.round((minElv + elvStep * i) * roundFactor) / roundFactor}m</div>`);
  }

  var legend = [
    '<div style="font-size:14px;font-weight:bold;">Elevation</div><div style="float:left">',
    ...colorSquares,
    '</div><div style="float:left;margin:9px 5px 0 5px;">',
    ...elvSteps,
    '</div></div>'
  ];

  document.getElementById('legend').innerHTML = legend.join('');
}

function processRequest(url) {
  return new Promise((resolve, reject) => {
    //Replace the domain placeholder to ensure the same Azure Maps cloud is used throughout the app.
    url = url.replace('{azMapsDomain}', atlas.getDomain());

    //Get the authentication details from the map for use in the request.
    var requestParams = map.authentication.signRequest({ url: url });

    //Transform the request.
    var transform = map.getServiceOptions().tranformRequest;
    if (transform) {
      requestParams = transform(request);
    }

    fetch(requestParams.url, {
      method: 'GET',
      mode: 'cors',
      headers: new Headers(requestParams.headers)
    })
      .then(r => r.json(), e => reject(e))
      .then(r => {
      resolve(r);
    }, e => reject(e));
  });
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.