Maplibre-GL Places Layers

Get direct, fast access to global POI data
<!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>
    <style>
        body, html {
            margin: 0;
            width: 100%;
            height: 100%;
        }
        #map {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <!--  where the map will live  -->
    <div id="map"></div>
    <script>
        // create targomo client
        const client = new tgm.TargomoClient('northamerica', '__targomo_key_here__')
        // Coordinates to center the map
        const lnglat = [-118.254427, 34.046185]
        
        // add the map and set the initial center
        const map = new maplibregl.Map({
            container: 'map',
            style: client.basemaps.getGLStyleURL("Light"),
            zoom: 13,
            minZoom: 9,
            center: lnglat
        })
        
        map.addControl(new maplibregl.NavigationControl())
        
        // disable scroll zoom
        map.scrollZoom.disable()
        
        // POI mvt paths for cafes/coffee_shops and restaurants, 
        const tileSources = [{
            type: 'cafe', color: 'black', textColor: 'white',
            url: `https://api.targomo.com/pointofinterest/{z}/{x}/{y}.mvt?apiKey=${client.serviceKey}` +
                '&group=coffee_shop&group=cafe&loadAllTags=true&layerType=node&layerGeometryDetailPerTile=5'
        }, {
            type: 'restaurant', color: 'orange', textColor: 'black',
            url: `https://api.targomo.com/pointofinterest/{z}/{x}/{y}.mvt?apiKey=${client.serviceKey}` +
                '&group=restaurant&loadAllTags=true&layerType=node&layerGeometryDetailPerTile=5'
        }]
        
        map.on('load', () => {
            // pre-load icons
            for (let icon of ['tgm-cafe', 'tgm-restaurant', 'tgm-circle']) {
                map.loadImage(`https://releases.targomo.com/tgm-icons/images/${icon}.png`, (error, image) => {
                    if (error) throw error
                    if (!map.hasImage(icon)) map.addImage(icon, image, { sdf: true })
                })
            }
        
            for (let source of tileSources) {
                // add source
                map.addSource(`poi-${source.type}-src`,{
                    type: 'vector',
                    tiles: [source.url],
                    minzoom: 9,
                    attribution: '<a href="https://www.targomo.com/developers/resources/attribution/" target="_blank">&copy; Targomo</a>'
                })
        
                // add layer for individual pois
                map.addLayer({
                    id: `poi-${source.type}`,
                    type: 'symbol',
                    source: `poi-${source.type}-src`,
                    'source-layer': 'poi',
                    layout: {
                        'icon-allow-overlap': true,
                        'icon-image': `tgm-${source.type}`,
                        'icon-size': 0.18
                    },
                    filter: ['==', ['get', 'numOfPois'], 1],
                    paint: {
                        'icon-color': source.color
                    }
                })
        
                // update cursor for layer
                map.on('mouseenter', `poi-${source.type}`, () => { map.getCanvas().style.cursor = 'pointer' })
                map.on('mouseleave', `poi-${source.type}`, () => { map.getCanvas().style.cursor = '' })
        
                // add layer for clusters
                map.addLayer({
                    id: `${source.type}-many`,
                    type: 'symbol',
                    source: `poi-${source.type}-src`,
                    'source-layer': 'poi',
                    layout: {
                        'icon-allow-overlap': true,
                        'icon-image': 'tgm-circle',
                        'icon-size': 0.3,
                        'text-field': '{numOfPois}',
                        'text-size': 8
                    },
                    filter: ['>', ['get', 'numOfPois'], 1],
                    paint: {
                        'icon-color': source.color,
                        'text-color': source.textColor
                    }
                })
        
                // update cursor for layer
                map.on('mouseenter', `${source.type}-many`, () => { map.getCanvas().style.cursor = 'pointer' })
                map.on('mouseleave', `${source.type}-many`, () => { map.getCanvas().style.cursor = '' })
            }
        
            map.on('click', event => {
                let description = ''
                // get all singular pois
                const poiFeatures = map.queryRenderedFeatures(event.point).filter(feature => (/^poi-/g).test(feature.source))
                // get all multiple pois
                const poiManyFeatures = map.queryRenderedFeatures(event.point).filter(feature => (/-many$/g).test(feature.layer.id))
                if (poiManyFeatures.length > 0) { // only show multiple if overlapping
                    description += `<strong>Multiple POIs</strong><br><em>${ poiManyFeatures[0].properties.numOfPois } 
                        POIs here,<br>zoom in to see details</em>`
                } else { // otherwise show singular
                    poiFeatures.forEach((f, i) => {
                        description += `<strong>POI: ${ f.properties.groupId.replace(/^\w/, c => c.toUpperCase()) }</strong><br>`
                        description += f.properties['tag-name'] ? f.properties['tag-name'] : '<em>Name not listed...</em>'
                        if (i < poiFeatures.length) { description += '<br>' }
                    })
                }
        
                // show popup
                if (description.length > 1) {
                    new maplibregl.Popup()
                        .setLngLat(event.lngLat)
                        .setHTML(description).addTo(map)
                }
            })
        })
    </script></body>
</html>
content_copy
Copied to clipboard