Skip to content

eschricker/ngx-mapbox-gl

 
 

Repository files navigation

ngx-mapbox-gl

Build Status npm version

Angular wrapper for mapbox-gl-js. It exposes a bunch of components meant to be simple to use with Angular.

v1.X : Angular 5 & 6 (rxjs 5)

v2.X : Angular 6 & 7 (rxjs 6)

v3.X : Angular 7.2

v4.X : Angular 8 - 10 (rxjs >= 6.5)

v5.X - 6.X : Angular 9 - 11 (rxjs >= 6.5)

v7.X : Angular 12 (rxjs >= 6.6)

Include the following components:

How to start

npm install ngx-mapbox-gl mapbox-gl
yarn add ngx-mapbox-gl mapbox-gl

If using typescript add mapbox-gl types

npm install @types/mapbox-gl --save-dev
yarn add @types/mapbox-gl --dev

Load the CSS of mapbox-gl (and mapbox-gl-geocoder if mglGeocoder is used)

For example, with angular-cli add this in angular.json:

"styles": [
        ...
        "./node_modules/mapbox-gl/dist/mapbox-gl.css",
        "./node_modules/@mapbox/mapbox-gl-geocoder/lib/mapbox-gl-geocoder.css"
      ],

Or in the global CSS file (called styles.css for example in angular-cli):

@import '~mapbox-gl/dist/mapbox-gl.css';
@import '~@mapbox/mapbox-gl-geocoder/lib/mapbox-gl-geocoder.css';

Add this in your polyfill.ts file (Wykks#136 (comment)):

(window as any).global = window;

Then, in your app's main module (or in any other module), import the NgxMapboxGLModule:

...
import { NgxMapboxGLModule } from 'ngx-mapbox-gl';

@NgModule({
  imports: [
    ...
    NgxMapboxGLModule.withConfig({
      accessToken: 'TOKEN', // Optional, can also be set per map (accessToken input of mgl-map)
      geocoderAccessToken: 'TOKEN' // Optional, specify if different from the map access token, can also be set per mgl-geocoder (accessToken input of mgl-geocoder)
    })
  ]
})
export class AppModule {}

How to get a Mapbox token: https://www.mapbox.com/help/how-access-tokens-work/

Note: mapbox-gl cannot work without a token anymore. If you want to keep using their services then make a free account, generate a new token for your application and use it inside your project.

You can use https://github.com/klokantech/tileserver-gl to serve vector tiles.

Display a map:

import { Component } from '@angular/core';

@Component({
  template: `
    <mgl-map
      [style]="'mapbox://styles/mapbox/streets-v9'"
      [zoom]="[9]"
      [center]="[-74.5, 40]"
    >
    </mgl-map>
  `,
  styles: [
    `
      mgl-map {
        height: 100%;
        width: 100%;
      }
    `,
  ],
})
export class DisplayMapComponent {}

Angular libraries AOT compilation

If you want to build a library using this module, you will most likely face this error when building for production:

ERROR: Error during template compile of 'YourLibraryModule'
  Function calls are not supported in decorators, but 'NgxMapboxGLModule' was called.

An unhandled exception occurred: Error during template compile of 'YourLibraryModule'
  Function calls are not supported in decorators, but 'NgxMapboxGLModule' was called.

This error is generated due to the AOT compilation that occurs in prod mode. The part that will generate the error will be this one:

@NgModule({
  imports: [
    ...
    NgxMapboxGLModule.withConfig({
      accessToken: 'TOKEN',
      geocoderAccessToken: 'TOKEN'
    })
  ]
})

So the error is pretty clear: Function calls are not supported in decorators but 'NgxMapboxGLModule' was called.

Solution

To solve this problem, we simply need to provide the accessToken via module configuration rather than how you would normally do:

import {
  MAPBOX_API_KEY, // ngx-mapbox-gl uses this injection token to provide the accessToken
  NgxMapboxGLModule,
} from 'ngx-mapbox-gl';

export interface IMyLibMapModuleConfig {
  mapboxToken: string;
}

@NgModule({
  declarations: [],
  exports: [],
  imports: [CommonModule, NgxMapboxGLModule],
})
export class MyLibMapModule {
  static forRoot(
    config: IMyLibMapModuleConfig
  ): ModuleWithProviders<MyLibMapModule> {
    return {
      ngModule: MyLibMapModule,
      providers: [
        {
          provide: MAPBOX_API_KEY,
          useValue: config.mapboxToken,
        },
      ],
    };
  }
}

We basically create a forRoot static function in the library module, that will accept a configuration object as a parameter. This configuration will provide the actual token to the ngx-mapbox-gl module via providers by providing the value from the configuration to the MAPBOX_API_KEY injection token.

Finally, in the application that will use your MyLibMapModule, you will import the module in this way:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { MyLibMapModule } from 'my-lib';

@NgModule({
  declarations: [AppComponent],
  imports: [
    CommonModule,
    AppRoutingModule,

    MyLibMapModule.forRoot({
      mapboxToken: environment.mapboxToken,
    }),
  ],
})
export class AppModule {}

About

Angular binding of mapbox-gl-js

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 96.6%
  • JavaScript 1.6%
  • Other 1.8%