Creating & Editing Geo-fences Using OpenStreetMap with the leaflet.js library in Angular 5 project
OpenStreetMap is built by a community of mappers that contribute and maintain data about roads, trails, cafés, railway stations, and much more, all over the world.
The leaflet is a JavaScript library for embedding maps which are displayed on OpenLayers. You could check out the leaflet.js.com tutorials pages, which will walk you through the basics.
This article will guide you on how to create a simple embedded map with markers, geofences using leaflet.js and OpenStreetMap as the tile provider.
Install
Install the package and its peer dependencies via npm (or yarn):
npm install leaflet
npm install @asymmetrik/ngx-leaflet
If you intend to use this library in a typescript project (utilizing the typings), you’ll need to install the leaflet typings:
npm install --save-dev @types/leaflet
Direct Import from HTML
If you are just building a webpage and not using a bundler for your css, you’ll want to directly import the css file in your HTML page.
<head>
...
<link rel="stylesheet"
type="text/css" href="./node_modules/leaflet/dist/leaflet.css">
...
</head>
Adding Styles in Angular CLI
If you are using Angular CLI, you will need to add the Leaflet CSS file to the styles array contained in angular.json
{
...
"styles": [
"styles.css",
"./node_modules/leaflet/dist/leaflet.css"
],
...
}
Importing Leaflet Module
Before you can use leaflet in your project you have to import its module to the project (and potentially the module that’s using it).
For example, in your app.module.ts
, add:
import { LeafletModule } from '@my-project/ngx-leaflet';...
imports: [
...
LeafletModule.forRoot()
]
...
You will also need to import the leaflet module in the module of the component which will be using the leaflet. In this case, in my-module.module.ts
, add:
import { LeafletModule } from '@my-project/ngx-leaflet';
...
imports: [
...
LeafletModule
]
...
Create and Configure a Map
Once the dependencies are installed and you have imported the LeafletModule
, you're ready to add a map to your page. To get a basic map to work, you have to:
- Apply the
leaflet
attribute directive to a div tag as seen below. - Style the div with a height. Otherwise, it’ll render with a 0 pixel height.
- Provide an initial zoom/center and set of layers either via the leaflet directives such as
leafletOptions
or by binding toleafletZoom
,leafletCenter
, andleafletLayers
.
Template:
<div style="height: 300px;"
leaflet
[leafletOptions]="options">
</div>
Example leafletOptions object:
options = {
layers: [
tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' })
],
zoom: 5,
center: latLng(46.879966, -121.726909)
};
The leafletOptions is configurable and must be initialized before the map initializes unless it will be ignored after map initializes. This is because these options are passed into the map constructor, so they can’t be changed anyway.
Add a Layers Control
The [leafletLayersControl]
input bindings give you the ability to add the layers control to the map. The layers control lets the user toggle layers and overlays on and off.
Template:
<div style="height: 300px;"
leaflet
[leafletOptions]="options"
[leafletLayersControl]="layersControl">
</div>
Example layersControl object:
layersControl = {
baseLayers: {
'Open Street Map': tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' }),
'Open Cycle Map': tileLayer('http://{s}.tile.opencyclemap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' })
},
overlays: {
'Big Circle': circle([ 46.95, -122 ], { radius: 5000 }),
'Big Square': polygon([[ 46.8, -121.55 ], [ 46.9, -121.55 ], [ 46.9, -121.7 ], [ 46.8, -121.7 ]])
}
}
You can add any kind of Leaflet layer you want to the overlays
map. This includes markers, shapes, geojson, custom layers from other libraries, etc.
Using the Leaflet-Draw Tool to create Geo-fences in the Map
The leaflet draw tool helps you create shapes across different locations on the map. To start with you will have to install the leaflet-draw package.
Install
Install the package and its peer dependencies via npm (or yarn):
npm install leaflet-draw
npm install @asymmetrik/ngx-leaflet-draw
Just the way you added leaflet style to your index.html and angular.json (if using angular-cli), you will need to import the leaflet-draw style also to the various files respectively.
You will also need to import the leaflet-draw module to the app.module.ts
of the project.
import { LeafletModule } from '@my-project/ngx-leaflet';
import { LeafletDrawModule } from '@my-project/ngx-leaflet-draw';
...
imports: [
...
LeafletModule.forRoot(),
LeafletDrawModule.forRoot()
]
...
Also import the leaflet-draw module to the module of the project which will be using the leaflet-draw.
Create and Configure a Map with the Draw Controls
Since we already have the leaflet directive in the html file of the component which it is in use we could simply add the leafletDraw directive which will be initialized with the map instance.
<div leaflet style="height: 300px;"
leafletDraw
[leafletOptions]="options"
[leafletDrawOptions]="drawOptions">
</div>
leafletDrawOptions
Input binding for the options to be passed to the draw plugin upon creation. These options are only currently processed at creation time.
drawOptions = {
position: 'topright',
draw: {
marker: {
icon: L.icon({
iconSize: [ 25, 41 ],
iconAnchor: [ 13, 41 ],
iconUrl: 'assets/marker-icon.png',
shadowUrl: 'assets/marker-shadow.png'
})
},
polyline: false,
circle: {
shapeOptions: {
color: '#aaaaaa'
}
}
}
};
You could also reference this documentation for more draw options as you can several draw shapes such as polygons, and squares to the drawOptions.
The drapOptions control has a toolbar which holds all the draw shapes available and could be used to carry out actions such as edit, delete on the draw/fence created.
leafletDrawReady
This output is emitted when once when the Leaflet Draw Control is initially created inside of the Leaflet Draw directive. The event will only fire when the Control exists and is ready for manipulation.
<div leaflet
leafletDraw
[leafletOptions]="options"
[leafletDrawOptions]="drawOptions"
(leafletDrawReady)="onDrawReady($event)">
</div>onDrawReady(drawControl: Draw.Control) {
// Do stuff with map
}
This method of getting the draw control makes the most sense if you are using the Leaflet directive inside your own component and just need to add some limited functionality or register some event handlers.
leafletDrawCreated
This output is emitted once the leaflet draw control is used to create a draw or fence across a geographical area in the map. With this event you could easily get details of the geo-fence such as the shape of the draw tool used, coordinates of the selected area e.t.c…
onMapReady(map:Map){
map.on('draw:created',(e) => {
const type = (e as any).layerType,
layer = (e as any).layer;
if (type === 'polygon') {
let polygonCoordinates = layer._latlngs;
this.coordinateModel.coordinates = [];
this.coordinateModel.coordinates = polygonCoordinates[0] ;
this.coordinateModel.geoFenceMode = 'POLYGON';
}
Getting Help
Here’s a list of articles, tutorials, guides, and help resources: