Mapbox gl js - Custom icons based on multiple criteria

1.9k Views Asked by At

I'm currently trying to build a customer web map with mapbox gl js and struggle how to best structure the code to display the geojson data on the map layer based on multiple properties.

Properties are as follows:

  • type: includes the property of the marker with 3 values: static, airplane, ship
  • name: include the name of the marker, can be any name for ship and airplane but defines a sub type for static: airport, building, bridge
  • nation: includes a numeric value based on the nation the above items belongs to: 0, 1, 2

Type and name will define the icon type, nation the icon color (icons are in sdf format)

I have the following code now which works but without taking the name subclass for static objects into account. Any suggestion on how this subclass match can be included so I can show different icons for static+airport, static+building, static+bridge but not care about the name for the airplane and ship types?

map.addLayer({
        'id': 'marker',
        'type': 'symbol',
        'source': 'db-json',
        'layout': {
            'icon-image': [
                    'match', // Use the 'match' expression: https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-match
                    ['get', 'type'], // Use the result 'coalition' property
                    'airplane', 'plane-icon',
                    'static', 'circle-stroked-15',
                    'ship', 'harbor-15',
                    'airfield-15' // any other type
                    ]
            },
            'paint': {
                'icon-color': [
                    'match', // Use the 'match' expression: https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-match
                    ['get', 'nation'], // Use the result 'nation' property
                    0, '#808080',
                    1, '#FF0000',
                    2, '#0000FF',
                    '#00FF00' // any other nation
                    ]
                }
        });

Thanks a million !!

1

There are 1 best solutions below

1
On

To answer my own question. Multiple levels can be stacked of course. Might not be the most optimal solution (vs a query that checks and compares 2 variables at the same time) but it works.

Example:

map.addLayer({
        'id': 'marker',
        'type': 'symbol',
        'source': 'db-json',
        'layout': {
            'icon-image': [
                    'match', 
                    ['get', 'type'], // Use the result 'type' property
                    'airplane', 'plane-icon',
                    'static', [
                       'match', 
                        ['get', 'name'], // Use the result 'name' property
                        'airport', 'airport-icon',
                        'building', 'building-icon',
                        'bridge', 'bridge-icon',
                        '' // none for any other type
                         ],
                    'ship', 'harbor-15',
                    'airfield-15' // any other type
                    ]
            },
            'paint': {
                'icon-color': [
                    'match', 
                    ['get', 'nation'], // Use the result 'nation' property
                    0, '#808080',
                    1, '#FF0000',
                    2, '#0000FF',
                    '#00FF00' // any other nation
                    ]
                }
        });