Skip to main content

Drawing Controller & Interactive Shapes

The DrawingController class provides an interface for drawing polygons, circles, and text notations directly on the map viewport.

Separate subpath

DrawingController and the drawing modes live under @sovereignsolutions/ss-map-gl/drawing, not the package root, so apps that never draw don't pay for the drawing engine in their bundle.


Initializing DrawingController​

import { DrawingController } from '@sovereignsolutions/ss-map-gl/drawing';

const drawingController = new DrawingController(mapEngine, {
showToolbar: true,
onDrawComplete: (features) => console.log('Drawing finished:', features),
onShapeSelect: (features) => console.log('Selected:', features),
onShapeUpdate: (features) => console.log('Updated:', features),
onShapeDelete: (features) => console.log('Deleted:', features),
});

DrawingController accepts either a MapEngine or a map created directly by another tool (for example react-map-gl or vue-maplibre-gl) - no change needed if you were already passing a MapEngine.


Supported Drawing Modes​

You can trigger drawing modes programmatically via drawingController.setMode(mode):

ModeDescription
'polygon'Click to place vertices, double-click to close the shape
'circle'Click to set center, drag to define radius
'notation'Click on the map to place a text label anchor point
'select'Select, move, and edit existing shapes
'trash'Delete the currently selected feature

Text Notation​

When notation mode is active, clicking the map places a point feature. An editor popup automatically opens allowing the user to configure the text content, font size (12px to 32px), and color (preset palette or custom hex picker). Text notations are exported as GeoJSON Point features with isNotation: true in properties - see GeoJSON Import & Export.


DrawingController Public API​

MethodSignatureDescription
setMode(mode: 'polygon' | 'circle' | 'notation' | 'select' | 'trash') => voidActivate a drawing or editing mode
getAllFeatures() => FeatureCollectionGet all drawn features as a GeoJSON FeatureCollection
addFeatures(features: FeatureCollection) => voidLoad GeoJSON features onto the drawing canvas
deleteFeature(id: string) => voidRemove a specific feature by ID
clear() => voidRemove all features from the drawing canvas
destroy() => voidCleanup all event listeners, popups, toolbar, and remove the draw control
draw (field)MapboxDrawDirect access to the underlying MapboxDraw instance for advanced use

Event Contract & Lifecycle Hooks​

The SDK provides direct callback event interfaces for all drawing interactions and map viewport lifecycle changes. Source: Event Contract & Lifecycle Hooks in the SDK README.

Callback HookEvent TypeDescriptionArgument Signature
onDrawStartDrawing ModeUser entered a drawing state(mode: string) => void
onDrawCompleteDraw CompleteShape finished drawing and added to map(features: Feature[]) => void
onDrawCreateDraw CreateRaw draw.create event (all shape types)(features: Feature[]) => void
onDrawUpdateDraw UpdateRaw draw.update event(features: Feature[]) => void
onDrawDeleteDraw DeleteRaw draw.delete event(features: Feature[]) => void
onShapeSelectShape SelectUser clicked/selected a shape on map(features: Feature[]) => void
onShapeUpdateShape UpdateShape vertex dragged, circle resized, or moved(features: Feature[]) => void
onShapeDeleteShape DeleteUser deleted a shape from the map(features: Feature[]) => void
onModeChangeMode ChangeSDK changed drawing mode internally (e.g. after shape completes)(mode: string) => void
onDragViewport Hook (MapEngine)Map viewport was panned/dragged() => void
onZoomViewport Hook (MapEngine)Map viewport was zoomed() => void
onBoundsChangeViewport Hook (MapEngine)Viewport bounds changed (at end of pan/zoom)(bounds: ViewportBounds) => void
drawingController.onDrawStart = (mode: string) => {
console.log('User started drawing in mode:', mode);
};

drawingController.onDrawComplete = (features) => {
console.log('New shape created:', features);
};

drawingController.onShapeUpdate = (features) => {
console.log('Shape vertices updated:', features);
};

drawingController.onShapeDelete = (features) => {
console.log('Shape removed:', features);
};

Cleanup & Unmount​

Invoke destroy() to remove layers, markers, listeners, controls, and DOM elements. Source: Cleanup & Unmount Behavior in the SDK README.

// Unmount Drawing Controller and toolbar
drawingController.destroy();

// Terminate the map instance
mapEngine.destroy();

Known Limitations​

  • Circle approximation: circles are represented as 64-vertex polygons. Resizing works smoothly, but fine coordinate precision is subject to 64-segment resolution.
  • Global cursor style conflicts: when switching modes, the underlying draw library alters CSS pointer styles. Hover interactions on clusters can overlay standard pointer rules.
  • Text notation rendering: notation labels are rendered using MapLibre symbol layers. Label visibility at very small zoom levels depends on the active base map style's collision detection settings.

See also: GeoJSON Import & Export.