Maplibre-GL Statistics Context

Quantify the reachability - see how many people are within 45 minutes on foot. Drag the marker to see how the reachable population changes
local_activityThe statistics service is a custom offering, and you need to contact us to get set-up
<!DOCTYPE html>
<html>
<head>
<!--  Include maplibregl javascript and css -->
    <script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
    <link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet">
    <!--  Include targomo core -->
    <script src="https://releases.targomo.com/core/latest.min.js"></script>
    <!--  Include micro progress bar  -->
    <script src="https://www.targomo.com/developers/scripts/mipb.min.js"></script>
    <style>
        body, html {
            margin: 0;
            width: 100%;
            height: 100%;
        }
        #map {
            width: 100%;
            height: 100%;
            position: relative;
        }
        .population {
            position: absolute; padding: 8px;
            top: 10px; left: 10px;
            font-family: Helvetica, Arial, Sans-Serif;
            background: white; border-radius: 4px;
            box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <!--  where the map will live  -->
    <div id="map"></div>
    <div class="population"><span>Reachable Population:</span>&nbsp;<span id="total-pop"></span></div>

    <script>
        // create targomo client
        const client = new tgm.TargomoClient('westcentraleurope', '__targomo_key_here__')
        // Coordinates to center the map
        const lnglat = [-3.699543, 40.415822]
        // set the progress bar
        const pBar = new mipb({ fg: '#FF8319' })
        
        // add the map and set the initial center to paris
        const map = new maplibregl.Map({
            container: 'map',
            style: client.basemaps.getGLStyleURL('Light'),
            minZoom: 9, zoom: 12.5, center: lnglat
        }).addControl(new maplibregl.NavigationControl())
        
        // disable scroll zoom
        map.scrollZoom.disable()
        
        const marker = new maplibregl.Marker({
            draggable: true
        }).setLngLat(lnglat).addTo(map)
        
        marker.on('dragend', getStats)
        
        const statsConfig = {
            maxEdgeWeight: 1800, travelType: 'Walk', // 30 minutes on foot
            statisticsGroup: 94, statistics: [{ id: 1 }] // Spain statistics on H3, total population
        }
        
        async function getStats() {
            // show progress bar
            pBar.show()
            const sources = [{ ...marker.getLngLat(), id: 'Marker1' }]
        
            // get the results as well as an id:travelTime map
            const [statisticsResults, statisticsTimes] = await Promise.all([
                client.statistics.dependent(sources, statsConfig),
                client.statistics.travelTimes(sources, statsConfig)
            ])
        
            const colors = [
                'rgb(26,152,80)', 'rgb(145,207,96)', 'rgb(217,239,139)',
                'rgb(254,224,139)', 'rgb(252,141,89)', 'rgb(215,48,39)'
            ]
        
            const colorExpression = ['match', ['get', 'id']]
            const opacityExpression = ['match', ['get', 'id']]
        
            // Calculate color values for each country based on 'id' value
            for (const [id, time] of Object.entries(statisticsTimes)) {
                // Determine which color bucket the cell's value lies within 
                const colorIndex = Math.ceil((time/(statsConfig.maxEdgeWeight/colors.length)))-1
                const color = colors[colorIndex]
                // update the expressions
                colorExpression.push(+id, color)
                opacityExpression.push(+id, .5)
            }
             
            // Last value is the default, used where there is no data
            colorExpression.push('#666')
            opacityExpression.push(0.2)
        
            // update the layer's style
            map.setPaintProperty('statistics', 'fill-color', colorExpression)
            map.setPaintProperty('statistics', 'fill-opacity', opacityExpression)
        
            // tally full reachable population
            const reachablePop = Object.values(
                statisticsResults.raw.statistics[statsConfig.statistics[0].id]
            ).reduce((acc, cur) => { return acc+cur }, 0)
        
            // update the 
            var popElem = document.querySelector('#total-pop')
            popElem.innerHTML = Math.round(reachablePop).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
        
            // hide progress bar
            pBar.hide()
        
            map.on('click', 'statistics', (e) => {
                const travelTime = Math.round(statisticsTimes[e.features[0].properties.id] / 60)
                const description = `Population: ${Math.round(e.features[0].properties[statsConfig.statistics[0].id])}
                    <br>Walk time: ${travelTime ? travelTime : 'not reachable'}`
        
                new maplibregl.Popup()
                    .setLngLat(e.lngLat)
                    .setHTML(description).addTo(map)
            })
        }
        
        map.on('load', async () => {
            // get metadata for statistics group 123 (France INSEE on hexagons)
            // to see the available statistics, as well as details of the dataset
            const meta = await client.statistics.metadata(statsConfig.statisticsGroup)
            
            // get the vectortiles url
            const tileRoute = await client.statistics.tileRoute(statsConfig.statisticsGroup, [statsConfig.statistics[0]])
            // add the tiles to the map
            map.addLayer({
                id: 'statistics',
                type: 'fill',
                source: {
                    type: 'vector',
                    tiles: [tileRoute],
                    minzoom: meta.min_zoom,
                    attribution: '<a href="https://www.targomo.com/developers/resources/attribution/" target="_blank">&copy; Targomo</a>'
                },
                'source-layer': `${statsConfig.statisticsGroup}`, // source-layer is the statistic group id
                layout: {},
                paint: {
                    'fill-opacity': 0.2,
                    'fill-color': '#666',
                    'fill-outline-color': 'rgba(50, 50, 50, 0.1)'
                }
            }, 'place_other')
        
            // Change the cursor to a pointer when the mouse is over the stats layer
            map.on('mouseenter', 'statistics', () => {
                map.getCanvas().style.cursor = 'pointer'
            })
        
            // Change it back to a pointer when it leaves.
            map.on('mouseleave', 'statistics', () => {
                map.getCanvas().style.cursor = ''
            })
        
            getStats()
        })
    </script>
</body>
</html>
content_copy
Copied to clipboard