2.1.7 • Published 26 days ago

leaflet-draw-manager v2.1.7

Weekly downloads
-
License
ISC
Repository
github
Last release
26 days ago

Leaflet Draw Manager

Drawing shapes on maps made easier with Leaflet. Classes designed for drawing and editing shapes on a map manually.

Demo

(Work in Progress)

Documentation

Table of Contents

tl;dr

  • Install using npm i --save leaflet-draw-manager.
  • Import { ShapeFactory } from "leaflet-draw-manager".
  • Instantiate ShapeFactory: const shapeFactory = ShapeFactory.getInstance().
  • Instantiate any class: const drawPolygon = shapeFactory.getPolygonInstance(map, featureGroup, shapeOptions).
  • Start drawing: drawPolygon.startDrawing().

What's New?

View CHANGELOG: https://github.com/mike16345/leaflet-draw-manager/blob/main/CHANGELOG.md

Basic Usage

This can be replaced with any class. Note: Not all classes have the handleUndoClick method.

// App.tsx

import "./App.css";
import { MapContainer, TileLayer } from "react-leaflet";
import CirclesInMap from "./Circle";

function App() {
  const position = { lat: 44.5, lng: -89.5 };

  return (
    <>
      <MapContainer
        className="map map-container z-[1]"
        minZoom={6}
        zoom={14}
        zoomControl={false}
        center={position}
        scrollWheelZoom={true}
      >
        <TileLayer
          url="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
          // tms={true}
          maxNativeZoom={16}
          maxZoom={20}
        />
        <CirclesInMap />
      </MapContainer>
    </>
  );
}

export default App;
// CirclesInMap.tsx

import { useRef } from "react";
import L, { Circle, CircleOptions } from "leaflet";
import { FeatureGroup, useMap } from "react-leaflet";
import { ShapeFactory, DrawCircle } from "leaflet-draw-manager";

const CirclesInMap = () => {
  const map = useMap();
  const circleGroup = useRef < L.FeatureGroup > null;
  const circleOptions: CircleOptions = { color: "red", radius: 0 };
  const shapeFactory = ShapeFactory.getInstance();
  const drawCircle = (useRef < DrawCircle) | (null > null);
  const latestCircle = (useRef < Circle) | (null > null);

  const handleDrawCircle = () => {
    if (!circleGroup.current) return;
    drawCircle.current = shapeFactory.getCircleInstance(
      map,
      circleGroup.current,
      circleOptions
    );
    drawCircle.current.startDrawing();
    drawCircle.current.setCustomOnFinishHandler((circle: Circle | null) => {
      latestCircle.current = circle;
    });
  };

  const handleEditCircle = () => {
    if (!drawCircle.current || !latestCircle.current) return;

    drawCircle.current.editShape(latestCircle.current);
  };

  const handleDeleteCircle = () => {
    if (!drawCircle.current) return;
    drawCircle.current.deleteShape();
  };

  const handleStopDrawing = () => {
    if (!drawCircle.current) return;
    drawCircle.current.stopDrawing();
  };

  const handleCancelEdit = () => {
    if (!drawCircle.current) return;
    drawCircle.current.cancelEdit();
  };

  return (
    <div className="draw-container">
      <button onClick={handleDrawCircle} className="draw-button">
        Draw Circle
      </button>
      <button onClick={handleStopDrawing} className="draw-button">
        Stop Drawing
      </button>
      <button onClick={handleEditCircle} className="draw-button">
        Edit Circle
      </button>
      <button onClick={handleCancelEdit} className="draw-button">
        Cancel Edit
      </button>
      <button onClick={handleDeleteCircle} className="draw-button">
        Delete Circle
      </button>
      <FeatureGroup ref={circleGroup}></FeatureGroup>
    </div>
  );
};

export default CirclesInMap;

Classes

ShapeFactory

ShapeFactory is in charge of creating class instances for shapes. It takes care of handling class cleanups when creating a new class instance therefore mantaining the Singleton implementation.

All classes can only be instantiated using the ShapeFactory class. The reason for this is to avoid having conflicts with events in other shape classes while drawing or editing. Any attempt to access an instance of a shape class outside the ShapeFactory class will throw an exception.

MethodDescriptionExample
static getInstance(classConfig?: IShapeClassConfig): ShapeFactoryCreates a new instance of the ShapeFactoryClass if it hasn't been created yet, and returns the existing instance.const shapeFactory = ShapeFactory.getInstance(classConfig);
setShapeConfig(config: IShapeClassConfig): voidSets the class configuration for the shape classes.shapeFactory.setShapeConfig(config);
getClassConfig():IShapeClassConfigReturns the current class configuration for the shape classes.shapeFactory.getClassConfig(config)
getPolygonInstance(map: Map, featureGroup: FeatureGroup, polygonOptions: PolylineOptions): DrawPolygonReturns an instance of the DrawPolygon class.const polygonInstance = shapeFactory.getPolygonInstance(map, featureGroup, polygonOptions);
getPolylineInstance(map: Map, featureGroup: FeatureGroup, polylineOptions: PolylineOptions): DrawPolylineReturns an instance of the DrawPolyline class.const polylineInstance = shapeFactory.getPolylineInstance(map, featureGroup, polylineOptions);
getCircleInstance(map: Map, featureGroup: FeatureGroup, circleOptions: CircleOptions): DrawCircleReturns an instance of the DrawCircle class.const circleInstance = shapeFactory.getCircleInstance(map, featureGroup, circleOptions);
getMarkerInstance(map: Map, featureGroup: FeatureGroup, markerOptions: L.MarkerOptions): DrawMarkerReturns an instance of the DrawMarker class.const markerInstance = shapeFactory.getMarkerInstance(map, featureGroup, markerOptions);
getArrowPolylineInstance(map: Map, featureGroup: FeatureGroup, polylineOptions: PolylineOptions): DrawArrowPolylineReturns an instance of the DrawArrowPolyline class.const arrowPolylineInstance = shapeFactory.getArrowPolylineInstance(map, featureGroup, polylineOptions);

ShapeClassConfig

ShapeClassConfig is a private class which provides a centralized mechanism to manage and apply configuration settings for various shape classes used in mapping applications. It allows developers to easily update and retrieve configuration settings for individual shape classes, ensuring consistency and flexibility in the application's behavior and appearance.

Any time a class is instantiated the configuration settings will automatically be applied to that class.

Accessed through the ShapeFactory class.

PropertyDescriptionDefault Value
displayLineDistancesFlag indicating whether to display the distances between points. (LineShapes only)false
displayVertexNumbersFlag indicating whether to display the number on the points. (LineShapes only)false
isTouchDeviceFlag indicating whether the device is touch-sensitive or not.false
isDraggableFlag indicating whether the shape should be draggable. (Markers/Polygons)false
vertexIconIcon for vertices that are used when drawing/editing shapes.null
midpointIconIcon for midpoint vertices that are used when drawing/editing shapes.null
polygonDragIconIcon that is used when dragging a polygon.null
eventsCustom event handlers.null

DrawShape - All classes have access to DrawShape's properties and methods.

MethodDescriptionExample
on(event: keyof IDrawManagerEvents, callback: Function)Sets a custom event handler for the shape.drawShape.on("onEditStart", () => { /* Your code here */ });
off(event: keyof IDrawManagerEvents)Removes an event handler from the shape class.drawShape.off("onEditStart");
stopDrawing()Stops drawing and resets the state of the class.drawShape.stopDrawing();
disableDrawEvents()Disables mouse and touch events for drawing.drawShape.disableDrawEvents();
deleteShape()Deletes the current shape from the map and resets the state of the class.drawShape.deleteShape();
setIsTouchDevice(isTouchDevice: boolean)Sets a flag indicating whether it is a touch device or not.drawShape.setIsTouchDevice(true);
getDrawMode()Retrieves the current draw mode of the shape.const mode = drawShape.getDrawMode();
getCurrentShape()Retrieves the current shape being drawn or edited.const shape = drawShape.getCurrentShape();
getShapeType()Retrieves the type of shape being drawn or edited.const type = drawShape.getShapeType();
setIsDraggable(isDraggable: boolean)Sets a flag indicating whether the shape should be draggable.drawShape.setIsDraggable(true);
setVertexIcon(vertexIcon: L.DivIcon \| L.Icon \| null)Sets the icon for the vertices of the shape.drawShape.setVertexIcon(icon);
setMidpointVertexIcon(midpointVertexIcon: L.DivIcon \| L.Icon \| null)Sets the icon for the midpoint vertices of the shape.drawShape.setMidpointVertexIcon(icon);

DrawLineShape - DrawPolygon/DrawPolyline/DrawArrowPolyline

DrawPolygon/DrawPolyline/DrawArrowPolyline all inherit these methods from the DrawLineShape class.

MethodDescriptionExample
startDrawing(drawVertices?: boolean)Initiates the drawing of the shape.drawLineShape.startDrawing();
cancelEdit()Cancels the current editing operation and reverts the shape to its state before editing.drawLineShape.cancelEdit();
editShape(shape: T)Initiates the editing mode for the specified shape.drawLineShape.editShape(shape);
redrawShape(): T \| undefinedRedraws the current shape on the map with updated coordinates.drawLineShape.redrawShape();
setLatLngs(latLngs: LatLng[])Sets the coordinates of the shape and redraws it on the map.drawLineShape.setLatLngs(latLngs);
displayLineDistances(display: boolean)Controls the display of line distances for the shape vertices.drawLineShape.displayLineDistances(true);
getDisplayLineDistances()Retrieves the current display state of line distances for the shape vertices.drawLineShape.getDisplayLineDistances();
setShapeOptions(options: PolylineOptions)Sets the options for the current shape.drawLineShape.setShapeOptions(options);
changeShapeAttribute(attribute: keyof PolylineOptions, value: any)Changes the value of a shape attribute.drawLineShape.changeShapeAttribute("color", "blue");
setDisplayVertexNumbers(display: boolean)Sets the option to display the numbers of the vertices and redraws them.drawLineShape.setDisplayVertexNumbers(true);

DrawPolygon

MethodDescriptionExample
static getInstance(map: L.Map, featureGroup: L.FeatureGroup, shapeOptions: L.PolylineOptions): DrawPolygonRetrieves the singleton instance of DrawPolygon or creates a new one if it does not exist.const drawPolygon = DrawPolygon.getInstance(map, featureGroup, shapeOptions);
resetInstance()Stops drawing polygons and resets the singleton instance of DrawPolygon.drawPolygon.resetInstance();
drawShape(latLngs: L.LatLng[] \| null = null): L.PolygonDraws a polygon on the map.const polygon = drawPolygon.drawShape(latLngs);
on(event: keyof IDrawManagerEvents, callback: Function): voidSets a custom event handler for the shape.drawPolygon.on("onEditStart", () => { /* Your code here */ });
removeDragMarker()Removes the drag marker from the map if it exists.drawPolygon.removeDragMarker();
setDragIcon(icon: Icon \| DivIcon): voidSets the icon for the drag marker.drawPolygon.setDragIcon(icon);

DrawPolyline

| Method | Description | Example |

| drawTransparentPolyline(latLngs:LatLng[]) | Creates a transparent polyline based on the provided set of LatLng coordinates. The transparent polyline has a weight of 40. This can be used to help capture clicks on a polyline if given the same coordinates. /| DrawPolyline.drawTransparentPolyline(coordinates)

DrawCircle

MethodDescriptionExample
static getRadiusLatLng(circle: Circle): LatLngCalculates the coordinates of two points on the circumference of a given circle.DrawCircle.getRadiusLatLng(circleCenter, radius);

DrawMarker

MethodDescriptionExample
drawTextMarker(latLng: L.LatLng[] \| null = null): MarkerCreates a text marker on the map.drawMarker.drawTextMarker([latLng]);
startDrawing(): voidStarts drawing the marker on the map.drawMarker.startDrawing();
stopDrawing(): voidStops drawing the marker on the map.drawMarker.stopDrawing();
resetInstance(): voidResets the instance of DrawIcon.drawMarker.resetInstance();
editShape(marker: L.Marker): L.MarkerEdits an existing marker.const editedMarker = drawMarker.editShape(existingMarker);
cancelEdit(): voidCancels editing an existing marker.drawMarker.cancelEdit();
deleteShape(): voidDeletes the marker shape.drawMarker.deleteShape();
drawShape(latLngs: L.LatLng[] \| null = null): MarkerDraws a marker on the map.const marker = drawMarker.drawShape([latLng]);
initDrawEvents(): voidInitializes the events for drawing the marker.drawMarker.initDrawEvents();
setIsDraggable(isDraggable: boolean): voidSets whether the marker should be draggable.drawMarker.setIsDraggable(true);
setMarkerIcon(iconOptions: L.IconOptions): voidSets the icon options for the marker.drawMarker.setMarkerIcon({ iconUrl: 'marker.png' });
setShapeOptions(options: L.MarkerOptions): voidSets the options for the marker shape.drawMarker.setShapeOptions({ color: 'red' });
setLatLng(latLng: LatLng): voidSets the latitude and longitude for the marker.drawMarker.setLatLng(new LatLng(40.7128, -74.0060));
setIsTextMarker(isText: boolean): voidSets whether the marker should be a text marker.drawMarker.setIsTextMarker(true);

Helper utilities

Here are a list of some functions/enums/interfaces that can be helpful while developing.

Helper UtilityDescription
getShapePositionsA function that retrieves the positions of the vertices of a given shape.
convertToLatLngInstancesA function that converts an array of latitude and longitude coordinates to LatLng instances.
LeafletShapeA type representing various Leaflet shapes such as Circle, Polygon, Polyline, Marker, and Icon.
ShapeClassA union type representing different shape classes used for drawing and editing shapes.
ShapeOptionsA union type representing options for different shapes such as Polyline, Marker, and Circle.
DrawManagerModeAn enum representing different modes of the DrawManager: START, DRAW, EDIT, and STOP.
ShapesAn enum representing different shape types: POLYGON, POLYLINE, ICON, MARKER, CIRCLE, ARROW_POLYLINE.
IShapeClassConfigAn interface representing the configuration options for shape classes.

Custom Event Handlers

Event NameDescriptionExample
onFinishFired when stopDrawing() method is called. This event provides the final shape object as a parameter.shapeInstance.on("onFinish", (shape: LeafletShape \| null) => { /* Your code here */ });
onAddPointFired when a new point is added to the shape during drawing. The updated shape's coordinates are provided as parameters.shapeInstance.on("onAddPoint", (latlngs: LatLng[]) => { /* Your code here */ });
onDeletePointFired when a point is deleted from the shape during drawing/editing. The coordinates of the shape after the point has been deleted are provided.shapeInstance.on("onDeletePoint", (latlngs: LatLng[]) => { /* Your code here */ });
onDragVertexFired continuously while user is dragging a vertex of the shape. The coordinates of the updated shape are provided.shapeInstance.on("onDragVertex", (latlngs: LatLng[]) => { /* Your code here */ });
onDragEndVertexFired when dragging of a vertex ends during editing. The final coordinates of the shape is provided.shapeInstance.on("onDragEndVertex", (latlngs: LatLng[]) => { /* Your code here */ });
onDragVertexStartFired when user starts dragging a vertex. No parameters are provided.shapeInstance.on("onDragVertexStart", () => { /* Your code here */ });
onDragMidpointVertexFired continuously while user is dragging a midpoint vertex of the shape. The updated coordinates of the shape are provided.shapeInstance.on("onDragMidpointVertex", (latlngs: LatLng[]) => { /* Your code here */ });
onDragEndMidpointVertexFired when the user stop dragging a midpoint vertex. The final coordinates of the shape are provided.shapeInstance.on("onDragEndMidpointVertex", (latlngs: LatLng[]) => { /* Your code here */ });
onDragMidpointVertexStartFired when user starts dragging a midpoint vertex. No parameters are provided.shapeInstance.on("onDragMidpointVertexStart", () => { /* Your code here */ });
onDeleteShapeFired when the deleteShape() method is called. No parameters are provided.shapeInstance.on("onDeleteShape", () => { /* Your code here */ });
onDrawStartFired when the startDrawing() method is called. No parameters are provided.shapeInstance.on("onDrawStart", () => { /* Your code here */ });
onEditStartFired when editShape(shapeToEdit) method is called. No parameters are provided.shapeInstance.on("onEditStart", () => { /* Your code here */ });
onEditFired when the coordinates of the shape are changed . The updated coordinates are provided.shapeInstance.on("onEdit", (latLngs:LatLng[]) => { /_ Your code here _/ });
onCancelEditFired when the cancelEdit() method is called. The shape object after the canceled edit is provided as a parameter.shapeInstance.on("onCancelEdit", (shape: LeafletShape \| null) => { /* Your code here */ });
onDragCenterStartFired when the center of a polygon/circle is being dragged. No parameters are provided.shapeInstance.on("onDragCenterStart", () => { /* Your code here */ });
onDragCenterFired continuously while user is dragging the center of a polygon/circle of the shape. The updated coordinates of the shape are provided.shapeInstance.on("onDragMidpointVertex", (latlngs: LatLng[]) => { /* Your code here */ });
onDragCenterEndFired when user stops dragging the center of a polygon/circle of the shape. The updated coordinates of the shape are provided.shapeInstance.on("onDragMidpointVertex", (latlngs: LatLng[]) => { /* Your code here */ });
2.1.6

26 days ago

2.1.7

26 days ago

2.1.4

28 days ago

2.1.5

28 days ago

2.1.2

1 month ago

2.1.3

1 month ago

2.1.1

1 month ago

2.1.0

1 month ago

2.0.1

1 month ago

2.0.0

1 month ago

1.0.1

2 months ago

1.0.0

2 months ago