在Leaflet-Geoman中编辑图层(在NextJs中)

zbq4xfa0  于 2023-06-29  发布在  其他
关注(0)|答案(1)|浏览(162)

我想让用户能够在NextJs中的LeafletMap上使用Geoman进行CRUD操作。我的代码可以很好地创建和删除层,但是当我试图编辑我的层时(无论是移动它们,向它们添加额外的点,还是在它们中切割洞),尽管我试图为此添加合适的事件,但什么也没有发生。
下面是我的Map.tsx,我在这里生成我的Map:

import "leaflet/dist/leaflet.css";
import { LayersControl, MapContainer, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
import { v4 as uuidv4 } from "uuid";

import React, { useState } from "react";
import type { FC } from "react";
import * as L from "leaflet";
import { GeomanControl } from "./GeomanControl";
import { DoneControl } from "./DoneButton";
import { CancelControl } from "./CancelButton";

interface IMapProps {
  isDone: boolean;
  setIsDone: (isDone: boolean) => void;
}

interface MyLayer extends L.Layer {
  _leaflet_id?: string;
  coords:
    | L.LatLngExpression[]
    | L.LatLngExpression[][]
    | L.LatLngExpression[][][];
}

const Map: FC<IMapProps> = ({ isDone, setIsDone }) => {
  const washingtonDC = L.latLng(38.9072, -77.0369);
  const mapStyle = { height: "100vh", width: "100%", padding: 0 };

  const [polygons, setPolygons] = useState<
    {
      id: string;
      coords:
        | L.LatLngExpression[]
        | L.LatLngExpression[][]
        | L.LatLngExpression[][][];
    }[]
  >([]);

  console.log(isDone);
  return (
    <React.Fragment>
      <MapContainer
        center={washingtonDC}
        zoom={8}
        zoomControl={false}
        style={mapStyle}
        //whenReady={() => {}}
      >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
        />

        <GeomanControl
          position="bottomleft"
          oneBlock
          onCreate={(layer) => {
            // Get the layer's coordinates and update the state variable
            const latlngs = (layer as L.Polygon).getLatLngs();

            // Generate a unique ID for the polygon
            // eslint-disable-next-line @typescript-eslint/no-unsafe-call
            const id = uuidv4() as string;

            // Add the polygon to the state
            setPolygons((prevPolygons) => [
              ...prevPolygons,
              { id, coords: latlngs },
            ]);

            // Assign the ID to the layer
            (layer as MyLayer)._leaflet_id = id;
          }}
          onUpdate={(layer) => {
            const latlngs = (layer as L.Polygon).getLatLngs();
            const id = (layer as MyLayer)._leaflet_id;

            console.log("Updated coordinates:", latlngs);
            setPolygons((prevPolygons) =>
              prevPolygons.map((polygon) =>
                polygon.id === id ? { id, coords: latlngs } : polygon
              )
            );
          }}
          onRemove={(layer) => {
            const id = (layer as MyLayer)._leaflet_id;

            setPolygons((prevPolygons) =>
              prevPolygons.filter((polygon) => polygon.id !== id)
            );
          }}
        />
        <DoneControl
          position="topright"
          clickHandler={() => {
            console.log("Done button clicked!");
            setIsDone(true);
            console.log("isDone: ", isDone);
          }}
        />
        <CancelControl />

        {/* Display different map layers */}
        <LayersControl position="topright">
          <LayersControl.BaseLayer checked name="OpenStreetMap.Mapnik">
            <TileLayer
              zIndex={1}
              attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              maxNativeZoom={19}
              maxZoom={25}
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="MapBox.Satellite">
            <TileLayer
              zIndex={1}
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url={`https://api.mapbox.com/styles/v1/${"mapbox/satellite-streets-v11"}/tiles/{z}/{x}/{y}?access_token=${
                process.env.NEXT_PUBLIC_MAPBOX_TOKEN || ""
              }`}
              maxNativeZoom={21}
              maxZoom={25}
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="MapBox.Outdoors">
            <TileLayer
              zIndex={1}
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url={`https://api.mapbox.com/styles/v1/${"mapbox/outdoors-v11"}/tiles/{z}/{x}/{y}?access_token=${
                process.env.NEXT_PUBLIC_MAPBOX_TOKEN || ""
              }`}
              maxNativeZoom={21}
              maxZoom={25}
            />
          </LayersControl.BaseLayer>
        </LayersControl>
      </MapContainer>
    </React.Fragment>
  );
};

export default Map;

下面是我的GeomanControl.tsx:

import { createControlComponent } from "@react-leaflet/core";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";

interface Props extends L.ControlOptions {
  position: L.ControlPosition;
  drawCircle?: boolean;
  oneBlock?: boolean;
  onCreate: (layer: MyLayer) => void;
  onRemove: (layer: MyLayer) => void;
  onUpdate: (layer: MyLayer) => void;
}

interface MyLayer extends L.Layer {
  _leaflet_id?: string;
}

class Geoman extends L.Control {
  options: Props;

  constructor(options: Props) {
    super(options);
    this.options = options;
  }

  onAdd(map: L.Map): HTMLElement {
    if (map.pm) {
      map.pm.addControls({
        position: this.options.position,
        oneBlock: this.options.oneBlock,
        drawCircleMarker: false,
        drawMarker: false,
        drawPolyline: false,
        drawText: false,
        drawCircle: false,
      });

      // When a layer is created by drawing or importing data
      map.on("pm:create", (e: { layer: MyLayer }) => {
        if (this.options.onCreate) {
          this.options.onCreate(e.layer);
        }
      });

      // When a layer is updated
      map.on("pm:update", (e: { layer: MyLayer }) => {
        if (this.options.onUpdate) {
          this.options.onUpdate(e.layer);
        }
      });

      // When a layer is updated
      map.on("pm:change", (e: { layer: MyLayer }) => {
        if (this.options.onUpdate) {
          this.options.onUpdate(e.layer);
        }
      });

      // When a layer is dragged
      map.on("pm:dragend", (e: { layer: MyLayer }) => {
        if (this.options.onUpdate) {
          this.options.onUpdate(e.layer);
        }
      });

      // When a layer's vertices are edited
      map.on("pm:edit", (e: { layer: MyLayer }) => {
        if (this.options.onUpdate) {
          this.options.onUpdate(e.layer);
        }
      });

      // When a layer is cut, edited, or dragged
      map.on("pm:cut", (e: { layer: L.Layer }) => {
        if (this.options.onUpdate) {
          this.options.onUpdate(e.layer);
        }
      });
    }
    return L.DomUtil.create("div");
  }

  onRemove(map: L.Map): void {
    if (map.pm) {
      map.pm.removeControls();
    }

    map.off("pm:create");
    map.off("pm:update");
    map.off("pm:update");
    map.off("pm:dragend");
    map.off("pm:edit");
    map.off("pm:cut");

    map.on("pm:remove", (e: { layer: MyLayer }) => {
      if (this.options.onRemove) {
        this.options.onRemove(e.layer);
      }
    });
  }
}

const createGeomanInstance = (props: Props) => new Geoman(props);

export const GeomanControl = createControlComponent(createGeomanInstance);

如何解决这个问题的所有建议将不胜感激!!
我一直在添加我的其他工作代码(抱歉长URL)来思考链接:
https://codesandbox.io/p/github/peter-novak-m/leaflet-geoman/master?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clito5f9h000b286fxsq8kl01%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clito5f9h000d286f8lhqpnrc%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clito5f9h000b286fxsq8kl01%2522%253A%257B%2522id%2522%253A%2522clito5f9h000b286fxsq8kl01%2522%252C%2522activeTabId%2522%253A%2522clitrmlb90059286f6292mwnm%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clito5f9h000a286fmtwajz9b%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Fmodules%252Fproject%252Fcomponents%252FMapArea%252FGeomanControl.tsx%2522%252C%2522id%2522%253A%2522clitrmlb90059286f6292mwnm%2522%252C%2522mode%2522%253A%2522temporary%2522%257D%255D%257D%252C%2522clito5f9h000d286f8lhqpnrc%2522%253A%257B%2522id%2522%253A%2522clito5f9h000d286f8lhqpnrc%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clito5wow006e286f0f4vwhb6%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A3000%252C%2522id%2522%253A%2522clitp3l9f00fb286fizr9wwk2%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clitp3l9f00fb286fizr9wwk2%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D

oymdgrw7

oymdgrw71#

我有这样的问题,兄弟!如果你找到任何解决方案,请让我知道他们!我也在找呢!

相关问题