@maplibre/ngx-maplibre-gl
v22.1.0
Published
An Angular binding for maplibre-gl
Readme
Angular wrapper for maplibre-gl. It exposes a bunch of components meant to be simple to use with Angular.
Demo site
Can be found here (based on the generated gh-pages in this repo): https://maplibre.org/ngx-maplibre-gl/
Attribution
This is a fork of ngx-mapbox-gl and I would like to thank the maintainers there for their amazing work to build this up. It's truly a great piece of software!
API Documentation
The API documentation can be found here.
How to start
npm install @maplibre/ngx-maplibre-gl maplibre-gl
yarn add @maplibre/ngx-maplibre-gl maplibre-glThere might be a need to add the following configuration to tsconfig.json file
"compilerOptions": {
...
"strictNullChecks": false,
"skipLibCheck": true,
}Load the CSS of maplibre-gl
For example, with angular-cli add this in angular.json:
"styles": [
...,
"./node_modules/maplibre-gl/dist/maplibre-gl.css"
],Or in the global CSS file (called styles.css for example in angular-cli):
@import 'maplibre-gl/dist/maplibre-gl.css';Serve the MapLibre GL JS web worker
MapLibre GL JS v6 is ESM-only and loads its web worker from a separate file at
runtime. Bundlers cannot rewrite that URL, so every bundler-based app must point
MapLibre at it before the first map is created — see
setWorkerUrl() is bundler-only.
Without it the worker 404s and no tiles render. Here is the Angular setup.
Add both files to the assets of your build target in angular.json. The worker
imports maplibre-gl-shared.mjs as a sibling at runtime, so they must be copied
together, into the same directory:
"assets": [
...,
{
"glob": "maplibre-gl-worker.mjs",
"input": "node_modules/maplibre-gl/dist",
"output": "/"
},
{
"glob": "maplibre-gl-shared.mjs",
"input": "node_modules/maplibre-gl/dist",
"output": "/"
}
]Then provide the worker URL with provideMaplibreWorker in your application config:
import { ApplicationConfig } from '@angular/core';
import { provideMaplibreWorker } from '@maplibre/ngx-maplibre-gl/config';
export const appConfig: ApplicationConfig = {
providers: [provideMaplibreWorker('maplibre-gl-worker.mjs')],
};The URL is resolved against document.baseURI, so it stays correct when your app
is deployed under a sub-path via --base-href. It can also be provided in a
component's providers to scope it to a subtree. The URL is applied lazily, right
before the first map is created — unlike calling setWorkerUrl() in main.ts,
this keeps maplibre-gl out of your initial bundle.
If you cannot use the provider, call setWorkerUrl() once yourself before the
first map is created instead:
import { setWorkerUrl } from 'maplibre-gl';
setWorkerUrl(new URL('maplibre-gl-worker.mjs', document.baseURI).href);If you also run browser-based unit tests, do the same in your test setup file. When
tests are served by Vite, a ?url import resolves the worker straight out of
node_modules:
import { setWorkerUrl } from 'maplibre-gl';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?url';
setWorkerUrl(new URL(workerUrl, document.baseURI).href);Upgrading MapLibre GL JS
Upgrading from v5? Follow the v5 to v6 migration guide.
Breaking change: camera inputs are plain values
[zoom], [bearing], [pitch] and [roll] took a single-element array, so that
re-assigning the same number still counted as a change. They are now plain numbers,
and two-way capable:
- <mgl-map [zoom]="[9]" [pitch]="[45]" [bearing]="[-17.6]" />
+ <mgl-map [zoom]="9" [pitch]="45" [bearing]="-17.6" />Updating one axis has never dragged the others back with it - that is handled by only sending the axes that actually changed - so nothing else changes for one-way bindings.
If you relied on the array to return the map to a position the user had since moved away from, bind two-way instead. The camera models follow the map, so the earlier value is a real change again:
<mgl-map [(zoom)]="zoom" [(center)]="center" />Then, in your app's main module (or in any other module), import the MapComponent:
import { Component } from '@angular/core';
import { MapComponent } from '@maplibre/ngx-maplibre-gl';
@Component({
template: `
<mgl-map
[mapStyle]="'https://demotiles.maplibre.org/style.json'"
[zoom]="9"
[center]="[-74.5, 40]"
>
</mgl-map>
`,
styles: [
`
mgl-map {
height: 100%;
width: 100%;
}
`,
],
imports: [MapComponent],
})
export class AppComponent {}If you use several components, it will be convenient to import NgxMapLibreGLModule instead:
import { Component } from '@angular/core';
import { NgxMapLibreGLModule } from '@maplibre/ngx-maplibre-gl';
@Component({
template: `
<mgl-map
[mapStyle]="'https://demotiles.maplibre.org/style.json'"
[zoom]="9"
[center]="[-74.5, 40]"
>
<mgl-control
mglNavigation
[visualizePitch]="true"
/>
</mgl-map>
`,
styles: [
`
mgl-map {
height: 100%;
width: 100%;
}
`,
],
imports: [NgxMapLibreGLModule]
})
export class AppComponent {}