Add a Nextzen cities text layer

Add a Nextzen cities text layer

This example adds a city text layer to a map using the Nextzen vector tile service (opens in a new tab) and filtered to only include features whose type property is equal to locality.

The text layer displays city names at various zoom levels and adjusts the font size based on the population of the city.

nextzen-cities.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>MapsGL SDK - Add a Nextzen cities text layer</title>
    <meta name="description" content="Add city text labels from a Nextzen vector tile source scaled by population." />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
 
    <link href="https://api.mapbox.com/mapbox-gl-js/v2.8.0/mapbox-gl.css" rel="stylesheet" />
    <script defer src="https://api.mapbox.com/mapbox-gl-js/v2.8.0/mapbox-gl.js"></script>
 
    <link href="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.css" rel="stylesheet" />
    <script defer src="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.js"></script>
    
 
    <style>
    body, html {
        margin: 0;
        padding: 0;
    }
    #map {
        height: 100vh;
        width: 100%;
    }
    </style>
 
</head>
<body>
    <div id="map"></div>
 
    <script>
        window.addEventListener('load', () => {
 
            mapboxgl.accessToken = 'MAPBOX_TOKEN';
            const map = new mapboxgl.Map({
                container: document.getElementById('map'),
                style: 'mapbox://styles/mapbox/light-v9',
                center: [-93, 40],
                zoom: 4
            });
 
            const account = new aerisweather.mapsgl.Account('CLIENT_ID', 'CLIENT_SECRET');
            const controller = new aerisweather.mapsgl.MapboxMapController(map, { account });
            
            controller.on('load', () => {
 
                // Hide Mapbox labels
                const map = controller.map;
                map.style.stylesheet.layers.forEach(function(layer) {
                    if (layer.type === 'symbol') {
                        map.setLayoutProperty(layer.id, 'visibility', 'none');
                    }
                });
 
                const source = controller.addSource('nextzen', {
                    type: 'vector',
                    url: 'https://tile.nextzen.org/tilezen/vector/v1/256/all/{z}/{x}/{y}.mvt?api_key={nextzen_key}'
                });
 
                const layer = controller.addLayer('nextzen-cities', {
                    type: 'text',
                    source: 'nextzen',
                    sourceType: 'point',
                    sourceLayer: 'places',
                    filter: ['all', ['==', 'kind', 'locality']],
                    paint: {
                        text: {
                            value: {
                                property: ['name:en', 'name']
                            },
                            weight: (data) => {
                                if (data.kind === 'region') {
                                    return 'bold';
                                }
                                return 'normal';
                            },
                            size: (data) => {
                                const z = data.zoom;
                                if (data.kind === 'country') {
                                    if (z < 4) {
                                        return 13;
                                    }
                                    return 20;
                                } else if (data.kind === 'region') {
                                    if (z < 4) {
                                        return 10;
                                    }
                                    return 12;
                                }
 
                                const mapValue = (number, [inMin, inMax], [outMin, outMax]) => {
                                    number = Math.max(inMin, Math.min(inMax, number));
                                    // if you need an integer value use Math.floor or Math.ceil here
                                    return (number - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
                                };
 
                                if (z < 4) {
                                    return 12;
                                }
 
                                return mapValue(data.population, [0, 5_000_000], [12, 20]);
                            },
                            transform: (data) => {
                                if (data.kind === 'region') {
                                    return 'uppercase';
                                }
                                return 'none';
                            },
                            letterSpacing: (data) => {
                                if (data.kind === 'region') {
                                    return 0.1;
                                }
                                return 0;
                            },
                            color: (data) => {
                                if (data.kind === 'region') {
                                    return '#999';
                                }
                                return '#555';
                            },
                            outlineColor: '#fff',
                            offset: { x: 0, y: 0 }                        
                        },
                        symbol: {
                            pitchWithMap: false,
                            rotateWithMap: false
                        }
                    }
                });
 
            });
        });
    </script>
 
</body>
</html>