mapbox-gl-draw icon indicating copy to clipboard operation
mapbox-gl-draw copied to clipboard

How initialize the polygons on the map then edit it.

Open ghost opened this issue 10 months ago • 1 comments

The code below tries to add a predefined polygons and loads it into map so I can edit it. I have used map.on('load'....) but still get error:

Uncaught TypeError: Cannot read properties of undefined (reading 'get')
'use client'
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
import MapboxDraw from "@mapbox/mapbox-gl-draw";
import { useControl, type ControlPosition, type MapRef } from "react-map-gl/maplibre";
import { FeatureCollection } from 'geojson';
import { useRef } from 'react';

export type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
    position?: ControlPosition;
    onCreate?: (evt: MapboxDraw.DrawCreateEvent) => void;
    onUpdate?: (evt: MapboxDraw.DrawUpdateEvent) => void;
    onDelete?: (evt: MapboxDraw.DrawDeleteEvent) => void;
};

// @ts-ignore
MapboxDraw.constants.classes.CONTROL_BASE = "maplibregl-ctrl";
// @ts-ignore
MapboxDraw.constants.classes.CONTROL_PREFIX = "maplibregl-ctrl-";
// @ts-ignore
MapboxDraw.constants.classes.CONTROL_GROUP = "maplibregl-ctrl-group";


const preloadedFeatures: FeatureCollection = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            geometry: {
                type: 'Polygon',
                coordinates: [
                    [
                        [-97.23839195565238, 49.96781104119992],
                        [-97.23923240023636, 49.8362686108012],
                        [-97.02407858673101, 49.831931896639674],
                        [-97.04508970133088, 49.96835162714311],
                        [-97.23839195565238, 49.96781104119992],
                    ],
                ],
            },
            properties: { name: 'Winnipeg Rectangle' },
            id: 'winnipeg-rectangle',
        },
    ],
};

const DrawControl: React.FC<DrawControlProps> = (props: DrawControlProps) => {
    const drawRef = useRef<any>(null); // Store Draw Instance

    useControl(
        () => {
            drawRef.current = new MapboxDraw({ ...props });
            return drawRef.current;
        },
        ({ map }: { map: MapRef }) => {
            if (!drawRef.current) return;
            const draw = drawRef.current;

            if (props.onCreate) map.on("draw.create", props.onCreate);
            if (props.onUpdate) map.on("draw.update", props.onUpdate);
            if (props.onDelete) map.on("draw.delete", props.onDelete);

            map.on("load", () => {
                console.log("on map load");
                if (draw && preloadedFeatures) {
                    drawRef.current.add(preloadedFeatures);
                    //console.log("all features", draw.getAll());
                }
            });
        },
        ({ map }: { map: MapRef }) => {
            if (!drawRef.current) return;
            const draw = drawRef.current;

            if (props.onCreate) map.off("draw.create", props.onCreate);
            if (props.onUpdate) map.off("draw.update", props.onUpdate);
            if (props.onDelete) map.off("draw.delete", props.onDelete);
        },
        {
            position: props.position,
        }
    );

    return null;
};

export default DrawControl;

ghost avatar Feb 18 '25 14:02 ghost

This error is usually thrown when you forget to add map.addControl(draw) to your code.

Try the following code:

'use client'
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
import MapboxDraw from "@mapbox/mapbox-gl-draw";
import { useControl, type ControlPosition, type MapRef } from "react-map-gl/maplibre";
import { FeatureCollection } from 'geojson';
import { useRef } from 'react';

export type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
    position?: ControlPosition;
    onCreate?: (evt: MapboxDraw.DrawCreateEvent) => void;
    onUpdate?: (evt: MapboxDraw.DrawUpdateEvent) => void;
    onDelete?: (evt: MapboxDraw.DrawDeleteEvent) => void;
};

// @ts-ignore
MapboxDraw.constants.classes.CONTROL_BASE = "maplibregl-ctrl";
// @ts-ignore
MapboxDraw.constants.classes.CONTROL_PREFIX = "maplibregl-ctrl-";
// @ts-ignore
MapboxDraw.constants.classes.CONTROL_GROUP = "maplibregl-ctrl-group";


const preloadedFeatures: FeatureCollection = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            geometry: {
                type: 'Polygon',
                coordinates: [
                    [
                        [-97.23839195565238, 49.96781104119992],
                        [-97.23923240023636, 49.8362686108012],
                        [-97.02407858673101, 49.831931896639674],
                        [-97.04508970133088, 49.96835162714311],
                        [-97.23839195565238, 49.96781104119992],
                    ],
                ],
            },
            properties: { name: 'Winnipeg Rectangle' },
            id: 'winnipeg-rectangle',
        },
    ],
};

const DrawControl: React.FC<DrawControlProps> = (props: DrawControlProps) => {
    const drawRef = useRef<any>(null); // Store Draw Instance

    useControl(
        () => {
            drawRef.current = new MapboxDraw({ ...props });
            return drawRef.current;
        },
        ({ map }: { map: MapRef }) => {
            if (!drawRef.current) return;
            const draw = drawRef.current;

            if (props.onCreate) map.on("draw.create", props.onCreate);
            if (props.onUpdate) map.on("draw.update", props.onUpdate);
            if (props.onDelete) map.on("draw.delete", props.onDelete);

            map.on("load", () => {
                console.log("on map load");
                if (draw && preloadedFeatures) {
                    drawRef.current.add(preloadedFeatures);
                    //console.log("all features", draw.getAll());
                }
            });
        },
        ({ map }: { map: MapRef }) => {
            if (!drawRef.current) return;
            const draw = drawRef.current;

            map.addControl(draw);

            if (props.onCreate) map.off("draw.create", props.onCreate);
            if (props.onUpdate) map.off("draw.update", props.onUpdate);
            if (props.onDelete) map.off("draw.delete", props.onDelete);
        },
        {
            position: props.position,
        }
    );

    return null;
};

export default DrawControl;

fatorius avatar Mar 25 '25 02:03 fatorius