Visualize Multigraph with Deck.gl

Multigraph’s power comes from it’s ability to return multiple geometry types. The base-level is nodes - here we’re using the raw nodes to manually aggregate into dynamic hexagons
<!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 deck.gl -->
    <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
    <script type="text/javascript">
        const { MapboxLayer, HexagonLayer } = deck;
    </script>
    <!--  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%;
        }
        #control-panel {
            position: absolute;
            margin: 10px;
            font-family: 'Open Sans', sans-serif;
            top: 0; z-index: 100;
            display: flex;
            flex-direction: column;
            padding: 5px 8px;
            background: #fff;
        }
        .panel-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        #map {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <!--  where the map will live  -->
    <div id="map"></div>
    <div id="control-panel">
        <div class="panel-item">
            <label>Hex size</label>
            <input id="radius" type="range" min="100" max="500" step="50" value="200"></input>
            <span id="radius-value"></span>
        </div>
        <div class="panel-item">
            <label>Hex pct.</label>
            <input id="coverage" type="range" min="0" max="1" step="0.1" value=".9"></input>
            <span id="coverage-value"></span>
        </div>
    </div>
    <script>
        // create targomo client
        const client = new tgm.TargomoClient('westcentraleurope', '__targomo_key_here__')
        // Coordinates to center the map
        const source = { id: 'src', lng: 2.375, lat: 48.844 }
        const attributionText = '<a href="https://www.targomo.com/developers/resources/attribution/" target="_blank">&copy; Targomo</a>'
        
        // set the progress bar
        const pBar = new mipb({ fg: '#FF8319' })
        
        // add the map and set the initial center to berlin
        const map = new maplibregl.Map({
            container: 'map',
            style: client.basemaps.getGLStyleURL('Light'),
            zoom: 11, pitch: 40,
            center: source,
            attributionControl: false
        })
            .addControl(new maplibregl.NavigationControl())
            .addControl(new maplibregl.AttributionControl({ customAttribution: attributionText }))
        
        // disable scroll zoom
        map.scrollZoom.disable()
        
        
        const marker = new maplibregl.Marker({
            //draggable: true
        }).setLngLat(source).addTo(map)
        // container for housing the multigraph data
        let data = []
        
        const OPTIONS = ['radius', 'coverage']
        
        const COLOR_RANGE = [
            [26, 152, 80], [145, 207, 96],
            [217, 239, 139], [254, 224, 139],
            [252, 141, 89], [215, 48, 39]
        ]
        
        function renderLayer() {
            const options = {}
            OPTIONS.forEach((key) => {
                const value = +document.getElementById(key).value
                document.getElementById(key + '-value').innerHTML = value
                options[key] = value
            })
        
            const myDeckLayer = new MapboxLayer({
                id: 'heatmap',
                type: HexagonLayer,
                colorRange: COLOR_RANGE,
                data,
                getPosition: (d) => [Number(d.lng), Number(d.lat)],
                getColorWeight: (d) => d.w,
                colorAggregation: 'MEAN',
                opacity: 0.3,
                ...options
            })
        
            if (map.getLayer('heatmap')) {
                map.removeLayer('heatmap')
            }
            map.addLayer(myDeckLayer, 'place_other')
        }
        
        async function setUp() {
            // show progress bar
            pBar.show()
            // here we're deciding that we want transit coverage, 30 minutes (1800s), nodes (as we are aggregating with deckGL)
            const multigraphOptions = {
                edgeWeight: 'time',
                travelType: 'transit',
                maxEdgeWeight: 1800,
                multigraph: {
                    layer: { type: 'identity' },
                    domain: { type: 'node' },
                    serialization: { format: 'geojson' },
                    aggregation: { type: 'routing_union' }
                }
            }
        
            const mg = await client.multigraph.fetch([source], multigraphOptions)
        
            // hide progress bar
            pBar.hide()
        
            data = mg.data.features.map((f) => {
                return {
                    lng: f.geometry.coordinates[0],
                    lat: f.geometry.coordinates[1],
                    w: f.properties.w
                }
            })
        
            // initial layer rendering
            renderLayer()
        
            OPTIONS.forEach((key) => {
                // re-render when hex settings change
                document.getElementById(key).oninput = renderLayer
            })
        }
        
        map.on('load', () => {
            setUp()
        })
    </script>
</body>
</html>
content_copy
Copied to clipboard