Skip to content

Side by Side Map

This complete example displays a split view of a movable and zoomable map, embedded inside an html element on a webpage, with each side of the view rendered in a different style, for example, a plain map on the left and satellite imagery on the right.

Overview

The map is centered on a desired initial location, which can be defined either as a point, using a (longitude, latitude) coordinate pair with altitude in meters, or as a bounding box area.
In the case of specifying the region as a bounding box, the (longitude, latitude) coordinates of both the upper left and of the lower right corners of the bounding box rectangle have to be defined.
The map supports pan and zoom, and is fully 3D, so holding down the shift key and panning will simultaneously rotate and tilt the map.
Each map view uses normalized coordinates to define the area of the viewport which it covers.
The center separator can be dragged to the right or to the left, to view the same region on the map in either the style on the left, without imagery in this case, or the style on the right, with imagery.
See the example fullscreen

If you want to jump right in, you can download the HTML file and the JavaScript file and the map style for this example in the same directory, and then load the HTML file in a web browser to try it out right now!

Or you can continue reading for a detailed explanation of the code.

How it works

1// Start by setting your token from https://developer.magiclane.com/api/projects
2gem.core.App.token="your_API_key_token";
The first step in JavaScript is to set your API key token gem.core.App.token, which you can get at the Magic Lane website, see the Getting Started tutorial.
You only need to type your email address and create a new password.
 5var defaultView;
 6var secondView;
 7
 8// The main function
 9gem.core.App.registerInitialCallFunction(function () {
10  // Get app default view
11  dragElement(document.getElementById("viewsSlider"));
12  let defaultScreen = gem.core.App.getDefaultScreen();
13  // View of the map
14  defaultView = defaultScreen.getDefaultMapView();
15  secondView = defaultScreen.createView({ x: 0., y: 0, width: 1.0, height: 1.0 });
16  readBinaryFile(secondView, "./Satellite.style");
17  defaultView.setClippingArea({ x: 0, y: 0, width: 0.5, height: 1.0 });
18  secondView.setClippingArea({ x: 0.5, y: 0, width: 0.5, height: 1.0 });
19  // @see gem.Coordinates
20  var coords = { latitude: 43.6438892, longitude: 9.066603, altitude: 1000000, bearing: 0.0 };
21  defaultView.centerOnCoordinates(coords, 0);
22});
23
24// Initializes the app
25gem.core.App.initApp();
The main function is gem.core.App.registerInitialCallFunction(function() and this is where execution starts.
gem.core.App.getDefaultScreen().getDefaultMapView() loads the default view of the map.
createView is used to make the second view. setClippingArea defines the size of each view, where the containing viewport has normalized coordinates, that is, 0,0 at the top left, and 1,1 at the bottom right, so 0.5,0.5 is the center of the viewport.
A latitude, longitude coordinate pair is defined and defaultView.centerOnCoordinates(coords,0) is used to set the camera at that location.
Altitude is in meters, and bearing(heading) is in degrees, where 0 is north, 90 is east, 180 is south and 270 (or -90) is west.
The 0 is the duration of the camera flight to the specified coordinates, in milliseconds, so the map is instantaneously displayed at the desired location.
26function readBinaryFile(pView, file) {
27  var rawFile = new XMLHttpRequest();
28  rawFile.open("GET", file, true);
29  rawFile.responseType = "arraybuffer";
30  rawFile.onreadystatechange = function () {
31    if (rawFile.readyState === 4) {
32      if (rawFile.status === 200 || rawFile.status == 0) {
33        var arrayBuffer = rawFile.response;
34        if (arrayBuffer) {
35          var byteArray = new Uint8Array(arrayBuffer);
36          pView.updateCurrentStyleFromStyleBuffer(byteArray);
37        }
38      }
39    }
40  }
41  rawFile.send(null);
42}
readBinaryFile loads a map style file which can be created with the online maps studio. The style is only applied to one of the views.
44function dragElement(elmnt) {
45  var pos1 = 0, pos2 = 0;
46  if (document.getElementById(elmnt.id + "header")) {
47    // if present, the header is where you move the DIV from:
48    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
49  } else {
50    // otherwise, move the DIV from anywhere inside the DIV:
51    elmnt.onmousedown = dragMouseDown;
52  }
53  function dragMouseDown(e) {
54    e = e || window.event;
55    e.preventDefault();
56    // get the mouse cursor position at startup:
57    pos2 = e.clientX;
58    document.onmouseup = closeDragElement;
59    // call a function whenever the cursor moves:
60    document.onmousemove = elementDrag;
61  }
62  function elementDrag(e) {
63    e = e || window.event;
64    e.preventDefault();
65    // calculate the new cursor position:
66    pos1 = pos2 - e.clientX;
67    pos2 = e.clientX;
68
69    let parentDiv = elmnt.parentNode;
70    let boundingBox = parentDiv.getBoundingClientRect();
71    let newPosition = elmnt.offsetLeft - pos1;
72    let normalizedPos = newPosition / boundingBox.width;
73    elmnt.style.left = normalizedPos * 100 + "%";
74    defaultView.setClippingArea({ x: 0, y: 0, width: normalizedPos, height: 1.0 });
75    secondView.setClippingArea({ x: normalizedPos, y: 0, width: 1.0 - normalizedPos, height: 1.0 });
76  }
77  function closeDragElement() {
78    // stop moving when mouse button is released:
79    document.onmouseup = null;
80    document.onmousemove = null;
81  }
82}
 1<!DOCTYPE html>
 2<html lang="en-us">
 3  <head>
 4    <meta charset="utf-8" />
 5    <title>Side By Side Map Example - MagicLane Maps SDK for JavaScript</title>
 6    <link rel="stylesheet" type="text/css" href="https://www.magiclane.com/sdk/js/gem.css" />
 7    <style>
 8      body {
 9        overflow: hidden;
10        margin: 0;
11        background-color: white;
12      }
13      .tooltiptext {
14        visibility: visible;
15        width: 240px;
16        background-color: black;
17        color: #fff;
18        text-align: center;
19        border-radius: 6px;
20        padding: 0px 0;
21        position: absolute;
22        z-index: 4 !important;
23        bottom: 150%;
24        left: 50%;
25        margin-left: -120px;
26        display: inline-block;
27      }
28      .tooltiptext::after {
29        content: "";
30        position: absolute;
31        top: 100%;
32        left: 50%;
33        margin-left: -5px;
34        border-width: 5px;
35        border-style: solid;
36        border-color: black transparent transparent transparent;
37      }
38    </style>
39  </head>
40  <body>
41    <div id="wrapper">
42      <div class="profile-main-loader">
43        <div class="loader">
44          <svg class="circular-loader" viewBox="25 25 50 50">
45            <circle class="loader-path" cx="50" cy="50" r="20" fill="none" stroke="#70c542" stroke-width="2" />
46          </svg>
47        </div>
48      </div>
49    </div>
50    <div id="canvasDiv" style="width: 100%; height: 100%; position: absolute; overflow: hidden">
51      <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex="0"></canvas>
52      <div id="viewsSlider" style="width: 5px; height: 100%; left: 50%; top: 0px; cursor: col-resize; background-color: black; position: absolute; z-index: 4 !important"></div>
53    </div>
54    <script src="https://www.magiclane.com/sdk/js/gemapi.js"></script>
55    <script type="text/javascript" src="token.js"></script>
56    <script type="text/javascript" src="jsSideBySide.js"></script>
57  </body>
58</html>
The canvas is the drawing area where the map is rendered. The canvas is configured to fill the browser window.
Note that the div elements must be defined before loading the JavaScript source.
The circular-loader is the rotating circle animation seen while loading.
At the bottom, gemapi.js, the Maps SDK for JavaScript is loaded.
Next, the JavaScript source of this example is loaded.
The example is 2 plain text files, one with the HTML code (.html file extension) and the other with the JavaScript code (.js file extension), and an optional style file (.style file extension) which can be created with the online map studio.
To run the example, the HTML file is loaded in a browser. The .js file should be in the same directory, as it will be loaded automatically.

Source code for this example:

HTML and the JavaScript and the map style

right-click on the links and select Save As.

JavaScript Examples

Maps SDK for JavaScript Examples can be downloaded or cloned with Git