Getting started with MapLibre
Installation#
The free packages are on npm at version 0.1.0 (all packages). Install them with the command below.
npm install @vectorstream/core @vectorstream/editor @vectorstream/maplibre maplibre-gl
maplibre-gl is a peer dependency (^6.11.0); @vectorstream/adapter comes along with
@vectorstream/maplibre.
The complete example#
A real file of this repository (docs/handbuch/beispiele/maplibre-quickstart.ts); a test in a real
browser draws a triangle through it, exports, undoes and switches tools by key. The test passes an
empty style instead of osmStyle so it fetches no tiles.
import * as maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { exportGeoJSON, importGeoJSON, type FeatureCollection } from '@vectorstream/core';
import { Editor, Toolbar, defaultToolbarEntries } from '@vectorstream/editor';
import { MapLibreAdapter } from '@vectorstream/maplibre';
/** A raster style with OpenStreetMap tiles. Any MapLibre style works. */
export const osmStyle: maplibregl.StyleSpecification = {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap contributors',
},
},
layers: [{ id: 'osm', type: 'raster', source: 'osm' }],
};
export function startEditor(container: HTMLElement, data: FeatureCollection, style = osmStyle) {
// 1. The map. MapLibre counts zoom in 512-pixel tiles: 16 here shows what 17 shows in Leaflet.
const map = new maplibregl.Map({ container, style, center: [7.4555, 51.5112], zoom: 16 });
// 2. The adapter may be created right away; it adds its sources and layers once the style loads.
const adapter = new MapLibreAdapter(map);
// 3. The editor works on a partition — here one built from GeoJSON.
const editor = new Editor(importGeoJSON(data), adapter);
// 4. The toolbar is state, not UI: it knows the tools and their shortcut keys.
const toolbar = new Toolbar(editor, defaultToolbarEntries());
toolbar.select('draw');
// 5. Every transaction ends in exactly one of three events.
editor.on('change', ({ label }) => console.log('changed:', label));
editor.on('unchanged', ({ label }) => console.log('nothing to do:', label));
editor.on('rejected', ({ label, violations }) => {
console.warn('rejected:', label, violations.map((v) => v.detail));
});
return {
map,
editor,
toolbar,
// 6. Export the active layer as GeoJSON.
save: (): FeatureCollection => exportGeoJSON(editor.partition),
// 7. Undo and redo; `false` means there was nothing to do, or the step was rejected.
undo: (): boolean => editor.undo(),
redo: (): boolean => editor.redo(),
destroy(): void {
toolbar.destroy();
editor.destroy();
adapter.destroy();
map.remove();
},
};
}
The steps are the same as on Getting started with Leaflet: map, adapter, editor, toolbar, events, export, undo. Only the map and the adapter differ.
MapLibre specifics#
- Create the adapter right away. You do not have to wait for the map's
loadevent: the adapter adds its sources and layers as soon as the style has loaded, and adds them again after every later style change (map.setStyle(…)). - Zoom levels. MapLibre counts zoom in 512-pixel tiles. Zoom 16 in MapLibre shows the same scale as zoom 17 in Leaflet or OpenLayers.
- No rotation, no pitch. While the adapter exists, it disables drag-rotate, touch pitch,
two-finger rotation and keyboard rotation; the editor assumes north is up.
adapter.destroy()restores what was enabled before. - Pointer events are taken from the map container. A press only counts on the map canvas
(not on a zoom button); a drag that started on the map keeps going over the controls. Keys come
from
keydownon the document, except while typing in an input field, text area, select box orcontenteditableelement. - Stacking. The adapter sets
isolation: isolateon the canvas container, so its markers and labels stay below MapLibre's controls and popups;destroy()restores the previous value. - The worker in a Vite build. MapLibre loads a web worker from a URL next to its own file. The
application in this repository (
app/) tells MapLibre where that file is, before the first map is created:maplibregl.setWorkerUrl(url), withurlimported asmaplibre-gl/dist/maplibre-gl-worker.mjs?worker&url(a Vite import suffix). Without it, Vite cannot see the worker file, and it is missing from the built bundle. - Tested version. The adapter is tested with MapLibre GL JS 6.11.2. It reads one internal field of MapLibre's style to know whether the style has loaded; a test fails if a MapLibre version removes it.
- Options.
new MapLibreAdapter(map, { ebenenFarbe })— the color of a layer, as with Leaflet.
Next: Faces and edges, Modes, API reference: MapLibreAdapter.