Integrating Leaflet Plugins with ngx-leaflet
A Step-by-Step Guide
Mar 01, 2018

One of the awesome things about Leaflet is that it is extensible and customizable. There are hundreds of plugins that add custom layers, controls, and utilities. This is a large part of why Leaflet is so popular and why we built ngx-leaflet.

We get a lot of questions about Leaflet plugin integration on Github and Stack Overflow. Often, we’ll include a ton of example code and configuration in the answers, but it isn’t centrally located or easy to find. As a result, we made a project on GitHub as a central location for integration examples. This article provides an intro to the ngx-leaflet-tutorial-plugins project and describes the process of Leaflet plugin integration with ngx-leaflet.

Introduction

In the ngx-leaflet-tutorial-plugins project, you’ll find several projects that show how to integrate ngx-leaflet with different Leaflet plugins. Each project has a working Angular CLI example as well as a README with instructions. The included projects are listed below. If we haven’t covered the specific plugin you’re interested in, you can still review this article and the example projects for helpful information.

Leaflet.Coordinates

Leaflet.Coordinates is a custom control that displays the coordinates of the mouse on the map. In addition, the user can drop markers at specific locations and see the coordinates of the position.

Leaflet.Coordinates displays the current mouse coordinates on the map

Leaflet.Path.Transform

Leaflet.Path.Transform extends existing Leaflet functionality. It allows users to drag, rotate, and scale vector features on the map.

Leaflet.Path.Transform adds the ability to manipulate vector features on the map

Leaflet.TimeDimension

Leaflet.TimeDimension is a really cool plugin that allows you to present time-based animated map features (e.g., time-based weather radar). And, it provides controls so the user can start and stop playback.

Leaflet.TimeDimension provides animated playback of map features

heatmap.js

heatmap.js adds custom heatmap layers to Leaflet.

heatmap.js presents data as a heatmap overlay on top of the map

Working with Leaflet Plugins and Angular.io

Leaflet plugins extend the functionality of Leaflet. Often, they add custom controls, layers, or utilities. Using Leaflet plugins outside of Angular is simple when Leaflet is exposed as the L variable. But, it gets more complicated with module systems (e.g., UMD, ES6 Modules, etc.), module bundlers (e.g., Webpack, Rollup, etc.), and Typescript. The rest of this article presents the general process of integrating Leaflet plugins into Angular CLI projects that use ngx-leaflet.

Installation and Dependency Management

The first step is installing the code for the plugin. Often, it’s available via npm. If it is, you can simply install it:

# Install via npm
$ npm install leaflet-timedimension

# Install via yarn
$ yarn add leaflet-timedimension

Unfortunately, not all dependencies are available as packages on npm. Some are only available via Bower.io or only as a download. In those cases, you need to download/install the files and place them directly in your project (i.e., in a directory).

Importing the Plugin Library

Next, you need to get the plugin code into your project. Leaflet plugins vary widely in how they are packaged. Some use ES6 modules. Most use a specific module system like UMD. But others are simply scripts that modify the global L variable.

Angular CLI is pretty flexible about supporting libraries that are exported using various module systems (or no module system at all). So, it’s usually just a matter of figuring out the right method of importing the library.

ES6 Modules

These are the easiest because you can perform named imports of Leaflet and of the plugin you want to use. Nothing special is necessary, so it’s not very exciting, eh?

Plugins that modify a global L variable

In this case, you have to import the whole Leaflet module into L. Then, you import the plugin library for side-effects. This is illustrated in the following snippet taken from the leaflet-path-transform example:

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

// Import Leaflet into L 
import * as L from 'leaflet';

// Import the plugin libraries so they will modify L
import 'leaflet-path-transform';
import 'leaflet-path-drag';

@Component({
...

What if the plugin is not an npm package?

Sometimes plugins aren’t npm packages, or don’t name a main file in package.json. As a result, you may need to reference the file using a relative file path. This will force Webpack to bundle the file, allowing it to modify L. This is the case with leaflet-timedimension:

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

// Import Leaflet into L
import * as L from 'leaflet';

// Import the plugin library file directly, so it will change L
import '../../node_modules/leaflet-timedimension/dist/leaflet.timedimension.src.js';

@Component({
...

What if the plugin is in an IIFE or a global script?

Finally, some plugins (or their dependencies) need to be loaded as global scripts. In these cases, you will need to configure Angular CLI to load them this way. In these cases, you have to modify the scripts property in angular.json like this example from heatmap.js:

...
      "scripts": [
        "./node_modules/leaflet/dist/leaflet.js",
        "./node_modules/heatmap.js/build/heatmap.js",
        "./node_modules/leaflet-heatmap/leaflet-heatmap.js"
      ],
...

Dealing with Typings

The last thing you need to set up is type information. Fortunately, a lot of typings already exist. If they don’t, you’ll need to create your own.

Check to see if they already exist

First, you should see if they are already included in the plugin library. Look in the plugin’s package.json file for a typings property. If it’s there, you should be good.

Second, check the DefinitelyTyped project for existing typings for the plugin. If they exist, install them using npm and you’re done. Angular CLI will automatically include them in your project.

Make them yourself

If you can’t find existing typings, you’ll need to create your own. But don’t worry, it isn’t hard. Most plugins (for better or worse) modify the existing Leaflet types. This means that most of the time, you’ll add some type info to the existing Leaflet module. You can do this by adding or modifying the /src/typings.d.ts file in your Angular CLI project. The following is an example for Leaflet.Coordinates:

// Import Leaflet into L in case you want to reference Leaflet types
import * as L from 'leaflet';

// Declare the leaflet module so we can modify it
declare module 'leaflet' {

  // We want to alter the control namespace
  namespace control {

    // Define minimal type information for the coordinates function
    function coordinates(v: any);

  }
}

In this example, we’re keeping the typings simple so we can get up and running quickly. But, they are not as easy to work with in the long run. In this example, we exposed the coordinates function but didn’t type the input parameter to the function.

Consider contributing typings back to the community

If you put in the effort to develop a really good set of type definitions for a Leaflet plugin, you should consider contributing it back to DefinitelyTyped.

Configure the Plugin

At this point, you can actually do the work to get the plugin working. This step varies a lot depending on the plugin. Some are layers that you can just create and add to the layers that get added to the map. This is the case with heatmap.js:

  heatmapLayer = new HeatmapOverlay({
    radius: 2,
    maxOpacity: 0.8,
    scaleRadius: true,
    useLocalExtrema: true,
    latField: 'lat',
    lngField: 'lng',
    valueField: 'count'
  });

  options = {
    layers: [
      L.tileLayer(...),
      this.heatmapLayer
    ],
    zoom: 4,
    center: L.latLng([ 46.879966, -121.726909 ])
  };

In other cases, you have to add a custom control to the map, like with Leaflet.Coordinates. To do this, simply bind a function (in this case onMapReady) to the (leafletMapReady) output binding, create the control, and add it to the map:

onMapReady(map: L.Map) {
  L.control.coordinates({}).addTo(map);
}

Every Plugin is Different

Every plugin has its nuances, so it will take a little investigation to get each to work. But, the plugin tutorials project provides several examples to get you started. If you have specific requests or questions, we monitor the ngx-leaflet tag on Stack Overflow. Otherwise, we welcome contributions on Github.

Can we Help You?

Feel free to contact us if you think we can help your organization with Leaflet, Angular.io, or other technologies. Or, you can check out our opportunities if you’re interested in working with these technologies yourself at a great company.