Skip to content

2gis/mapgl-terra-draw

Repository files navigation

MapGL TerraDraw Adapter

TerraDraw adapter for MapGL JS API or just a simple drawing tool.

intro pic

Demo

Drawing Modes User Manual

Getting started

Install library

npm install @2gis/mapgl-terra-draw

Use ui-helper createTerraDrawWithUI and not forget to plug css:

import { load } from '@2gis/mapgl';
import { createTerraDrawWithUI } from '@2gis/mapgl-terra-draw';
import '@2gis/mapgl-terra-draw/dist/mapgl-terra-draw.css';

load().then((mapgl) => {
    const map = new mapgl.Map('map', {
        center: [55.31878, 25.23584],
        zoom: 13,
        key: 'Your MapGL JS API key',
        enableTrackResize: true,
    });

    map.on('styleload', () => {
        createTerraDrawWithUI({
            map,
            mapgl: mapgl as any,
            controls: ['color', 'select', 'point', 'polygon', 'circle', 'download', 'clear'],
        });
    });
});

Or directly in HTML via unpkg CDN

<html>
    <head>
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />
        <link rel="stylesheet" type="text/css" href="https://unpkg.com/@2gis/mapgl-terra-draw@0.2.0/dist/mapgl-terra-draw.css" />
        <script src="https://mapgl.2gis.com/api/js/v1"></script>
        <script src="https://unpkg.com/terra-draw@1.0.0/dist/terra-draw.umd.js"></script>
        <script src="https://unpkg.com/@2gis/mapgl-terra-draw/dist/mapgl-terra-draw.umd.cjs"></script>
        <style>
            html,
            body,
            #container {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script>
            const map = new mapgl.Map('container', {
                center: [55.31878, 25.23584],
                zoom: 13,
                key: 'bfd8bbca-8abf-11ea-b033-5fa57aae2de7',
                enableTrackResize: true,
            });

            map.on('styleload', () => {
                mapglTerraDraw.createTerraDrawWithUI({
                    map,
                    mapgl: mapgl,
                    controls: ['color', 'select', 'point', 'polygon', 'circle', 'download', 'clear'],
                });
            });
        </script>
    </body>
</html>

Advanced usage

If advanced cases (use your custom drawing mode, customize a very flexible TerraDraw selection behaviour, design a fancy UI, e.g.) you can use TerraDrawMapGlAdapter class directly.

This gives you much more flexibility, but puts a some bunch of work on your side. Here is a simple example:

import { load } from '@2gis/mapgl';
import {
    TerraDraw,
    TerraDrawPointMode,
    TerraDrawPolygonMode,
    TerraDrawSelectMode,
} from 'terra-draw';
import { TerraDrawMapGlAdapter } from '@2gis/mapgl-terra-draw';

load().then((mapgl) => {
    const map = new mapgl.Map('map', {
        center: [55.31878, 25.23584],
        zoom: 13,
        key: 'Your MapGL JS API key',
        enableTrackResize: true,
    });

    map.on('styleload', () => {
        const draw = new TerraDraw({
            adapter: new TerraDrawMapGlAdapter({
                map,
                mapgl,
                coordinatePrecision: 9,
            }),
            modes: [
                new TerraDrawSelectMode(),
                new TerraDrawPointMode(),
                new TerraDrawPolygonMode(),
            ],
        });

        const buttons = document.createElement('div');
        buttons.style.display = 'flex';
        buttons.style.flexDirection = 'column';
        buttons.style.gap = '8px';
        new mapgl.Control(map, buttons, { position: 'centerLeft' });

        const selectButton = document.createElement('button');
        selectButton.innerText = 'select';
        selectButton.addEventListener('click', () => {
            draw.setMode('select');
        });
        buttons.appendChild(selectButton);

        const pointButton = document.createElement('button');
        pointButton.innerText = 'point';
        pointButton.addEventListener('click', () => {
            draw.setMode('point');
        });
        buttons.appendChild(pointButton);

        const polygonButton = document.createElement('button');
        polygonButton.innerText = 'polygon';
        polygonButton.addEventListener('click', () => {
            draw.setMode('polygon');
        });
        buttons.appendChild(polygonButton);

        const clearButton = document.createElement('button');
        clearButton.innerText = 'clear';
        clearButton.addEventListener('click', () => {
            draw.clear();
        });
        buttons.appendChild(clearButton);

        draw.start();
    });
});

How to get a drawed data

To get drawing data with styling use this code snippet:

const adapter = new TerraDrawMapGlAdapter({
    ...
});
const { draw } = createTerraDrawWithUI({
    adapter,
    ...
});

const features = draw.getSnapshot();
const { icons, layers } = adapter.addStyling(features);
const featureCollection = {
    type: 'FeatureCollection',
    icons,
    layers,
    features,
};

Here we obtain a standart GeoJSON FeatureCollection and put icons and layers props in the root (which is permitted by GeoJSON specification).

To display this data, you should add icons and layers to your MapGL map, and add GeoJSON via GeoJsonSource

for (const icon in featureCollection.icons) {
    map.addIcon(icon, { url: featureCollection.icons[icon] });
}
for (const layer of featureCollection.layers) {
    map.addLayer(layer);  
}
const source = new mapgl.GeoJsonSource(map, {
    data: featureCollection,
    attributes: {
        name: 'terra-draw-output',
    },
});

You can use demo on codepen for reference.

Raw Data

If you want just geojson shapes of drawed feature use a .getSnapshot() method of a TerraDraw.

const { draw } = createTerraDrawWithUI({
    ...
});

...

draw.getSnapshot();

Material Icons

UI relies on Material Icons font to display icons. So you should include following link to your HTML head.

<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />

Deploy

npm run build
npm publish --access=public

LICENSE

MIT