Leaflet Maps with Angular
By: Abhishek Pandey
Tags: Leaflet, Easy, Angular, Maps

How it started

As I was working on a Hackathon, we came up with an idea to plot and connect our actors on a map.

As already, I had some hands-on and basic understanding of how these works, started exploring for free maps and easy api integration.

There are bunch of providers who does the job → Google, ESRI, OpenLayers, etc., but I didn’t wanted to complicate things for Hackathon as we were sliding on bottleneck.

So, on man-searching, I was suggested to use Leaflet — (an open-source JavaScript library for mobile-friendly interactive maps). It comes packed with nice features and is extremely mobile-friendly.

And, things on the table started turning with just a finger touch. :)

Now, How do I do with Angular?

Lets get started:

ng new leaflet-map-project

You are open to choose your favourite stylesheet syntax — I opted for css.

Once your Angular Project is created, you have 2 ways to install Leaflet.

1. Open your package.json and add the following dependency

"leaflet": "1.6.0"

& then run npm install

or

2. Simply run npm install leaflet

Now let’s create a map component which would serve as leaflet map container.

Navigate to src/app and type:

$ ng generate component map or ng g c map

Open up app.component.html , and replace everything inside it with our new component:

app.component.html

<app-map></app-map>

Generating the Map

Let’s first create a full-size map by constructing a simple skeleton:

map.component.html

<div class="map-container">

<div class="map-frame">

<div id="mymap"></div>

</div>

</div>

map.component.scss

.map-container {

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

} .map-frame {

border: 2px solid black;

height: 100%;

} #mymap {

height: 100%;

}

We first have our outermost div that will position the map in the DOM, and then the innermost div will be the target for Leaflet’s script injection to produce the map. The id that we give it will be passed as an argument when we construct our Leaflet map.

OK, we can now start using Leaflet & build our map.

Open up map.component.ts and import the Leaflet package:

import * as L from 'leaflet';

We’ll also declare a variable for our map object, (creatively called map ), and assign it as a new leaflet map object.

Note that the map div needs to already exist on the DOM before we can reference it to create our map. So, we put this in the AfterViewInit lifecycle hook. Extend your component to implement AfterViewInit and add the ngAfterViewInit() function to your component.

Our component should now look like this:

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

import * as L from 'leaflet'; @Component({

selector: 'app-map',

templateUrl: './map.component.html',

styleUrls: ['./map.component.scss']

})

export class MapComponent implements AfterViewInit {

private map; constructor() { } ngAfterViewInit(): void {

}

}

Looking good so far! Let’s create a separate private function called renderMap() to isolate all the map initialization. We can then call it from ngAfterViewInit .

In this function, we need to create a new Leaflet map object, and the API allows us to define some options in it as well. Let’s start off simple and set the centre of the map and starting zoom value.

I wanted to centre the map on India’s capital city New Delhi, so the co-ordinates are [ 28.6139, 77.2090].

I am using default zoom level as 10, then our leaflet map would be, as:

private renderMap(): void {

this.map = L.map('mymap', {

center: [ 28.6139, 77.2090 ],

zoom: 10

});

}

Note the value passed into the map function 'mymap' is referring to the id of the div where our map will be injected.

Now, we create a new tile layer which we must first pass a tile server URL. There are many tile server providers out there, but I personally like using the OpenStreetMap tile server.

As with creating the map object, we can pass in a parameters object. Let’s go with setting the max zoom to 18, the min zoom to 3, and the attribution for the tiles. We cap it off by adding the tile layer to the map:

let streetMap = L.tileLayer(

'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',

{

maxZoom: 19,

attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'

}); streetMap .addTo(this.map);

Our Final Code should be looking as below:

import { Component, AfterViewInit } from ‘@angular/core’;

import * as L from ‘leaflet’; @Component({

selector: ‘app-map’,

templateUrl: ‘./map.component.html’,

styleUrls: [‘./map.component.css’]

}) export class MapComponent implements AfterViewInit {

private map; constructor() { } ngAfterViewInit(): void {

this.renderMap();

} private renderMap(): void { /** MAP * */

this.map = L.map(‘map’, {

center: [28.6139, 77.2090],

zoom: 10,

}); /** Tiles **/

let streetMap = L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {

maxZoom: 19,

attribution: ‘© <a href=”http://www.openstreetmap.org/copyright">OpenStreetMap</a>'

}); tiles.addTo(this.map); /** Adding Tiles to map **/

streetMap(this.map);

}

}

Run npm start and navigate to http://localhost:4200 to see your shiny new map!

Let’s now take a look at our browser and see how our map is coming along:

Well this is progress, at least. But why are the tiles are missing? One thing we need to do when we include the Leaflet package into our project is to also include the Leaflet stylesheet into the build. There are several ways we can do this, but my personal favourite (if you’re using CSS, that is) is to simply import it into your root styles.css file.

styles.css

/* You can add global styles to this file, and also import other style files */

@import "~leaflet/dist/leaflet.css";

If you’re currently running npm start you will need to stop the process and restart so it refreshes the base stylesheet. Take a final look at the browser:

Yay! Awesome! You now have successfully created a Leaflet map with Angular that you can drag around and zoom.

In the next tutorial, we will see how to create data & render on map

1.Marker

2.Line

3.Polygon

4.Circles