A vanilla JavaScript Web Component for Leaflet using GeoJSON

<leaflet-map></leaflet-map>

Use Leaflet maps with GeoJSON objects as a Web Component

This simple guide will quickly get you started on using <leaflet-map>, including setting up the Web Component and working with GeoJSON objects.

The <leaflet-map> is using the attributes flyToBounds, with a small delay, customStyle for a pop-up with dark background when the point and polygon are clicked, and allowAddMarker for adding a marker using the right button.

Getting started

To get started you need to do the following steps on your project:

  1. Install the Web Component copying the directory /components/leaflet-map-component/ to your project. It is only required to keep all the files of the Web Component in the same directory. Any directory structure can be used.
  2. Include the Web Component itself.
    
    <head>
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
    
        <link rel="shortcut icon" type="image/x-icon" href="assets/favicon.ico">
        <script type="module" src="./components/leaflet-map-component/leaflet-map.js"></script>
    </head>
                    
  3. Add the element <leaflet-map>. An id is recommended with multiple maps.
    
    <body>
        <leaflet-map id="initial-map" class="small-map"></leaflet-map>
    </body>
                    
  4. Make sure the Web Component container has a defined size.
    
    .small-map {
        margin-left: auto;
        margin-right: auto;
        width: 70%;
    }
                    

Setting up the map

Let's create a map of the Puerta de Alcalá of Madrid with pretty OpenStreetMap tiles. First we’ll initialize the map and set its view to our chosen geographical coordinates and a zoom level:


<body>
    <leaflet-map id="madrid-map"
    longitude = "-3.6888136946558996"
    latitude = "40.42062134697108"
    zoom = "16"
    ></leaflet-map>
</body>
            

<leaflet-map> allows the following attributes: latitude; longitude; maxZoom; tileCopyright; tileServer; zoom and, the specials allowAddMarker; customStyle; and fitToBounds or flyToBounds.

The special attribute allowAddMarker triggers the 'x-leaflet-map:marker-pointed-out' event on adding a new marker. Nothing is done on the map.

The optional attribute customStyle defines the name of a custom class and a style file separated by a colon. This allows custom styling of elements within the Web Component.

The special attributes fit, without or with animation, the map view to contain all added GeoJSON objects at the hightest possible zoom level.

Defaults are centred on London city using OpenStreetMap tiles:


{
    latitude: 51.505,
    longitude: -0.09,
    maxZoom: 19,
    tileCopyright: '© OpenStreetMap',
    tileServer: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    zoom: 13
}
            

The customStyle attribute

For example, to change the background colour of all pop-up, we would include a CSS file

custom-popup-style.css


.custom-leaflet-popup-style .leaflet-popup-content-wrapper {
    background: #2c3e50;
    color: #fff;
}

.custom-leaflet-popup-style .leaflet-popup-tip {
background: #2c3e50;
}
                

and the customStyle attribute as following


<body>
    <leaflet-map customStyle="custom-leaflet-popup-style:<path to file>/custom-popup-style.css"></leaflet-map>
</body>
                

Obviously the name of the class custom-leaflet-popup-style is the same as the one that encapsulates the styles in the css file.

Tiles

Change easily the tile layer on the map using the tileServer property.

Note that most tile servers require attribution, which you can set using the tileCopyrigth property.


<leaflet-map id="tiles-map"
    longitude = "-3.6888136946558996"
    latitude = "40.42062134697108"
    zoom = "16"
    tileCopyright="Map data: © <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>" +
        " contributors, <a href='http://viewfinderpanoramas.org'>SRTM</a>" +
        " | Map style: © <a href='https://opentopomap.org'>OpenTopoMap</a>" +
        " (<a href='https://creativecommons.org/licenses/by-sa/3.0/'>CC-BY-SA</a>)"
    tileServer="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png">
</leaflet-map>
            

Leaflet Provider Demo is a good resource for Leaflet layer providers

GeoJSON

GeoJSON is a format for encoding a variety of geographic data structures […]. A GeoJSON object may represent a region of space (a Geometry), a spatially bounded entity (a Feature), or a list of Features (a FeatureCollection). GeoJSON supports the following geometry types: Point; LineString; Polygon; MultiPoint; MultiLineString; MultiPolygon; and, GeometryCollection.

Features in GeoJSON contain a Geometry object and additional properties, and a FeatureCollection contains a list of Features. GeoJSON Specification (RFC 7946)

<leaflet-map> allows to add GeoJSON features. Among the allowed properties:

  1. The style and popupContent properties are optional.
  2. The coordinates property is in the form [longitude, latitude].

Events

The Web Component <leaflet-map> defines two events as actions.

Event 'x-leaflet-map-geojson-add'

Use it to adding GeoJSON Features and FeatureCollections as they allow you to describe features with a set of properties (samples bellow).

This event requires an object with the property:

  1. geojson, the GeoJSON object to be added

Event 'x-leaflet-map-clear'

Use it to removing all GeoJSON features from the map.

This event requires no object.

Markers, circles, and polygons

The <leaflet-map> on the header is using the GeoJSON features point, circle and polygon all added using a FeatureCollection as following:


const introductionMap = document.getElementById('initial-map');

const features = {
    type: "FeatureCollection",
    features: [{
        type: "Feature",
        geometry: {
            type: "Point",
            coordinates: [-0.09, 51.5]
        },
        properties: {
            popupContent: "<b>Hello world!</b><br>I am a popup.",
            icon: {
                iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-violet.png',
                shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
                iconSize: [25, 41],
                iconAnchor: [12, 41],
                popupAnchor: [1, -34],
                shadowSize: [41, 41]
            }
        }
    },
    {
        type: "Feature",
        geometry: {
            type: "Point",
            coordinates: [-0.11, 51.508]
        },
        properties: {
            radius: 500,
            style: {
                color: 'green',
                fillColor: 'lightgreen',
                fillOpacity: 0.5,
            }
        }
    },
    {
        type: "Feature",
        geometry: {
            type: "Polygon",
            coordinates: [[
                [-0.08, 51.509], [-0.06, 51.503], [-0.047, 51.51]
            ]]
        },
        properties: {
            popupContent: "I am a polygon.",
            style: {
                color: 'black'
            }
        }
    }]
};

introductionMap.dispatchEvent(new CustomEvent('x-leaflet-map-geojson-add', {
    detail: {
        geojson: features
    }
}));
        

The icon property for a marker is optional.

The radius property defines a circle and is the only one required.

The popupContent and style properties are always optional for all GeoJSON feature.

A marker allows to be dragged by adding the draggable property in as follow


const marker = {
    type: "Feature",
    geometry: {
        type: "Point",
        coordinates: [-0.09, 51.5]
    },
    properties: {
        ...,
        draggable: true
    }
    ...
}
        

An example using other GeoJSON features

MultiPoint feature


const multiPoint = {
    type: "Feature",
    geometry: {
        type: "MultiPoint",
        coordinates: [
            [-3.682427584343109, 40.4111491873453],
            [-3.68192202963495, 40.41365692730523],
            [-3.681948851722108, 40.41519059487516]
        ]
    },
    properties: {
        popupContent: "I am a MultiPoint.",
        icon: {
            iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png',
            shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
            iconSize: [25, 41],
            iconAnchor: [12, 41],
            popupAnchor: [1, -34],
            shadowSize: [41, 41]
        }
    }
};
            

LineString feature


const lineString = {
    type: "Feature",
    geometry: {
        type: "LineString",
        coordinates: [
            [-3.687652527491114, 40.409744093267946], [-3.682427584343109, 40.4111491873453]
        ]
    },
    properties: {
        popupContent: "I am a LineString.",
        style: {
            color: "darkgreen"
        }
    }
};
            

MultiLineString feature


const multiLineString = {
    type: "Feature",
    geometry: {
        type: "MultiLineString",
        coordinates: [
            [[-3.682427584343109, 40.4111491873453],[-3.6826099745492304, 40.411341160113004]],
            [[-3.6826099745492304, 40.411341160113004], [-3.6826528899000177, 40.411506583044506]],
            [[-3.6826528899000177, 40.411506583044506], [-3.68243831317919853, 40.411606653500144]],
            [[-3.68243831317919853, 40.411606653500144], [-3.682108401470939, 40.412278551277]],
            [[-3.682108401470939, 40.412278551277], [-3.681923329048269, 40.41250115425148]],
            [[-3.681923329048269, 40.41250115425148], [-3.6817275277905215, 40.41301170869761]],
            [[-3.6817275277905215, 40.41301170869761], [-3.681829451732911, 40.41325473125318]],
            [[-3.681829451732911, 40.41325473125318], [-3.6817870058620503, 40.41364722100761]],
            [[-3.6817870058620503, 40.41364722100761], [-3.6819264807305836, 40.41399847689981]],
            [[-3.6819264807305836, 40.41399847689981], [-3.681591447371322, 40.41409650736312]],
            [[-3.681591447371322, 40.41409650736312], [-3.6818127296148377, 40.41472753715036]],
            [[-3.6818127296148377, 40.41472753715036], [-3.6818435750184553, 40.414991996086876]]
        ]
    },
    properties: {
        popupContent: "I am a MultiLineString.",
        style: {
            color: "green",
        }
    }
};
            

MultiPolygon feature


const multiPolygon = {
    type: "Feature",
    geometry: {
        type: "MultiPolygon",
        coordinates: [
            [[
                [-3.6851719536314866, 40.418190942101084], [-3.6836913742578337, 40.41853094304074],
                [-3.68269536666569, 40.41612787699837], [-3.684217761317601, 40.415778927180085]
            ]],
            [[
                [-3.6818543038540397, 40.41399031407121], [-3.6811368129438007, 40.41413326654296],
                [-3.6811247430031844, 40.41355941263011], [-3.6816638670142425, 40.41346649276557]
            ]]
        ]
    },
    properties: {
    popupContent: "I am a MultiPolygon.",
    style: {
        color: "black",
        opacity: 0.5,
    }
};
            
adding all of them to the following map:

const walking = document.getElementById('walk-throught-el-retiro');
const walkThroughtElRetiro = {
type: "FeatureCollection",
    features: [multiPoint, lineString, multiLineString, multiPolygon]
};

walking.dispatchEvent(new CustomEvent('x-leaflet-map-geojson-add', {
    detail: {
        geojson: walkThroughtElRetiro
    }
}));
            

The <leaflet-map> is using the attribute fitToBounds


<leaflet-map id="walk-throught-el-retiro"
    longitude="-3.6843547932100424"
    latitude="40.41411233423414"
    fitToBounds></leaflet-map>
            

Adding a marker to the map

Actually adding a marker only triggers the 'x-leaflet-map:marker-pointed-out' event and any action must be performed by whoever uses the web component by adding functionality to that marker. Nothing is done on the map.

Adding a marker to the map could be done clicking with the right button in any point.

This action opens a popup with a button for confirmation. Clicking in it triggers the 'x-leaflet-map:marker-pointed-out' event by exposing the latitude and longitude of the point as follows


    x-leaflet-map:marker-pointed-out {
        target: leaflet-map,
        isTrusted: false,
        detail: {
            latlng: {
                lat: 51.52540664057756,
                lng: -0.07201194763183595
            }
        }
        ...
    }
        

You can the first map as a small demo using the allowAddMarker attribute.

Remove a marker from the map

Any of the markers added to the map can be deleted by double clicking on it and confirming the deletion.

Web Component <leaflet-map> triggers 'x-leaflet-map:marker-removed' event when any marker is removed from map by exposing its GeoJSON as follows


    x-leaflet-map:marker-removed {
        target: leaflet-map,
        isTrusted: false,
        detail: {
            feature: {
                type: "Feature",
                geometry: {
                type: "Point",
                coordinates: [-0.09, 51.5]
                },
                ...
            }
        }
        ...
    }
        

You can the first map as a small demo using the flyToBounds attribute.

Multiple maps

As you can see from the previous examples, it is very easy to add multiple maps on a web page.

About the code

Take a deeper look at the web component by reading and cloning the code on GitHub.