PolyDraw is a free-hand drawing tool that allows you to draw shapes which are converted to polygons on your Leaflet-map. The tool supports concaving by default, subtracting (donut polygons) and are fully editable by adding edges, dragging edges. PolyDraw was initially heavily inspired by Leaflet.FreeDraw (Adam Timberlake "Wildhoney") and leaflet-freehandshapes (Benjamin DeLong "bozdoz"), so a big thank you and kudos for you!
Pre requirements
Polydraw require that TSyringe, a lightweight dependency injection container for JavaScript/TypeScript, is installed in your project, it might work without it if you use angular (Injectable).
TSyringe can be found at https://github.com/microsoft/tsyringe.
npm:
npm install --save tsyringe
yarn:
yarn add tsyringe
Include the following lines to you tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
You also need to add a polyfill for the Reflect API, use one of the following, we use 'reflect-metadata' in the example below.
How to
import "reflect-metadata";
import { container } from "tsyringe";
import * as L from "Leaflet";
import { MapStateService, PolyDrawService, ILatLng } from 'leaflet-polydraw';
export class LeafletPolyDrawExample {
polyDrawService: PolyDrawService;
constructor() {
this.mapState = container.resolve(MapStateService);
this.polyDrawService = container.resolve(PolyDrawService);
}
onInit() {
this.map = new L.Map("map");
this.map.setView(new L.LatLng(59.911491, 10.757933), 16);
}
onDrawClick(): void {
this.polyDrawService.drawModeClick();
}
onSubtractClick(): void {
this.polyDrawService.subtractClick();
}
onAutoAddPolygon(polygon: ILatLng[][][]): void {
this.polyDrawService.addAutoPolygon(polygon);
}
}
Road to configuration.
- Default configuration
{
"touchSupport": true,
"mergePolygons": true,
"kinks": false,
"modes": {
"attachElbow": false,
"dragElbow": true
},
"markers": {
"deleteMarker": true,
"infoMarker": true,
"menuMarker": true,
"coordsTitle": true,
"zIndexOffset": 0,
"markerIcon": {
"styleClasses": [
"polygon-marker"
],
"zIndexOffset": null
},
"holeIcon": {
"styleClasses": [
"polygon-marker",
"hole"
],
"zIndexOffset": null
},
"markerInfoIcon": {
"position": 3,
"showArea": true,
"showPerimeter": true,
"useMetrics": true,
"usePerimeterMinValue": false,
"areaLabel": "Area",
"perimeterLabel": "Perimeter",
"values": {
"min": {
"metric": "50",
"imperial": "100"
},
"unknown": {
"metric": "-",
"imperial": "-"
}
},
"units": {
"unknownUnit": "",
"metric": {
"onlyMetrics": true,
"perimeter": {
"m": "m",
"km": "km"
},
"area": {
"m2": "m²",
"km2": "km²",
"daa": "daa",
"ha": "ha"
}
},
"imperial": {
"perimeter": {
"feet": "ft",
"yards": "yd",
"miles": "mi"
},
"area": {
"feet2": "ft²",
"yards2": "yd²",
"acres": "ac",
"miles2": "mi²"
}
}
},
"styleClasses": [
"polygon-marker",
"info"
],
"zIndexOffset": null
},
"markerMenuIcon": {
"position": 7,
"styleClasses": [
"polygon-marker",
"menu"
],
"zIndexOffset": null
},
"markerDeleteIcon": {
"position": 5,
"styleClasses": [
"polygon-marker",
"delete"
],
"zIndexOffset": null
}
},
"polyLineOptions": {
"color": "#50622b",
"opacity": 1,
"smoothFactor": 0,
"noClip": true,
"clickable": false,
"weight": 2
},
"subtractLineOptions": {
"color": "#50622b",
"opacity": 1,
"smoothFactor": 0,
"noClip": true,
"clickable": false,
"weight": 2
},
"polygonOptions": {
"smoothFactor": 0.3,
"color": "#50622b",
"fillColor": "#b4cd8a",
"noClip": true
},
"simplification": {
"simplifyTolerance": {
"tolerance": 0.0001,
"highQuality": false,
"mutate": false
},
"dynamicMode": {
"fractionGuard": 0.9,
"multipiler": 2
}
},
"boundingBox": {
"addMidPointMarkers": true
},
"bezier": {
"resolution": 10000,
"sharpness": 0.85
}
}
- Inline configuration
const polyDraw = new PolyDraw({
...args...
});
- Point out your own json-file with configuration options
const polyDraw = new PolyDraw({
configPath: "path/to/your/location/polydraw.config.json"
});
Key | Type | Default | Description |
---|---|---|---|
touchSupport | boolean | true |
Allow touch support. |
mergePolygons | boolean | true |
PolyDraw attempts to merge polygons if they are intersecting. |
kinks | boolean | false |
text |
modes | object | Turn on or off features | |
attachElbow | boolean | false |
When enabled, attaching elbows is allowed |
dragElbow | boolean | true |
When enabled, dragging elbows is allowed |
markers | object | Main object for marker configuration. | |
deleteMarker | boolean | true |
When enabled, show delete marker icon. |
infoMarker | boolean | true |
When enabled, show info marker icon. |
menuMarker | boolean | true |
When enabled, show menu marker icon. |
coordsTitle | boolean | true |
When enabled, show tooltip with coord information on elbow markers. |
zIndexOffset | number | 0 |
By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like 1000 (or high negative value, respectively). |
markerIcon | object | Default elbow marker icon configuration. | |
styleClasses | Array | [polygon-marker] |
String array with name of style classes |
zIndexOffset | number | null |
Override of the zIndexOffset on markers |
holeIcon | object | Hole marker icon configuration. | |
styleClasses | array | [polygon-marker, hole] |
String array with name of style classes |
zIndexOffset | number | null |
Override of the zIndexOffset on markers |
markerInfoIcon | object | Info marker icon configuration. | |
position | int | Where to position the marker, see Marker position for more information. | |
showArea | boolean | When enabled, displays area information. | |
showPerimeter | boolean | When enabled, displays perimeter information section. | |
useMetrics | boolean | When enabled, displays metric units, otherwise imperial units. | |
usePerimeterMinValue | boolean | When enabled, a predefined value is shown in case of a unknown value. | |
areaLabel | string | Display text on area label | |
perimeterLabel | string | Display text on perimeter label | |
values | object | Predefined default values | |
min | object | Default values for min values if usePerimeterMinValue is enabled. | |
metric | string | 50 |
Default min value for metric values |
imperial | string | 100 |
Default min value for imperial values |
unknown | object | Default values for unkown values | |
metric | string | - |
Default unknown value for metric values |
imperial | string | - |
Default unknown value for imperial values |
units | object | Predefined default units | |
unknownUnit | string | empty string |
Value for unknown units |
metric | object | Metric properties | |
onlyMetrics | boolean | false | When enabled, daa and ha is removed from area, only m2 and km2 is used. |
perimeter | object | Perimeter properties | |
m | string | m |
Meter unit |
km | string | km |
Kilometer unit |
area | object | Area properties | |
m2 | string | m² |
Square meter unit |
km2 | string | km² |
Square kilometer unit |
daa | string | daa |
Decare unit |
ha | string | ha |
Hectare unit |
imperial | object | Imperial properties | |
perimeter | object | Perimeter properties | |
feet | string | ft |
Feet unit |
yards | string | yd |
Yard unit |
miles | string | mi |
Miles unit |
area | object | Area properties | |
feet2 | string | ft² |
Square feet unit |
yards2 | string | yd² |
Square yard unit |
acres | string | ac |
Acre unit |
miles2 | string | mi² |
Square mile unit |
styleClasses | array | [polygon-marker, info] |
String array with name of style classes |
zIndexOffset | number | null |
Override of the zIndexOffset on markers |
markerMenuIcon | object | Menu marker icon configuration. | |
position | int | 7 |
Where to put the marker, see Marker position for more information. |
styleClasses | array | [polygon-marker, info] |
String array with name of style classes |
zIndexOffset | number | null |
Override of the zIndexOffset on markers |
markerDeleteIcon | object | Delete marker icon configuration. | |
position | int | 5 |
Where to put the marker, see Marker position for more information. |
styleClasses | array | [polygon-marker, delete] |
String array with name of style classes |
zIndexOffset | number | null |
Override of the zIndexOffset on markers |
polyLineOptions | object | Polyline configuration. | |
color | string | #50622b |
Polyline color |
opacity | number | 1.0 |
Opacity on polyline. |
smoothFactor | number | 0.0 |
How much to simplify the polyline. Much: smoother look, Less: more accurate. |
noClip | boolean | true |
Disable polyline clipping. |
clickable | boolean | false |
text |
weight | number | 2 |
Polyline width in pixels |
subtractLineOptions | object | Subtract (holes) polyline configuration. | |
color | string | #50622b |
Polyline color |
opacity | number | 1.0 |
Opacity on polyline. |
smoothFactor | number | 0.0 |
How much to simplify the polyline. Much: smoother look, Less: more accurate. |
noClip | boolean | true |
Disable polyline clipping. |
clickable | boolean | false |
text |
weight | number | 2 |
Poly line width in pixels |
polygonOptions | object | Polygon configuration. | |
color | string | #50622b |
Polygon color |
fillColor | number | #b4cd8a |
Polygon fill color. |
smoothFactor | number | 0.3 |
How much to simplify the polyline. Much: smoother look, Less: more accurate. |
noClip | boolean | true |
Disable polyline clipping. |
simplification | object | Simplification configuration. | |
simplifyTolerance | object | Tolerance configuration | |
tolerance | number | 0.0001 |
Tolerance affects the amount of simplification (lesser value means higher quality but slower and with more points). |
highQuality | boolean | false |
Excludes distance-based preprocessing step which leads to highest quality simplification but runs ~10-20 times slower. |
mutate | boolean | false |
Allows GeoJSON input to be mutated (significant performance increase if true) |
dynamicMode | object | ||
fractionGuard | number | 0.9 |
When to stop the dynamic simplification. (ie. Avoid the polygon to have less than 3 points. |
multiplier | number | 2 |
A number for how much the tolerance should be increased by. (ie. tolerance * multipiler) |
boundingBox | object | ||
addMidPointMarkers | boolean | true |
When enabled, bounding boxes is decorated with West, North, East and South elbows. |
bezier | object | ||
resolution | number | 10000 |
Time in milliseconds between points. |
sharpness | number | 0.75 |
A measure of how curvy the path should be between splines. |
Delete marker (North West)
Used to delete the polygon. You can control this marker by:
this.polyDrawService.configurate({
"markers": {
"deleteMarker": true,
"markerDeleteIcon: {
...options...
}
}
});
Menu marker (North)
Used to show a popup with alter-options to the polygon.
- Simplify, decrease number of elbows
- BBox, convert polygon to it's bounding box You can control this marker by:
this.polyDrawService.configurate({
"markers": {
"menuMarker": true,
"markerDeleteIcon: {
...options...
}
}
});
Info marker (North East)
Used to show a popup with info about the polygon. You can control this marker by:
this.polyDrawService.configurate({
"markers": {
"infoMarker": true,
"markerInfoIcon: {
...options...
}
}
});
You can choose where you want to put the delete-marker and area information-marker. The area information-marker offsets around the delete marker. example:
const polyDraw = new PolyDraw({
markers: {
markerDeleteIcon: {
position: MarkerPlacement.North
},
markerInfoIcon: {
position: MarkerPlacement.East
},
markerMenuIcon: {
position: MarkerPlacement.West
}
}
});
This configuration gives this result.
MarkerPosition {
SouthWest = 0,
South = 1,
SouthEast = 2,
East = 3,
NorthEast = 4,
North = 5,
NorthWest = 6,
West = 7
}
- Prio 1, Not started - Marker cursor, when dragElbows is false
- Prio 2, Not started - Fallback positions for special markers (delete, info & menu)
- Prio 1, Beta phase - New menu item Increase elbows
- Prio 3, Not started - New menu item Bezier