### Full Usage Example with MapLibre GL Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/1.GETTING_STARTED.md A complete example demonstrating how to import Terra Draw and its MapLibre GL adapter, initialize a MapLibre map, create a Terra Draw instance with the adapter and modes, and start drawing. ```javascript // Import Terra Draw import { TerraDraw, TerraDrawRectangleMode } from "terra-draw"; import { TerraDrawMapLibreGLAdapter } from 'terra-draw-maplibre-gl-adapter // Import MapLibreGL import { MapLibreGL as lib } from "maplibre-gl"; // Create MapLibre Map, targeting
const map = new MapLibreGL.Map({ container: "map" }); // Create Terra Draw const draw = new TerraDraw({ // Using the MapLibre Adapter adapter: new TerraDrawMapLibreGLAdapter({ map, lib }), // Add the Rectangle Mode modes: [new TerraDrawRectangleMode()], }); // Start drawing draw.start(); draw.setMode("rectangle"); ``` -------------------------------- ### Install Terra Draw and OpenLayers Adapter Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/terra-draw-openlayers-adapter/README.md Install the core terra-draw package and the OpenLayers adapter using npm. ```shell npm install terra-draw terra-draw-openlayers-adapter ``` -------------------------------- ### Install Terra Draw and MapLibre GL Adapter Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/terra-draw-maplibre-gl-adapter/README.md Install the core Terra Draw package and the MapLibre GL adapter using npm. ```shell npm install terra-draw terra-draw-maplibre-gl-adapter ``` -------------------------------- ### Build Terra Draw Storybook Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/storybook/README.md Generate a static production build of the Storybook. This is useful for deployment or sharing examples. ```shell npm run storybook:build ``` -------------------------------- ### Run Terra Draw Storybook in Development Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/storybook/README.md Use this command to start the Storybook development server. This allows for live updates as you make changes to components. ```shell npm run storybook ``` -------------------------------- ### Remove Features by ID or Clear Store Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Provides examples for removing specific features from the store using their IDs and for clearing all features from the store. ```javascript // Remove Feature from the Store by ID draw.removeFeatures(["id-1", "id-2", "id-3"]); // Remove all Features from the Store draw.clear(); ``` -------------------------------- ### Custom Marker Styling in Custom Modes Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Example of how to style marker icons within a custom mode's `styleFeature` method, allowing dynamic configuration of marker properties. ```typescript styleFeature(feature: GeoJSONStoreFeatures): TerraDrawAdapterStyling { const styles = { ...getDefaultStyling() }; if ( feature.type === "Feature" && feature.geometry.type === "Point" && feature.properties.mode === this.mode ) { styles.zIndex = Z_INDEX.LAYER_THREE; styles.markerHeight = this.getNumericStylingValue( this.styles?.markerHeight, 30, // Whatever the default maker height is feature, ); styles.markerWidth = this.getNumericStylingValue( this.styles?.markerWidth, 30, // Whatever the default maker width is feature, ); styles.markerUrl = this.getUrlStylingValue( this.styles?.markerUrl, "https://www.example.com/your-custom-marker.png" feature, ); } return styles; } ``` -------------------------------- ### Styling TerraDrawPolygonMode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Example of how to style the TerraDrawPolygonMode by passing a styles object to its constructor. Colors are represented as 6-digit Hex colors. ```javascript const draw = new TerraDraw({ // Create Adapter adapter: new TerraDrawMapboxGLAdapter({ map, lib }), // Create Modes modes: [ // Polygon Mode new TerraDrawPolygonMode({ // Pass styles to the constructor styles: { // Fill colour (a string containing a 6 digit Hex color) fillColor: "#00FFFF", // Fill opacity (0 - 1) fillOpacity: 0.7, // Outline colour (Hex color) outlineColor: "#00FF00", //Outline width (Integer) outlineWidth: 2, }, }), ], }); ``` -------------------------------- ### Listen for Select Event Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Get selected features by listening to the 'select' event. This method provides the ID of the selected feature. ```typescript draw.on('select', (id: string) => { const snapshot = draw.getSnapshot() // Search the snapshot for the selected polygon const polygon = snapshot.find((feature) => feature.id === id) }) ``` -------------------------------- ### Retrieve All Features from Store Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Get a deep copy of all features currently in the store using `getSnapshot`. Mutating the returned array will not affect the store's state. ```javascript // Get an array of all features in the Store. These features will be copies. const features = draw.getSnapshot(); ``` -------------------------------- ### Add Marker Feature with Properties Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Example of adding a feature programmatically that will render as a marker icon. The 'marker: true' property in the GeoJSON properties is crucial for this. ```typescript draw.addFeatures([ { type: "Feature", geometry: { type: "Point", coordinates: [-0.09, 51.505] }, properties: { mode: "marker", // or your custom mode name marker: true, // Required for marker icon rendering } } ]); ``` -------------------------------- ### Render Mode Styling for Points Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Example of creating a Terra Draw instance with a Render Mode to style uneditable points. This includes setting a unique mode name and defining point styles. ```javascript const draw = new TerraDraw({ adapter: new TerraDrawMapboxGLAdapter({ map, lib }), modes: [ new TerraDrawRenderMode({ modeName: "contextual", styles: { pointColor: "#00FFFF", pointOutlineColor: "#00FF00", }, }), ], }); draw.addFeatures([point]); ``` -------------------------------- ### Enable Drawing Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Set the active drawing mode on the Terra Draw instance after initialization. This allows users to start drawing with the specified mode. ```javascript // Once we have started Terra Draw draw.start(); // Enable the TerraDrawPolygonMode draw.setMode("polygon"); // Switch to the TerraDrawFreehandMode draw.setMode("freehand"); ``` -------------------------------- ### Initialize Terra Draw with Undo/Redo and Handle History Events Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Configure Terra Draw with undo/redo capabilities and listen for the 'history' event to update UI elements like undo/redo buttons based on stack sizes. This setup enables custom control over undo/redo actions. ```typescript import { TerraDraw, TerraDrawPolygonMode, TerraDrawModeUndoRedo, TerraDrawSessionUndoRedo, TerraDrawUndoRedoKeyboardShortcuts, } from "terra-draw"; const draw = new TerraDraw({ adapter, modes: [new TerraDrawPolygonMode()], undoRedo: { modeLevel: new TerraDrawModeUndoRedo({ maxStackSize: 100 }), // Optional sessionLevel: new TerraDrawSessionUndoRedo({ maxStackSize: 100 }), // Optional keyboardShortcuts: new TerraDrawUndoRedoKeyboardShortcuts(), // Optional }, }); draw.start(); draw.on("history", ({ cause, stack, undoSize, redoSize }) => { // cause: "push" | "undo" | "redo" // stack: "mode" | "session" // undoSize / redoSize: current stack sizes undoButton.disabled = undoSize === 0; redoButton.disabled = redoSize === 0; }); ``` -------------------------------- ### GeoJSON Feature with Mode Property Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md An example of a GeoJSON Feature created by drawing a polygon, showing the 'mode' property set to 'polygon'. ```json { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "mode": "polygon" }, "geometry": { "type": "Polygon", "coordinates": [ [ [-1.82645, 51.17888], [-1.826208, 51.179025], [-1.825859, 51.178867], [-1.82609, 51.178682], [-1.82645, 51.17888] ] ] } } ] } ``` -------------------------------- ### Custom Polygon Validation Example Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Implement custom validation for polygons to prevent self-intersection. This validation runs when the drawing is finished or committed. ```typescript polygonMode = new TerraDrawPolygonMode({ validation: (feature, { updateType }) => { if (updateType === "finish" || updateType === "commit") { return ValidateNotSelfIntersecting(feature); } return { valid: true } } }); ``` -------------------------------- ### Get Features at Pointer Event Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Retrieve features under the pointer, with options to control search radius, polygon inclusion, and ignored feature types. Defaults are `ignoreSelectFeatures: false` and `pointerDistance: 30`. ```typescript document.addEventListener("mousemove", (event) => { const featuresAtMouseEvent = draw.getFeaturesAtPointerEvent(event, { // The number pixels to search around input point pointerDistance: 40, // By default polygons are only considered at the location if they are directly selected // this option allows them to be returned if they are within the pointer distance includePolygonsWithinPointerDistance: true, // Ignore features that have been selected ignoreSelectFeatures: true, // ignore coordinates ignoreCoordinatePoints: true, // Ignore the current feature if one is being drawn ignoreCurrentlyDrawing: true, // Ignore closing points ignoreClosingPoints: true, // Ignore snapping points ignoreSnappingPoints: true, // Adds to feature's properties information about the closest coordinate to pointer event addClosestCoordinateInfoToProperties: true }); // Do something with the features... console.log({ featuresAtMouseEvent }); }); ``` -------------------------------- ### Retrieve a Single Feature by ID Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Get a copy of a specific feature from the store using its ID with the `getSnapshotFeature` method. This is useful when you need to work with an individual feature's data. ```javascript // Get a copy of a specific feature from the Store const features = draw.getSnapshotFeature('f8e5a38d-ecfa-4294-8461-d9cff0e0d7f8'); ``` -------------------------------- ### Get Features at Longitude/Latitude Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Retrieve features at a specific longitude and latitude. Options include search radius and ignoring selected features. Defaults are `ignoreSelectFeatures: false` and `pointerDistance: 30`. ```typescript map.on("mousemove", (event) => { const { lng, lat } = event.lngLat; const featuresAtLngLat = draw.getFeaturesAtLngLat( { lng, lat }, { // The number pixels to search around input point pointerDistance: 40, // Ignore features that have been selected ignoreSelectFeatures: true, }, ); console.log({ featuresAtLngLat }); }); ``` -------------------------------- ### Instantiate MapLibre Adapter Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/3.ADAPTERS.md Demonstrates how to import MapLibre, create a map instance, and then instantiate the TerraDrawMapLibreGLAdapter with the map instance. ```javascript import maplibregl from "maplibre-gl"; import { TerraDraw, TerraDrawRectangleMode } from "terra-draw"; import { TerraDrawMapLibreGLAdapter } from "terra-draw-maplibre-gl-adapter"; // Create Map Instance const map = new maplibregl.Map({ container: id, style: 'https://demotiles.maplibre.org/style.json', center: [lng, lat], zoom: zoom, }); // Create Adapter const adapter = new TerraDrawMapLibreGLAdapter({ // Pass in the map instance map, }); ``` -------------------------------- ### Run Headed E2E Tests Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/e2e/README.md Execute E2E tests with a browser window opening, allowing visual inspection of the test execution. ```shell npm run test:headed ``` -------------------------------- ### Instantiate Render Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Create a new Render Mode instance. A unique `modeName` is required to identify this mode, allowing for custom styling and management. ```javascript const renderMode = new TerraDrawRenderMode({ // Unique mode name used to identify the Mode (required) modeName: "custom-name", }); ``` -------------------------------- ### Instantiating Terra Draw with Custom Mode Names Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Demonstrates how to add different modes, including custom-named instances of the same mode class, during Terra Draw instantiation. ```javascript const draw = new TerraDraw({ adapter: new TerraDrawLeafletAdapter({ lib, map }), modes: [ // Polygon Mode has the built-in name "polygon" new TerraDrawPolygonMode(), // Polygon Mode has the custom name "custom-polygon" new TerraDrawPolygonMode({ modeName: "custom-polygon", }), // Render Modes are given custom names new TerraDrawRenderMode({ modeName: "custom-name", }), ], }); draw.start(); ``` -------------------------------- ### Styling Polygons with Random Colors Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Demonstrates how to style polygons with dynamically generated random colors using a styling function and a cache for feature IDs. This approach allows for unique styling of each polygon. ```typescript function getRandomColor() { const letters = "0123456789ABCDEF"; let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } const colorCache: Record = {}; const draw = new TerraDraw({ adapter: new TerraDrawMapboxGLAdapter({ map, coordinatePrecision: 9, }), modes: [ new TerraDrawPolygonMode({ styles: { fillColor: ({ id }) => { colorCache[id] = colorCache[id] || getRandomColor(); return colorCache[id]; }, }, }), ], }); draw.on("delete", (ids) => ids.forEach((id) => delete cache[id])); ``` -------------------------------- ### Configure Circle with Both Interactions Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Instantiate a Circle mode to enable both click-move-click and click-and-drag interactions. This provides maximum flexibility for users. ```typescript new TerraDrawCircleMode({ drawInteraction: "click-move-or-drag" }) ``` -------------------------------- ### Check Drawing State Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Retrieve the current state of the active drawing mode. This can be used to determine if the user is currently drawing or has started a drawing operation. ```typescript // Once we have started Terra Draw draw.start(); // Enable the TerraDrawPolygonMode draw.setMode("polygon"); // Determine if the user is currently drawing or not - either 'started' or 'drawing' const state = draw.getModeState(); ``` -------------------------------- ### Styling Lines Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Customize the appearance of selected lines using color, opacity, and width properties. ```markdown | Property | Type | Example Value | Description | | --------------------------- | ------------ | ------------- | ----------------------- | | `selectedLineStringColor` | Hex Color | `#00FFFF` | The color of the line | | `selectedLineStringOpacity` | Number (0-1) | `0.7` | The opacity of the line | | `selectedLineStringWidth` | Integer | `3` | The width of the line | ``` -------------------------------- ### Styling Points Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Customize the appearance of selected points using color, opacity, and width properties for both fill and outline. ```markdown | Property | Type | Example Value | Description | | ----------------------------- | ------------ | ------------- | -------------------------------- | | `selectedPointColor` | Hex Color | `#00FFFF` | The fill color of the point | | `selectedPointOpacity` | Number (0-1) | `0.7` | The fill opacity of the point | | `selectedPointWidth` | Integer | `2` | The width of the point | | `selectedPointOutlineColor` | Hex Color | `#00FFFF` | The outline color of the point | | `selectedPointOutlineOpacity` | Number (0-1) | `0.7` | The outline opacity of the point | | `selectedPointOutlineWidth` | Integer | `2` | The outline width of the point | ``` -------------------------------- ### Run Terra Draw Tests with Coverage Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/7.DEVELOPMENT.md Run tests and generate a code coverage report. The script fails if coverage drops below 80%. ```shell npm run test:coverage ``` -------------------------------- ### Listen for Styling Changes Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Shows how to listen for the 'styling' change event, which is emitted when styles are updated using `updateModeOptions`. ```typescript draw.on('change', (ids, type) => { if (type === 'styling') { console.log('styling has changed'); } }) ``` -------------------------------- ### Dynamically Set Feature Mode Before Adding Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Explains how to dynamically assign a drawing mode to features before adding them to the store. This ensures features are associated with the correct mode, especially when multiple modes of the same type exist. ```javascript // Iterate over the points points.forEach((point) => { // Set the `mode` property to "point" point.properties.mode = "point"; }); draw.addFeatures(points); ``` -------------------------------- ### Run Headless E2E Tests Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/e2e/README.md Execute E2E tests without opening a browser window. This is useful for CI/CD pipelines. ```shell npm run test ``` -------------------------------- ### Select and LineString Mode Snapping Configuration Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Configure snapping behavior for Select and LineString modes, allowing snapping to coordinates and line segments of existing features. ```typescript new TerraDrawSelectMode({ projection: "web-mercator", flags: { polygon: { feature: { coordinates: { snappable: { toLine: true, toCoordinate: true }, } } }, linestring: { feature: { coordinates: { snappable: { toLine: true, toCoordinate: true }, } } } } }) ``` -------------------------------- ### Update Polygon Mode Styles Dynamically Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Demonstrates how to initialize a mode with styles and then update them dynamically using `updateModeOptions`. This method allows for partial updates to the styles object. ```typescript const draw = new TerraDraw({ adapter: new TerraDrawMapboxGLAdapter({ map, lib }), modes: [ new TerraDrawPolygonMode({ // Pass styles to the constructor styles: { fillColor: "#00FFFF", fillOpacity: 0.7, outlineColor: "#00FF00", outlineWidth: 2, }, }), ], }); // Later on... draw.updateModeOptions('polygon', { // We can pass in a partial styles object and it will just update the fields passed styles: { fillColor: "#b3250a", fillOpacity: 0.85 } }) ``` -------------------------------- ### Styling Polygons Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Customize the appearance of selected polygons, including fill and outline colors, opacities, and widths. ```markdown | Property | Type | Example Value | Description | | ----------------------------- | ------------ | ------------- | ---------------------------------- | | `selectedPolygonColor` | Hex Color | `#00FFFF` | The fill color of the polygon | | `selectedPolygonFillOpacity` | Number (0-1) | `0.7` | The fill opacity of the polygon | | `selectedPolygonOutlineColor` | Hex Color | `#00FFFF` | The outline color of the polygon | | `selectedPolygonOutlineOpacity` | Number (0-1) | `0.7` | The outline opacity of the polygon | | `selectedPolygonOutlineWidth` | Integer | `2` | The outline width of the polygon | ``` -------------------------------- ### Environment Variables for Terra Draw Storybook Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/storybook/README.md Configure API keys and access tokens for different mapping libraries using a .env file. This is necessary for Storybook to function correctly with Google Maps and Mapbox. ```shell GOOGLE_API_KEY=your-google-key-here MAPBOX_ACCESS_TOKEN=your-mapbox-key-here ``` -------------------------------- ### Configure Rectangle with Click-and-Drag Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Instantiate a Rectangle mode to only allow the click-and-drag interaction. This is useful for touch-friendly interfaces. ```typescript new TerraDrawRectangleMode({ drawInteraction: "click-drag" }) ``` -------------------------------- ### Store and Restore Terra Draw Data with localStorage Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Persist drawing data by taking a snapshot with `getSnapshot`, filtering out internal points, and stringifying it for `localStorage`. Restore data by parsing the string and using `addFeatures`. ```javascript const features = draw.getSnapshot() // We don't want any mid points or selection points so we filter them out const filteredFeatures = features.filter((f) => !f.properties.midPoint && !f.properties.selectionPoint) // localStorage can only store strings, so we stringify the features first localStorage.setItem('terra-draw-data', JSON.stringify(filteredFeatures)); // Later on, perhaps after the user has refreshed. const retrievedFeatures = localStorage.getItem('terra-draw-data'); if (retrievedFeatures) { draw.addFeatures(JSON.parse(retrievedFeatures)) } ``` -------------------------------- ### Switching Between Terra Draw Modes Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Shows how to switch the active mode of a Terra Draw instance using the `setMode` method. ```javascript draw.setMode('polygon') // Later on... draw.setMode('point') ``` -------------------------------- ### Dynamically Update Mode Options Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Update mode options after instantiation using the `updateModeOptions` method. This allows for on-the-fly changes to mode behavior, such as modifying snapping settings. ```typescript draw.updateModeOptions('polygon', { snapping: { toLine: false, toCoordinate: true } }) ``` -------------------------------- ### Configure Rectangle with Default Click-Move-Click Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Explicitly set the Rectangle mode to use the default click-move-click interaction. This is the standard GIS/CAD-style drawing workflow. ```typescript new TerraDrawRectangleMode({ drawInteraction: "click-move" }) ``` -------------------------------- ### Enable Coordinate Points in LineString Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Activate the rendering of coordinate points for each vertex in the LineString mode. These points are managed internally by the mode and store. ```typescript import { TerraDraw, TerraDrawLineStringMode } from "terra-draw"; const draw = new TerraDraw({ adapter, modes: [ new TerraDrawLineStringMode({ showCoordinatePoints: true, }), ], }); draw.start(); draw.setMode("linestring"); ``` -------------------------------- ### Styling Selection Points Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Customize the appearance of selection points used for moving existing geometry points, including fill and outline styles. ```markdown | Property | Type | Example Value | Description | | ------------------------------ | ------------ | ------------- | ------------------------------------------ | | `selectionPointColor` | Hex Color | `#00FFFF` | The fill color of the selection point | | `selectionPointOpacity` | Number (0-1) | `0.7` | The fill opacity of the selection point | | `selectionPointOutlineColor` | Hex Color | `#00FF00` | The outline color of the selection point | | `selectionPointOutlineOpacity` | Number (0-1) | `0.7` | The outline opacity of the selection point | | `selectionPointWidth` | Integer | `2` | The width of the selection point | | `selectionPointOutlineWidth` | Integer | `3` | The width of the selection point | ``` -------------------------------- ### Polygon Mode Snapping Configuration Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Configure snapping to existing feature coordinates and line segments for the Polygon mode. Includes a validation function to prevent self-intersection on finish or commit. ```typescript new TerraDrawPolygonMode({ snapping: { toLine: true, toCoordinate: true, }, validation: (feature, { updateType }) => { if (updateType === "finish" || updateType === "commit") { return ValidateNotSelfIntersecting(feature); } return { valid: true }; }, }) ``` -------------------------------- ### Run Smoke Tests on Terra Draw Storybook Source: https://github.com/jameslmilner/terra-draw/blob/main/packages/storybook/README.md Execute a series of automated smoke tests against the Storybook stories. This helps ensure that all stories load and function as expected. ```shell npm run storybook:test ``` -------------------------------- ### Run Terra Draw Tests without Type Checking and with Coverage Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/7.DEVELOPMENT.md Combines skipping type checking with generating a code coverage report for efficient local testing. ```shell npm run test:nocheck:coverage ``` -------------------------------- ### Enable Coordinate Points in Polygon Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Activate the rendering of coordinate points for each vertex in the Polygon mode. These points are managed internally by the mode and store. ```typescript import { TerraDraw, TerraDrawPolygonMode } from "terra-draw"; const draw = new TerraDraw({ adapter, modes: [ new TerraDrawPolygonMode({ showCoordinatePoints: true, }), ], }); draw.start(); draw.setMode("polygon"); ``` -------------------------------- ### Generate and Add Feature with Custom ID Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Illustrates generating a feature ID using `getFeatureId` before adding a feature to the store. This is useful when you need to manage feature IDs externally. ```javascript const id = draw.getFeatureId() // Add a Point to the Store draw.addFeatures([ { id, type: "Feature", geometry: { type: "Point", coordinates: [-1.825859, 51.178867], }, properties: { mode: "point", }, }, ]); ``` -------------------------------- ### Style Selected Polygon in Selection Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Illustrates how to pass styles to the `TerraDrawSelectMode` constructor to customize the appearance of selected polygons. Different geometry types can have distinct selection styles. ```javascript const draw = new TerraDraw({ adapter: new TerraDrawMapboxGLAdapter({ map, lib }), modes: [ new TerraDrawPolygonMode(), new TerraDrawSelectMode({ styles: { // Fill colour selectedPolygonColor: "#00FFFF", // Fill opacity selectedPolygonFillOpacity: 0.7, // Outline colour selectedPolygonOutlineColor: "#00FF00", //Outline width selectedPolygonOutlineWidth: 2, }, flags: { polygon: { feature: { draggable: true, }, }, }, }), ], }); draw.start(); ``` -------------------------------- ### Polygon Mode Custom Snapping Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Implement custom snapping logic in the Polygon mode by providing a `toCustom` function. This allows snapping to arbitrary positions, such as external data or other features. ```typescript new TerraDrawPolygonMode({ snapping: { toCustom: () => { // You can return whatever position you want here, determined in any way you see fit! return [0, 0] } } }) ``` -------------------------------- ### Styling Mid Points Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/5.STYLING.md Customize the appearance of midpoints used for adding new points to geometries, including fill and outline styles. ```markdown | Property | Type | Example Value | Description | | ------------------------ | ------------ | ------------- | ------------------------------------ | | `midPointColor` | Hex Color | `#00FFFF` | The fill color of the mid point | | `midPointOpacity` | Number (0-1) | `0.7` | The fill opacity of the mid point | | `midPointOutlineColor` | Hex Color | `#00FFFF` | The outline color of the mid point | | `midPointOutlineOpacity` | Number (0-1) | `0.7` | The outline opacity of the mid point | | `midPointWidth` | Integer | `2` | The width of the mid point | | `midPointOutlineWidth` | Integer | `3` | The width of the mid point | ``` -------------------------------- ### LineString Mode with Globe Projection for Geodesic Lines Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Draw geodesic lines on a web mercator map by setting the `projection` to 'globe' and using `insertCoordinates` with a specified strategy and value. ```typescript new TerraDrawLineStringMode({ projection: 'globe', insertCoordinates: { strategy: 'amount', value: 10 } }), ``` -------------------------------- ### Configure Pointer Distance for Interaction Accuracy Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Adjust the 'pointerDistance' option to define the buffer zone around coordinates for selection or closing events. This helps differentiate intended interactions from general map clicks. ```typescript new TerraDrawPolygonMode({ pointerDistance: 25 }), ``` -------------------------------- ### Toggle Coordinate Points in Polygon Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Demonstrates how to enable and disable coordinate points for the polygon mode after instantiation using `updateModeOptions`. This function also affects existing features within the specified mode. ```typescript draw.updateModeOptions("polygon", { showCoordinatePoints: true, }); draw.updateModeOptions("polygon", { showCoordinatePoints: false, }); ``` -------------------------------- ### Configure Selection Mode Flags Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md This snippet shows the various flags available when instantiating TerraDrawSelectMode, controlling manual selection/deselection and editing capabilities for different feature types. ```javascript new TerraDrawSelectMode({ // Allow manual deselection of features allowManualDeselection: true, // this defaults to true - allows users to deselect by clicking on the map // Allow manual selection of features by clicking on the map allowManualSelection: true, // this defaults to true - set to false to require selection via draw.selectFeature(id) // Enable editing tools by Feature flags: { // Point point: { feature: { draggable: true, }, }, // Polygon polygon: { feature: { draggable: true, coordinates: { midpoints: true, draggable: true, deletable: true, }, }, }, // Line linestring: { feature: { draggable: true, coordinates: { midpoints: true, draggable: true, deletable: true, }, }, }, // Freehand freehand: { feature: { draggable: true, coordinates: { midpoints: true, draggable: true, deletable: true, }, }, }, // Circle circle: { feature: { draggable: true, coordinates: { midpoints: true, draggable: true, deletable: true, }, }, }, // Rectangle rectangle: { feature: { draggable: true, coordinates: { midpoints: true, draggable: true, deletable: true, }, }, }, }, // Styles go here... styles: { // See Styling Guide for more information }, }); ``` -------------------------------- ### Configure Polygon Feature Editing in Selection Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md This snippet demonstrates how to enable editing for polygon features within the Selection Mode, including making the entire feature draggable and configuring coordinate manipulation. ```javascript const selectMode = new TerraDrawSelectMode({ flags: { polygon: { feature: { // The entire Feature can be moved draggable: true, // Individual coordinates that make up the Feature... coordinates: { // Midpoint be added midpoints: { // Midpoint be dragged draggable: true }, // Can be moved draggable: true, // Can snap to other coordinates from geometries _of the same mode_ snappable: true, // Allow resizing of the geometry from a given origin. // center will allow resizing of the aspect ratio from the center // and opposite allows resizing from the opposite corner of the // bounding box of the geometry. resizable: 'center', // can also be 'opposite', 'center-fixed', 'opposite-fixed' // Can be deleted deletable: true, // Provide a custom validation that will run when we attempt to edit the geometry validation: (feature, context) => { // context has the methods project and unproject and be used to go from screen space // to geographic space and vice versa // ValidateMinAreaSquareMeters can be imported from Terra Draw return ValidateMinAreaSquareMeters(feature.geometry, 1000); } }, }, }, }, }); ``` -------------------------------- ### Handle Invalid Features After Adding Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Shows how to filter and process features that failed validation after being added to the store. This allows for specific error handling, such as sending analytics for features with holes. ```typescript // Create a list of features that did not pass validation const invalidFeatures = result.filter(({ valid }) => !valid); // Do something with the information invalidFeatures.forEach(({ reason }) => { // ValidationReasonFeatureHasHoles is exposed in the Terra Draw library under ValidationReasons if (reason === ValidationReasonFeatureHasHoles) { // sentAnalytics is a fake function that illustrates reacting to a invalid feature sentAnalytics({ type: 'error', info: 'Feature that is being added to Terra Draw has holes when it should not' }) } }); ``` -------------------------------- ### Handle Terra Draw Change Events Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Listen for changes to features, including creation, update, deletion, and styling. The 'context' object provides details about the event's origin and target. ```typescript draw.on("change", (ids, type, context) => { //Done editing if (type === 'change') { if (context?.origin === 'api') { console.log('this was changed via the API!') } else if (context?.origin === undefined) { console.log('this change did not originate from the API!') } } }); ``` ```typescript draw.on("change", (ids, type, context) => { if (type === 'change') { if (context?.target === 'properties') { console.log('properties were changed') } else if (context?.target === 'geometry') { console.log('geometry was changed') } } }); ``` ```typescript draw.on("change", (ids, type) => { //Done editing if (type === "delete") { // Get the Store snapshot const snapshot = draw.getSnapshot(); // Do something //... } }); ``` ```typescript draw.on("change", (ids: string[], type: string) => { // Possible type values: // 'create' // 'update' // 'delete' // 'styling' // Do something //... }); ``` -------------------------------- ### Programmatically Add, Select, and Deselect Features Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Manage features programmatically using Terra Draw instance methods. This includes adding features, selecting them by ID, and deselecting them. ```typescript const draw = new TerraDraw({ adapter, modes: [ new TerraDrawPointMode(), new TerraDrawSelectMode({ flags: { point: { feature: { draggable: true } }, }, }), ], }); draw.start(); // Add feature programmatically const result = draw.addFeatures([ { id: "f8e5a38d-ecfa-4294-8461-d9cff0e0d7f8", type: "Feature", geometry: { type: "Point", coordinates: [-25.431289673, 34.355907891], }, properties: { mode: "point", }, }, ]); // Log out if the feature passed validation or not if (!result[0].valid) { throw new Error(result.reason ? result.reason : 'Feature f8e5a38d-ecfa-4294-8461-d9cff0e0d7f8 was invalid') } // Select a given feature draw.selectFeature("f8e5a38d-ecfa-4294-8461-d9cff0e0d7f8"); // Deselect the given feature draw.deselectFeature("f8e5a38d-ecfa-4294-8461-d9cff0e0d7f8"); ``` -------------------------------- ### Handle Terra Draw Finish Event Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Respond to the completion of drawing or editing actions. The context object specifies the action type (e.g., 'draw', 'dragFeature') and the mode. ```typescript draw.on("finish", (id: string, context: { action: string, mode: string }) => { if (context.action === 'draw') { // Do something for draw finish event } else if (context.action === 'dragFeature') { // Do something for a drag finish event } else if (context.action === 'dragCoordinate') { // }else if (context.action === 'dragCoordinateResize') { // } }); ``` -------------------------------- ### Add Modes to Terra Draw Instance Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Add custom drawing modes, such as Polygon and Freehand, to the Terra Draw instance during initialization. Built-in modes have predefined names. ```javascript const draw = new TerraDraw({ adapter: new TerraDrawLeafletAdapter({ lib, map }), modes: [ // Polygon Mode has the built-in name "polygon" new TerraDrawPolygonMode(), // Freehand Mode has the built-in name "freehand" new TerraDrawFreehandMode(), ], }); draw.start(); ``` -------------------------------- ### Run Terra Draw Tests without Type Checking Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/7.DEVELOPMENT.md Execute tests while skipping TypeScript type checking for faster local development. This option only checks explicitly tested files. ```shell npm run test:nocheck ``` -------------------------------- ### Configure Marker Icons in TerraDrawMarkerMode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Set custom marker icons, width, and height for the Marker mode. Ensure your GeoJSON features have a 'marker: true' property in their properties to render as icons. ```typescript new TerraDrawMarkerMode({ styles: { markerUrl: "https://leafletjs.com/examples/custom-icons/leaf-green.png", markerWidth: 25, markerHeight: 60, }, }) ``` -------------------------------- ### Access Map Event with Selected Feature Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Access the specific mouse/map event alongside the selected geometry by registering a click event on the map. This allows for actions like positioning popups based on user interaction. ```typescript // Register an on click event onto the map itself map.on('click', (event) => { const snapshot = draw.getSnapshot() // Search the snapshot for the selected polygon const polygon = snapshot.find((feature) => feature.properties.selected === true && feature.geometry.type === 'Polygon') // If there is not a selected polygon, don't do anything if (!polygon) { return } // Else create or update the popup location to be the cursor position! if (popup) { popup.setLngLat([event.lngLat.lng, event.lngLat.lat]) } else { popup = new maplibregl.Popup({ closeOnClick: false }) .setLngLat([event.lngLat.lng, event.lngLat.lat]) .setHTML('

Example Popup

') .addTo(map); } }) ``` -------------------------------- ### Handle Terra Draw Select Event Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/6.EVENTS.md Trigger a callback when a feature is selected. This event provides the ID of the selected feature. ```typescript draw.on("select", (id: string) => { // Do something //... }); ``` -------------------------------- ### Terra Draw Base Mode Anatomy Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/7.DEVELOPMENT.md Defines the core methods and event handlers for creating custom modes in Terra Draw. Extend `TerraDrawBaseMode` to implement drawing or editing features. ```typescript /** @internal */ start() { this.setStarted(); } /** @internal */ stop() { this.setStopped(); } /** @internal */ onClick(event: TerraDrawMouseEvent) {} /** @internal */ onMouseMove(event: TerraDrawMouseEvent) {} /** @internal */ onKeyDown(event: TerraDrawKeyboardEvent) {} /** @internal */ onKeyUp(event: TerraDrawKeyboardEvent) {} /** @internal */ onDragStart(event: TerraDrawMouseEvent) {} /** @internal */ onDrag(event: TerraDrawMouseEvent) {} /** @internal */ onDragEnd(event: TerraDrawMouseEvent) {} /** @internal */ styleFeature(feature: GeoJSONStoreFeatures): TerraDrawAdapterStyling {} ``` -------------------------------- ### Enable Editable Features in Polygon Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/4.MODES.md Configure Terra Draw modes to support editable geometries. This allows users to make light edits, such as dragging coordinates, without switching to a separate select mode. ```typescript new TerraDrawPolygonMode({ editable: true }), ``` -------------------------------- ### Filter Features by Mode Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Filter the features obtained from `getSnapshot` to retrieve specific types, such as only polygon features. This allows for targeted data manipulation or display. ```javascript features.filter((feature) => feature.properties.mode === 'polygon') ``` -------------------------------- ### Custom Integer ID Strategy for Terra Draw Source: https://github.com/jameslmilner/terra-draw/blob/main/guides/2.STORE.md Define a custom ID strategy to generate incrementing integer IDs for features. Ensure your strategy includes a `isValidId` function to validate IDs and a `getId` function to generate them. ```typescript const draw = new TerraDraw({ adapter, modes, idStrategy: { isValidId: (id) => typeof id === "number" && Number.isInteger(id), getId: (function () { let id = 0; return function () { return ++id; }; })() // Returns a function that returns incrementing integer ids }, }); ```