LoginSignup
1
0

More than 1 year has passed since last update.

(For beginner) Guidance on Making a 3D webmap with MapLibre GL JS

Last updated at Posted at 2022-09-14

Introduction

I would like to demonstrate how we can create a webmap with MapLibre GL JS. The main target of this text is for the beginners.

This document will explain:

  • How we create a simple 2D webmap with MapLibre GL JS from existing vector tile and style
  • How we exmapnd 2D map to a terrain 3D map with existing RGB elevation tiles.

but it will not explain:

  • How we create vector tiles
  • Howe we develop RGB raster tiles
  • How we develop map styles
  • How we prepare text fonts (glyphs) or map symbols (sprite)

For the issues I do not explain here, I have another materials, so please feel free to visit my GitHub repository or my speaker deck.

Note added on 2022-09-22

We have YouTube movie for this hands-on.

Environment

My working environment is as follows:

  • Windows 10 Enterprise
  • Windows PowerShell
  • Page hosting via GitHub page

Procedure

Step 1: Making a GitHub repository

Create a repository for this practice. I have created a repository here:
https://github.com/ubukawa/practice-bm

Then, let's create a "docs" directory to store the files for web hosting, and move there.

mkdir docs
cd docs

Step 2: Getting the latest MapLibre GL JS

Let's check the latest version of MapLibre GL JS here https://github.com/maplibre/maplibre-gl-js. As of the 13th September 2022, the latest version is 2.4.0. Then, get these files from unpkg.org with the following command in the PowerShell. Let's also get the license text from maplibre.

mkdir maplibre-gl@2.4.0
cd maplibre-gl@2.4.0
curl.exe -O https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js
curl.exe -O https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js.map
curl.exe -O https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css
curl.exe -O https://raw.githubusercontent.com/maplibre/maplibre-gl-js/main/LICENSE.txt
cd ..

image.png

You will have files as below.
image.png

Step 2: Consider map styles

If you are getting familiar with the MapLibre/Mapbox webmaps, you can freely design map style by writing style.json (or json file with any other name) following the MapLibre/Mapbox style specification.

A style json generally has rich information on the map styling, I mean style layers information. In addition, I think it is important to understand that a tyle json has information on:

  • data source (vector, raster, WMS, etc..),
  • map symbol (sprite),
  • text font (glyphs),
  • and others

This time, let's use existing style file (json format) for easy understanding. From my past practice, I have three different styles as below.

Step 3: Preparing html file

Now, we have 1) a map library, that is MapLibre GL JS, and 2) style information that is confirmed at the previous step. So, let's make a html file to draw a webmap.

Under the "docs" directory, where is the root of the GitHub page, let's create a "map1.html" as below.

map1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map - Practice 1</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="./maplibre-gl@2.4.0/maplibre-gl.js"></script>
<link href="./maplibre-gl@2.4.0/maplibre-gl.css" rel="stylesheet" />
<style>
    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = new maplibregl.Map({
container: 'map', // container id
style: 'https://ubukawa.github.io/vt-test/maps/test-simple.json', // style URL
//center: [140.084556, 36.104611], // you can specify starting position if you want [lng, lat]
//zoom: 7, // starting zoom
//maxZoom: 4, // min zoom
maxZoom: 14 // max zoom of the map
});

//UI
map.addControl(new maplibregl.NavigationControl(), 'bottom-right');
map.addControl(new maplibregl.GeolocateControl({positionOptions: {enableHighAccuracy: true},trackUserLocation: true}), 'top-right');
map.addControl(new maplibregl.ScaleControl() );

//debug
//map.showTileBoundaries = true;
//map.showCollisionBoxes = true;
</script>
</body>
</html>

image.png
Once you make it, please push your edit to your GitHub repository.
image.png

Don't forget to enable GitHub page at your repository.
image.png

Now, you will see a map like this. Please note that the boundaries in the map are not authorized by any agencies. We are now refering to the style of a small scale map, but we can change the reference to any other style hosted in the Internet.
image.png

Let's try to change the referred style from the first one to the second one. You just need to slightly edit the style in the map. We can also change the maxZoom of the map because the second one is larger map than the first one. Edit it as below, and push it and wait for awhile. It might be a good idea to save the revised file as map2.html.

Part of map2.html (in the script at the body)
var map = new maplibregl.Map({
container: 'map', // container id
style: 'https://ubukawa.github.io/practice-bm/srtm.json', // style URL
maxZoom: 19 // max zoom of the map
});

Then, you will see the map like this. This map is based on the vector tile converted from OSM data, and hillshade, derived from RGM elevation tile converted from SRTM 1 sec DEM, is added for certain area. I did not upload the RGB elevation tile for the whole area, so you will find the area with hillshade is limited.
image.png

These styles with raster-dem source are ready to go for terrain 3D expression by MapLibre.

Step 4: Create a webmap with terrain 3D expression

Before making a 3D terrain map, please make sure that you have proper raster-dem source. If you have any suitable RGB elevation source in the style file, it is perfect. It is also possible to separately add the RGB elevation source within a html's script.

Case 1: Adding the source and setting the terrain within html script

Let's copy map2.html as map3.html. Then, let's add map.addSource to add a terrain source and map.setTerrain to set the terrain 3D. Let's add the followings to the map3.html

part of map3.html (after var map is defined)
//for 3D terrain
map.on('load', () => {
 map.addSource("terrain3D",{
   "type": "raster-dem",
   "tiles": ["https://ubukawa.github.io/srtm-rgb-nyc/zxy/{z}/{x}/{y}.png"],
   "attribution": "RGB Elevation from SRTM DEM - 1 second (USGS)",
   "tileSize": 256,
   "maxzoom": 12,
   "minzoom": 4
 });
 map.setTerrain({
   source: "terrain3D",
   exaggeration: 1
 });
});

Let's also add maxPitch (to 85) and hash setting to the map so that we can handle map easily. Please see below.

var map = new maplibregl.Map({
container: 'map', // container id
style: 'https://ubukawa.github.io/practice-bm/srtm.json', // style URL
maxZoom: 19, // max zoom of the map
maxPitch: 85,
hash: true
});

You can see the actual html and demo site from:
html: https://github.com/ubukawa/practice-bm/blob/main/docs/map3.html
demo: https://ubukawa.github.io/practice-bm/map3.html

Now, because we enable hash, you can see the zoom level, lat, long, nearing, and pitch as the URL path.

For example, you can see the Bear Mountain and Hessian Lake in New York States here: https://ubukawa.github.io/practice-bm/map3.html#16.18/41.31329/-73.993859/-60.1/74
image.png

Case 2: Adding the source and setting the terrain in style file

Instead of adding the source and setting the terrain in html script, we can also define them in the style file. Let's copy the original style file to edit and save in your repository.

The edited style only have an additional source for terrain, and terrain setting. And, by simply referring to this style, we can create a 3D map. (You do not have to add map.on function here.)

html: https://github.com/ubukawa/practice-bm/blob/main/docs/map4.html
demo: https://ubukawa.github.io/practice-bm/map4.html

You may see the same map with the previous case.
image.png

some note on 3D terrain:

Because the MapLibre GL JS is derived from Mapbox GL JS version 1.X, regarding the basic map creation, you can do the almost same things with Mapbox GL JS and Mapbox GL JS. However, the terrain 3D expression is somehow different between MapLibre and Mapbox due to the change of the license of the Mapbox's license after its version 2.0.

One more practice: Plug-in

I got a request of using a comparing tool, so let's quickly go through "maplibre-gl-compare" plug-in.

Preparation of the maps to compare

Here, I have prepared two maps for the comparison.

We have the following two maps with the above two styles.
https://ubukawa.github.io/practice-bm/comp-map1.html
https://ubukawa.github.io/practice-bm/comp-map2.html
image.png
If you want to know how to develop Sentinel 2 raster tile with FOSS4G tool, I have another article here (in Japanese. Use translator): https://qiita.com/T-ubu/items/de0d30e0f2bdcd72ee8a

Downloading "maplibre-gl-compare"

Let's get the plug-in files from https://github.com/maplibre/maplibre-gl-compare. We will use maplibre-gl-compare.js, maplibre-gl-compare.css, and license.txt, but cloning whole repository woudl be easier. Let's run "git clone" at your docs directory.

git clone https://github.com/maplibre-maplibre-gl-compare

image.png

Then, you will have JS and CSS files under "maplibre-gl-compare/dist" directory.
image.png

Then, keep the "dist" directory and the license.txt, and delete other files.
image.png

Preparing a html file to compare

Referring to some example, we can create a simple comparison map as below:

comp-map.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map - map for compare</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="./maplibre-gl@2.4.0/maplibre-gl.js"></script>
<link href="./maplibre-gl@2.4.0/maplibre-gl.css" rel="stylesheet" />
<script src="./maplibre-gl-compare/dist/maplibre-gl-compare.js"></script>
<link href="./maplibre-gl-compare/dist/maplibre-gl-compare.css" rel="stylesheet" />
<style>
    body { margin: 0; padding: 0; overflow: hidden; }
    body * {webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
    .map { position: absolute; top: 0; bottom: 0; width: 100%; }
    .controls { position: absolute; top: 0; right: 0; }
</style>
</head>
<body>
 <div id="wrapper">
   <div id="map1" class="map"></div>
   <div id="map2" class="map"></div>
 </div>
<script>
var map1 = new maplibregl.Map({
  container: "map1",
  style: "https://ubukawa.github.io/osm-neighbor/style.json",
  zoom: 9,
  center: [-73.8128, 40.8513], // center [lng, lat]
  maxZoom: 0, // min zoom
  maxZoom: 16, // max zoom
  hash: true
});

var map2 = new maplibregl.Map({
  container: "map2",
  style: "https://ubukawa.github.io/practice-bm/style-sentinel-ny.json",
  zoom: 9,
  center: [-73.8128, 40.8513], // center [lng, lat]
  maxZoom: 0, // min zoom
  maxZoom: 16, // max zoom
  hash: true
});

var wrapperSelector = "#wrapper";
var wrapperElement = document.body.querySelectorAll("#wrapper")[0];

var options = {
  mousemove: false, 
  orientation: "vertical", //horizontal 
};

var map = new maplibregl.Compare(
  map1,
  map2,
  wrapperSelector,
  options
);

map1.addControl(new maplibregl.ScaleControl(), 'bottom-left' );
map1.addControl(new maplibregl.NavigationControl(), 'bottom-left');

</script>
</body>
</html>

I noticed the followings things when I worked on the above file.

  • Reference to the maplibre-gl-compare.js and maplibre-gl-compare.css are added.
  • style for body *, .map are added. (I omitted the controls, but keep .control in the style.)
  • Instead of "map", "wrapper" div is used and it includes the map1 and map2, which are the maplibre.Map.
  • Elements of the map1 and map2 are difined. It would be good to use a common set of parameters to avoid confusion.
  • There are some options for maplibregl.Compare. We could explore them in the future.
  • control elements are added to the map1, not wrapper. I have not yet tested to add controls to the wrapper though.

You will see a map like this.
image.png

You can see the area around the Bear Mountain at: https://ubukawa.github.io/practice-bm/comp-map.html#13.62/41.31192/-73.99523
image.png

Congratulation. This is the end of our practice.

Summary

Thus, we can create a webmap with 3D terrains powered by MapLibre. We also can try a simple comparison plugin.

References

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0