Creating a Maplibre application using a self hosted basemap

Image alt

In this article, we will walk through the process of creating a MapLibre GL JS application using offline tiles. We will use a Vite vanilla TypeScript project as our baseline. We will start from the very beginning and get a working map visualization with offline tiles.

Setup

First, let's set up a new Vite project with TypeScript.

npm create vite@latest maplibre-offline-tiles -- --template vanilla-ts
cd maplibre-offline-tiles
npm install

Installing MapLibre GL JS

Next, we need to install MapLibre GL JS and its TypeScript types.

npm install maplibre-gl

Configuring MapLibre GL JS

Unlike CesiumJS, MapLibre GL JS doesn't require special configuration with Vite. We just need to import the CSS file in our main TypeScript file.

Create the tiles server

We will use the pmtiles format to serve the tiles. pmtiles is a simple, fast, and efficient format for storing tiled map data. In order to serve it we are going to acces directly the pmtiles file from the application, this approach can also be used by deploying the file to an S3 compatible file storage.

We are going to use the serve npm package:

npm install --global serve

Then we just run it where we have save our pmtiles file. We allow CORS to * by using the -C parameter.

serve -C

We can use the pmtiles provided by Keimaps as an starting point. They can be obtained here.

Consuming the pmtile file

To use pmtiles with MapLibre GL JS, we need to install the pmtiles library:

npm install pmtiles

Example Code

Now, let's update our main.ts file to initialize MapLibre GL JS with the offline tiles.

import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { Protocol } from 'pmtiles';

// Register the pmtiles protocol
const protocol = new Protocol();
maplibregl.addProtocol("pmtiles", protocol.tile);

// Initialize the MapLibre GL JS map
const map = new maplibregl.Map({
  container: 'map',
  style: {
    version: 8,
    sources: {
      'offline-tiles': {
        type: 'raster',
        url: 'pmtiles://http://localhost:3000/satellite.pmtiles',
        tileSize: 256,
      },
    },
    layers: [
      {
        id: 'offline-layer',
        type: 'raster',
        source: 'offline-tiles',
      },
    ],
  },
  center: [0, 0],
  zoom: 2,
});

// Add navigation controls
map.addControl(new maplibregl.NavigationControl());

Update the index.html file to include a container for the MapLibre GL JS map.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MapLibre GL JS Offline Tiles</title>
    <style>
      body { margin: 0; padding: 0; }
      #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

This setup will create a MapLibre GL JS map using offline tiles stored in a PMTiles file. Make sure to replace 'http://localhost:3000/satellites.pmtiles' with the actual path to your PMTiles file.

Remember to serve your PMTiles file from a local server or adjust the URL accordingly if you're hosting it elsewhere.