Working with GeoJSON | MapGL | Urbi Documentation

Working with GeoJSON

To show GeoJSON data on the map, you need to add:

  1. a source with the data to the map;
  2. a layer to a map style to describe data appearance.

Let's take an example of GeoJSON data:

const data = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            properties: {},
            geometry: {
                type: 'Polygon',
                coordinates: [
                    [
                        [55.41, 25.34],
                        [55.44, 25.34],
                        [55.43, 25.37],
                        [55.41, 25.34],
                    ],
                ],
            },
        },
    ],
};

To add the data as a map data source, you need to use GeoJsonSource:

const source = new mapgl.GeoJsonSource(map, {
    data,
});

The code above adds the polygon to the map data only. But the map can't render it because it can't link to a specific map style layer. The polygon adds to the general data array of the map, where you can't distinguish one polygon from another.

To distinguish it from other polygons, you should add a unique attribute for it in properties field:

const data = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            properties: {
                foo: 'qwe', // Unique attribute
            },
            geometry: {
                type: 'Polygon',
                coordinates: [
                    [
                        [55.41, 25.34],
                        [55.44, 25.34],
                        [55.43, 25.37],
                        [55.41, 25.34],
                    ],
                ],
            },
        },
    ],
};

Or you can add a unique attribute to the whole data source in attributes field:

const source = new mapgl.GeoJsonSource(map, {
    data,
    attributes: {
        bar: 'asd', // Unique attribute
    },
});

Now the polygon can be associated with a new map style layer and therefore drawn.

A map style is a config that describes map data appearance. The style contains layers. Each layer contains:

  • filter field — to describe a data filtering logic to determine which data will be drawn by this layer;
  • style field — to describe the appearance of the drawing objects (color, width, font, etc.).

You can find more information about the map style in Style Specification.

We added a polygon as the map data source above. Now, we can link it with a new style layer.

At first, create a new layer:

const layer = {
    id: 'my-polygons-layer', // Each layer ID must be unique

    // Data filtering logic
    filter: [
        'match',
        ['sourceAttr', 'bar'],
        ['asd'],
        true, // Result if value of bar source attribute equals "asd"
        false, // Result if not
    ],

    // Drawing object type
    type: 'polygon',

    // Style of drawing object
    style: {
        color: '#0000ff',
    },
};

Here in filter we use:

  • SourceAttrExpression — to get values from bar source attribute;
  • MatchExpression — to match the values with string "asd".

If you used the GeoJSON object properties field to add the unique attribute, you should use GetExpression instead of SourceAttrExpression.

At the end, you need to add the created layer to a map style using map.addLayer(layer), and the map will be redrawn along with the new polygon:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="GeoJSON polygon example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.425, 25.355],
                zoom: 13,
                key: 'Your API access key',
            });

            const data = {
                type: 'FeatureCollection',
                features: [
                    {
                        type: 'Feature',
                        properties: {},
                        geometry: {
                            type: 'Polygon',
                            coordinates: [
                                [
                                    [55.41, 25.34],
                                    [55.44, 25.34],
                                    [55.43, 25.37],
                                    [55.41, 25.34],
                                ],
                            ],
                        },
                    },
                ],
            };

            const source = new mapgl.GeoJsonSource(map, {
                data,
                attributes: {
                    bar: 'asd',
                },
            });

            const layer = {
                id: 'my-polygons-layer', // Each layer ID must be unique

                // Data filtering logic
                filter: [
                    'match',
                    ['sourceAttr', 'bar'],
                    ['asd'],
                    true, // Result if value of bar source attribute equals "asd"
                    false, // Result if not
                ],

                // Drawing object type
                type: 'polygon',

                // Style of drawing object
                style: {
                    color: '#0000ff',
                },
            };

            map.on('styleload', () => {
                map.addLayer(layer);
            });
        </script>
    </body>
</html>

After creating a map, its style will be empty until it is loaded from the server. It is important to add new layers only after style loading because the loaded style will completely overwrite the old one. To do this, the example above uses styleload event, which is emitted every time after a new style is set:

map.on('styleload', () => {
    map.addLayer(layer);
});

If you change a map style with map.setStyleById() method, you can also use Promise that the method returns:

map.setStyleById('e05ac437-fcc2-4845-ad74-b1de9ce07555').then(() => {
    map.addLayer(layer);
});

Layers of a map style are ordered relative to each other. The order of the layers determines the sequence in which they are drawn on the map.

By default, the map.addLayer(layer) method adds a new layer to the end of the layers list, i.e. the new layer will be drawn last. If you need to add the layer not at the end, but before of another layer, you need to specify the ID of another layer in the method as the second argument:

map.addLayer(anotherLayer, 'my-polygons-layer');

You can also add the layer before the layers that are configured in Style Editor:

map.addLayer(layer, 'other roads tunnel');
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="GeoJSON polygon under roads example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.425, 25.355],
                zoom: 13,
                key: 'Your API access key',
            });

            const data = {
                type: 'FeatureCollection',
                features: [
                    {
                        type: 'Feature',
                        properties: {},
                        geometry: {
                            type: 'Polygon',
                            coordinates: [
                                [
                                    [55.41, 25.34],
                                    [55.44, 25.34],
                                    [55.43, 25.37],
                                    [55.41, 25.34],
                                ],
                            ],
                        },
                    },
                ],
            };

            const source = new mapgl.GeoJsonSource(map, {
                data,
                attributes: {
                    bar: 'asd',
                },
            });

            const layer = {
                id: 'my-polygons-layer', // Each layer ID must be unique

                // Data filtering logic
                filter: [
                    'match',
                    ['sourceAttr', 'bar'],
                    ['asd'],
                    true, // Result if value of bar source attribute equals "asd"
                    false, // Result if not
                ],

                // Drawing object type
                type: 'polygon',

                // Style of drawing object
                style: {
                    color: '#0000ff',
                },
            };

            map.on('styleload', () => {
                map.addLayer(layer, 'other roads tunnel');
            });
        </script>
    </body>
</html>

To draw a data source, instead of adding a layer via the API, you can also add it in Style Editor to your map style.

To do this, there, at the creating new layer step, you should click JSON — manual adding button and add MatchExpression, which would have to be specified in the filter when adding a layer via API:

GeoJSON styles from editor

To subscribe to events, such as a click on GeoJsonSource or to other MapEventTable events, use on() method of map instance. GeoJsonSource objects contain targetData with a type GeoJsonEventTargetData in events.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>2GIS Map API</title>
    <meta name="description" content="GeoJSON events example" />
    <style>
        html,
        body,
        #container {
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <div id="container"></div>
    <script src="https://mapgl.2gis.com/api/js/v1"></script>
    <script>
        const map = new mapgl.Map('container', {
            center: [55.4218, 25.3357],
            zoom: 17,
            pitch: 45,
            key: 'Your API access key',
        });

        const data = {
            type: 'FeatureCollection',
            features: [
                {
                    type: 'Feature',
                    properties: {
                        type: 'star',
                        name: 'geoJson Polygon - star-polygon A'
                    },
                    geometry: {
                        type: 'Polygon',
                        coordinates: [
                            [
                                [55.422656536102316, 25.335250625051458],
                                [55.42331099510195, 25.335570623342118],
                                [55.42392253875736, 25.33520214038817],
                                [55.423622131347685, 25.335774258177413],
                                [55.42422294616701, 25.336074861355655],
                                [55.423579216003446, 25.33610395194616],
                                [55.42338609695437, 25.336666368655063],
                                [55.42309641838077, 25.336123345669286],
                                [55.422409772872946, 25.33614273938931],
                                [55.42298913002018, 25.33580334884018],
                                [55.422656536102316, 25.335250625051458],
                            ],
                        ],
                    },
                },
                {
                    type: 'Feature',
                    properties: {
                        type: 'star',
                        name: 'geoJson Polygon - star-polygon B'
                    },
                    geometry: {
                        type: 'Polygon',
                        coordinates: [
                            [
                                [55.419437885284445, 25.334988807638815],
                                [55.42009234428408, 25.335308806621768],
                                [55.42070388793948, 25.334940322870644],
                                [55.420403480529814, 25.33551244189763],
                                [55.42100429534914, 25.335813045726233],
                                [55.42036056518557, 25.33584213637969],
                                [55.420167446136496, 25.336404554305396],
                                [55.419877767562895, 25.335861530144776],
                                [55.419191122055075, 25.335880923906757],
                                [55.419770479202306, 25.33554153262335],
                                [55.419437885284445, 25.334988807638815],
                            ],
                        ],
                    },
                },

                {
                    type: 'Feature',
                    properties: {
                        type: 'marker',
                        label: 'Star A',
                        color: 'blue',
                        name: 'geoJson Point - star-marker A'
                    },
                    geometry: {
                        type: 'Point',
                        coordinates: [55.42332172393799, 25.33587122702617],
                    },
                },
                {
                    type: 'Feature',
                    properties: {
                        type: 'marker',
                        label: 'Star B',
                        color: 'blue',
                        name: 'geoJson Point - star-marker B'
                    },
                    geometry: {
                        type: 'Point',
                        coordinates: [55.420124530792236, 25.335590017150714],
                    },
                },

            ],
        };

        const source = new mapgl.GeoJsonSource(map, {
            data,
            attributes: {
                bar: 'asd',
            },
        });

        map.on('styleload', () => {
            map.addLayer(
                {
                    type: 'polygon',
                    id: 'my-stars',
                    filter: [
                        'all',
                        ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                        ['match', ['get', 'type'], ['star'], true, false],
                    ],
                    style: {
                        color: '#fcc9ff',
                    },
                },
            );


            map.addLayer({
                type: 'point',
                id: 'my-marker',
                filter: [
                    'all',
                    ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                    ['match', ['get', 'type'], ['marker'], true, false],
                ],
                style: {
                    iconImage: ['match', ['get', 'color'], ['blue'], 'ent_i', 'ent'],
                    iconWidth: 25,
                    textField: ['get', 'label'],
                    textFont: ['Noto_Sans'],
                    textColor: '#0098ea',
                    textHaloColor: '#fff',
                    textHaloWidth: 1,
                    iconPriority: 100,
                    textPriority: 100,
                },
            });
        });
        map.on('click', (e) => { if (e.targetData.type === 'geojson') { alert('GeoJsonFeature clicked: ' + e.targetData.feature.properties.name) } })
    </script>
</body>

</html>

Below is a complex example of using GeoJSON. The examples uses:

  • different types of GeoJSON data (Point,Polygon, LineString);
  • different drawing objects (line,dashedLine, point,polygon);
  • compound expressions in filter;
  • expressions inside style properties.
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>2GIS Map API</title>
        <meta name="description" content="GeoJSON complex example" />
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.4218, 25.3357],
                zoom: 17,
                pitch: 45,
                key: 'Your API access key',
            });

            const data = {
                type: 'FeatureCollection',
                features: [
                    {
                        type: 'Feature',
                        properties: {
                            type: 'topLine',
                        },
                        geometry: {
                            type: 'LineString',
                            coordinates: [
                                [55.41612267494202, 25.3373063569028],
                                [55.418890714645386, 25.33572577372391],
                                [55.41969537734985, 25.336870001646474],
                                [55.42081117630005, 25.33621061738493],
                                [55.421626567840576, 25.337393627765234],
                                [55.42233467102051, 25.336966969617198],
                                [55.42382597923279, 25.339100245313542],
                            ],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'star',
                        },
                        geometry: {
                            type: 'Polygon',
                            coordinates: [
                                [
                                    [55.422656536102316, 25.335250625051458],
                                    [55.42331099510195, 25.335570623342118],
                                    [55.42392253875736, 25.33520214038817],
                                    [55.423622131347685, 25.335774258177413],
                                    [55.42422294616701, 25.336074861355655],
                                    [55.423579216003446, 25.33610395194616],
                                    [55.42338609695437, 25.336666368655063],
                                    [55.42309641838077, 25.336123345669286],
                                    [55.422409772872946, 25.33614273938931],
                                    [55.42298913002018, 25.33580334884018],
                                    [55.422656536102316, 25.335250625051458],
                                ],
                            ],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'star',
                        },
                        geometry: {
                            type: 'Polygon',
                            coordinates: [
                                [
                                    [55.419437885284445, 25.334988807638815],
                                    [55.42009234428408, 25.335308806621768],
                                    [55.42070388793948, 25.334940322870644],
                                    [55.420403480529814, 25.33551244189763],
                                    [55.42100429534914, 25.335813045726233],
                                    [55.42036056518557, 25.33584213637969],
                                    [55.420167446136496, 25.336404554305396],
                                    [55.419877767562895, 25.335861530144776],
                                    [55.419191122055075, 25.335880923906757],
                                    [55.419770479202306, 25.33554153262335],
                                    [55.419437885284445, 25.334988807638815],
                                ],
                            ],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'bottomLine',
                        },
                        geometry: {
                            type: 'LineString',
                            coordinates: [
                                [55.42360067367554, 25.33460092894936],
                                [55.42147636413574, 25.335803348840205],
                                [55.42107939720153, 25.335231231188487],
                                [55.42302131652832, 25.334077290746556],
                            ],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'marker',
                            label: 'Star #2',
                            color: 'blue',
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [55.42332172393799, 25.33587122702617],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'marker',
                            label: 'Star #1',
                            color: 'blue',
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [55.420124530792236, 25.335590017150714],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'marker',
                            color: 'gray',
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [55.4215407371521, 25.336588794091984],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: {
                            type: 'marker',
                            color: 'gray',
                        },
                        geometry: {
                            type: 'Point',
                            coordinates: [55.42234539985657, 25.33490153504211],
                        },
                    },
                ],
            };

            const source = new mapgl.GeoJsonSource(map, {
                data,
                attributes: {
                    bar: 'asd',
                },
            });

            map.on('styleload', () => {
                map.addLayer(
                    {
                        type: 'polygon',
                        id: 'my-stars',
                        filter: [
                            'all',
                            ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                            ['match', ['get', 'type'], ['star'], true, false],
                        ],
                        style: {
                            color: '#fcc9ff',
                        },
                    },
                    '31871',
                );
                map.addLayer(
                    {
                        type: 'dashedLine',
                        id: 'my-dashedline',
                        filter: [
                            'all',
                            ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                            ['match', ['get', 'type'], ['topLine'], true, false],
                        ],
                        style: {
                            color: '#0baf08',
                            width: 10,
                            dashLength: 10,
                            gapLength: 5,
                        },
                    },
                    '973940',
                );
                map.addLayer(
                    {
                        type: 'line',
                        id: 'my-line',
                        filter: [
                            'all',
                            ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                            ['match', ['get', 'type'], ['bottomLine'], true, false],
                        ],
                        style: {
                            color: '#ffcd17',
                            width: 7,
                        },
                    },
                    '973940',
                );
                map.addLayer({
                    type: 'point',
                    id: 'my-marker',
                    filter: [
                        'all',
                        ['match', ['sourceAttr', 'bar'], ['asd'], true, false],
                        ['match', ['get', 'type'], ['marker'], true, false],
                    ],
                    style: {
                        iconImage: ['match', ['get', 'color'], ['blue'], 'ent_i', 'ent'],
                        iconWidth: 25,
                        textField: ['get', 'label'],
                        textFont: ['Noto_Sans'],
                        textColor: '#0098ea',
                        textHaloColor: '#fff',
                        textHaloWidth: 1,
                        iconPriority: 100,
                        textPriority: 100,
                    },
                });
            });
        </script>
    </body>
</html>