Step-3: Adding a polygon layer with labels

Step-3: Adding a polygon layer with labels and events handling

Introduction

This step-3 shows you how to add a polygon layer with labels and handling of events.

Getting Started

This guide involves three main steps:

1. Adding a source
2. Adding a polygon layer
3. Adding Labels

1. Adding a source

Sources objects supply data to be shown on the map. This has been explained in step-2. The following code adds a source to the map with the unique ID municipalities:

map.addSource("municipalities", { 
    type: "geojson", 
    data: "https://vektordemo.viamap.net/starterkit/data/kommuner.json", 
}); 

2. Adding a polygon layer

As described in step-2 , a layer defines styling for data from a specified source. To add a layer of type polygon, specify "type": fill as shown in the code block below

map.addLayer({
    id: "polygons",
    type: "fill",
    source: "municipalities",
    'paint': {
        "fill-opacity": ["case",
            ["boolean", ["feature-state", "hover"], false],
            0.2,
            0.5
        ],
        'fill-color': '#080',
        'fill-outline-color': '#800',
    }
});

3. Adding Labels

Similar to adding a polygon, labels can be added as layers by setting the type: "symbol" as shown in code block below:

map.addLayer({
    id: "municipality-name",
    type: "symbol",
    source: "municipalities",
    layout: {
        "text-field": "{name}\n",
        "text-font": ["Droid Sans Regular"],
        "text-size": 12,
        'symbol-placement': "point"
    },
    paint: {
        "text-color": ["case",
            ["boolean", ["feature-state", "hover"], false],
            'rgba(255,0,0,0.75)',
            'rgba(0,0,0,0.75)'
        ],
        "text-halo-color": ["case",
            ["boolean", ["feature-state", "hover"], false],
            'rgba(255,255,0,0.75)',
            'rgba(255,255,255,0.75)'
        ],
        "text-halo-width": 2,
        "text-halo-blur": 0,
    }
});

Mouse Events Handling

To trigger mouse events on the Viamap, add a listener for events of a specified type in a specified style layer by using the method:

on(type, layerId listener)

NameDescription
type(string) The event type to add a listen for.
layerId(string) The ID of a style layer. Only events whose location is within a visible feature in this layer will trigger the listener.

The event will have a features property containing an array of the matching features.
listener(Function) The function to be called when the event is fired.

Following code uses the mouse events: click, mouseenter, mousemove, mouseleave to handle the mouse events.

map.on('click', 'polygons', function(e) {
    new mapboxgl.Popup()
        .setLngLat(e.lngLat)
        .setHTML("Municipality code: " + e.features[0].properties.id)
        .addTo(map);
});

// change mouse cursor over 
map.on('mouseenter', 'polygons', function() {
    map.getCanvas().style.cursor = 'pointer';
});

// hover effect from this example: 
// https://www.mapbox.com/mapbox-gl-js/example/hover-styles/
var hoveredStateId = null;
map.on("mousemove", "polygons", function(e) {
    if (e.features.length > 0) {
        if (hoveredStateId) {
            map.setFeatureState({
                source: 'municipalities',
                id: hoveredStateId
            }, {
                hover: false
            });
        }
        hoveredStateId = e.features[0].id;
        map.setFeatureState({
            source: 'municipalities',
            id: hoveredStateId
        }, {
            hover: true
        });
    }
});

map.on("mouseleave", "polygons", function() {
    if (hoveredStateId) {
        map.setFeatureState({
            source: 'municipalities',
            id: hoveredStateId
        }, {
            hover: false
        });
    }
    hoveredStateId = null;
    // Change cursor back to a pointer when leaving.
    map.getCanvas().style.cursor = '';
});

Final Code

Here is the final code that adds a polygon layer with labels and handling of events.

A working example can be seen here.

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
        <title>Viamap vektordemo</title>

        <script src="./js/mapbox-geoviewport.js"></script>

        <!-- add viamap bootstrap code -->
        <script src="./js/viamapstrap.js"></script>
    </head>

    <body style="margin:0; padding:0;">
        <nav id="menu"></nav>
        <div id='map' style="position:absolute; top:0; bottom:0; width:100%;"></div>
        <script>
            // the position for the marker
            var lnglat = [9.912028, 57.043528],
                zoom = 15.6;

            vms.initmap({
                    container: 'map',
                    hash: false,
                    // 'center': lnglat,
                    // 'zoom': zoom
                })
                .then(function(map) {
                    // add some controls
                    map.addControl(new mapboxgl.NavigationControl(), 'top-left');


                    map.addSource("municipalities", {
                        type: "geojson",
                        data: "https://vektordemo.viamap.net/starterkit/data/kommuner.json",
                    });

                    // add municipality geometries
                    map.addLayer({
                        id: "polygons",
                        type: "fill",
                        source: "municipalities",
                        'paint': {
                            "fill-opacity": ["case",
                                ["boolean", ["feature-state", "hover"], false],
                                0.2,
                                0.5
                            ],
                            'fill-color': '#080',
                            'fill-outline-color': '#800',
                        }
                    });

                    // add municipality labels 
                    map.addLayer({
                        id: "municipality-name",
                        type: "symbol",
                        source: "municipalities",
                        layout: {
                            "text-field": "{name}\n",
                            "text-font": ["Droid Sans Regular"],
                            "text-size": 12,
                            'symbol-placement': "point"
                        },
                        paint: {
                            "text-color": ["case",
                                ["boolean", ["feature-state", "hover"], false],
                                'rgba(255,0,0,0.75)',
                                'rgba(0,0,0,0.75)'
                            ],
                            "text-halo-color": ["case",
                                ["boolean", ["feature-state", "hover"], false],
                                'rgba(255,255,0,0.75)',
                                'rgba(255,255,255,0.75)'
                            ],
                            "text-halo-width": 2,
                            "text-halo-blur": 0,
                        }
                    });

                    // you could also load the layer directly from file, but the above saves loading the file twice when adding labels also
                    // On the other hand, it is clear that labels are placed once for every label in a multi-polygon, so maybe the better approach here is to have a precomputed layer with label centroids
                    // map.addLayer({
                    // 	'id': 'polygons',
                    // 	'type': 'fill',
                    // 	'source': {
                    // 		'type': 'geojson',
                    // 		'data': "https://vektordemo.viamap.net/starterkit/data/kommuner.json"
                    // 	},
                    // 	'layout': {},
                    // 	'paint': {
                    // 		'fill-color': '#088',
                    // 		'fill-opacity': 0.8
                    // 	}
                    // });
                    //

                    // on click action example 


                    map.on('click', 'polygons', function(e) {
                        new mapboxgl.Popup()
                            .setLngLat(e.lngLat)
                            .setHTML("Municipality code: " + e.features[0].properties.id)
                            .addTo(map);
                    });

                    // change mouse cursor over 
                    map.on('mouseenter', 'polygons', function() {
                        map.getCanvas().style.cursor = 'pointer';
                    });

                    // hover effect from this example: 
                    // https://www.mapbox.com/mapbox-gl-js/example/hover-styles/
                    var hoveredStateId = null;
                    map.on("mousemove", "polygons", function(e) {
                        if (e.features.length > 0) {
                            if (hoveredStateId) {
                                map.setFeatureState({
                                    source: 'municipalities',
                                    id: hoveredStateId
                                }, {
                                    hover: false
                                });
                            }
                            hoveredStateId = e.features[0].id;
                            map.setFeatureState({
                                source: 'municipalities',
                                id: hoveredStateId
                            }, {
                                hover: true
                            });
                        }
                    });

                    map.on("mouseleave", "polygons", function() {
                        if (hoveredStateId) {
                            map.setFeatureState({
                                source: 'municipalities',
                                id: hoveredStateId
                            }, {
                                hover: false
                            });
                        }
                        hoveredStateId = null;
                        // Change cursor back to a pointer when leaving.
                        map.getCanvas().style.cursor = '';
                    });

                });
        </script>
    </body>

</html>

Do you want to try Viamap? Download “starter kit