terra-draw-mapbox-gl-adapter
Version:
Terra Draw Adapter for Mapbox GL JS
1 lines • 30.8 kB
Source Map (JSON)
{"version":3,"file":"terra-draw-mapbox-gl-adapter.cjs","sources":["../src/terra-draw-mapbox-gl-adapter.ts"],"sourcesContent":["/**\n * @module terra-draw-mapbox-gl-adapter\n */\nimport {\n\tTerraDrawChanges,\n\tSetCursor,\n\tTerraDrawStylingFunction,\n\tTerraDrawExtend,\n\tGeoJSONStoreGeometries,\n} from \"terra-draw\";\n\nimport { Feature, LineString, Point, Polygon } from \"geojson\";\nimport {\n\tCircleLayerSpecification,\n\tFillLayerSpecification,\n\tLineLayerSpecification,\n\tGeoJSONSource,\n\tPointLike,\n} from \"mapbox-gl\";\n\nexport class TerraDrawMapboxGLAdapter extends TerraDrawExtend.TerraDrawBaseAdapter {\n\tconstructor(\n\t\tconfig: {\n\t\t\tmap: mapboxgl.Map;\n\t\t\trenderBelowLayerId?: string;\n\t\t\tprefixId?: string;\n\t\t} & TerraDrawExtend.BaseAdapterConfig,\n\t) {\n\t\tsuper(config);\n\t\tthis._map = config.map;\n\t\tthis._container = this._map.getContainer();\n\n\t\t// We want to respect the initial map settings\n\t\tthis._initialDragRotate = this._map.dragRotate.isEnabled();\n\t\tthis._initialDragPan = this._map.dragPan.isEnabled();\n\t\tthis._renderBeforeLayerId = config.renderBelowLayerId;\n\t\tthis._prefixId = config.prefixId || \"td\";\n\t}\n\n\tprivate _renderBeforeLayerId: string | undefined;\n\tprivate _prefixId: string;\n\tprivate _initialDragPan: boolean;\n\tprivate _initialDragRotate: boolean;\n\tprivate _nextRender: number | undefined;\n\tprivate _map: mapboxgl.Map;\n\tprivate _container: HTMLElement;\n\n\tprivate toGlDashArrayFromPixels(\n\t\tdash: [number, number] | undefined,\n\t\tlineWidth: number,\n\t): [number, number] | null {\n\t\tif (!dash) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst [onPx, offPx] = dash;\n\t\tif (\n\t\t\t!Number.isFinite(onPx) ||\n\t\t\t!Number.isFinite(offPx) ||\n\t\t\tonPx < 0 ||\n\t\t\toffPx < 0\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst width = Math.max(0.0001, lineWidth);\n\t\treturn [onPx / width, offPx / width];\n\t}\n\n\t// Marker state\n\tprivate markerCounter = 0;\n\tprivate markerMap = new Map<string, string>();\n\n\t// MapLibre/Mapbox GL do not support sizing icons on both the X and Y axis independently\n\t// To maintain compatibility we resize the image to the desired dimensions and then\n\t// pass that to MapLibre/Mapbox GL as a base64 string\n\tprivate resizeImage(\n\t\timageUrl: string,\n\t\twidth: number,\n\t\theight: number,\n\t\tcallback: (resizedDataURL: string) => void,\n\t) {\n\t\tconst img = new Image();\n\t\timg.crossOrigin = \"anonymous\"; // if loading from remote source\n\t\timg.onload = () => {\n\t\t\tconst canvas = document.createElement(\"canvas\");\n\t\t\tcanvas.width = width;\n\t\t\tcanvas.height = height;\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) {\n\t\t\t\tthrow new Error(\"Could not get canvas context\");\n\t\t\t}\n\t\t\tctx.drawImage(img, 0, 0, width, height);\n\t\t\tconst resizedDataURL = canvas.toDataURL(); // base64 string\n\t\t\tcallback(resizedDataURL);\n\t\t};\n\t\timg.src = imageUrl;\n\t}\n\n\tprivate _addGeoJSONSource(id: string, features: Feature[]) {\n\t\tthis._map.addSource(id, {\n\t\t\ttype: \"geojson\",\n\t\t\tdata: {\n\t\t\t\ttype: \"FeatureCollection\",\n\t\t\t\tfeatures: features,\n\t\t\t},\n\t\t\ttolerance: 0,\n\t\t});\n\t}\n\n\tprivate _addFillLayer(id: string) {\n\t\treturn this._map.addLayer({\n\t\t\tid,\n\t\t\tsource: id,\n\t\t\ttype: \"fill\",\n\t\t\tlayout: {\n\t\t\t\t\"fill-sort-key\": [\"get\", \"zIndex\"],\n\t\t\t},\n\t\t\t// No need for filters as style is driven by properties\n\t\t\tpaint: {\n\t\t\t\t\"fill-color\": [\"get\", \"polygonFillColor\"],\n\t\t\t\t\"fill-opacity\": [\"get\", \"polygonFillOpacity\"],\n\t\t\t},\n\t\t} as FillLayerSpecification);\n\t}\n\n\tprivate _addFillOutlineLayer(id: string) {\n\t\tconst layer = this._map.addLayer({\n\t\t\tid: id + \"-outline\",\n\t\t\tsource: id,\n\t\t\ttype: \"line\",\n\t\t\tlayout: {\n\t\t\t\t\"line-sort-key\": [\"get\", \"zIndex\"],\n\t\t\t},\n\t\t\t// No need for filters as style is driven by properties\n\t\t\tpaint: {\n\t\t\t\t\"line-width\": [\"get\", \"polygonOutlineWidth\"],\n\t\t\t\t\"line-color\": [\"get\", \"polygonOutlineColor\"],\n\t\t\t\t\"line-opacity\": [\"get\", \"polygonOutlineOpacity\"],\n\t\t\t},\n\t\t} as LineLayerSpecification);\n\n\t\treturn layer;\n\t}\n\n\tprivate _addLineLayer(id: string) {\n\t\tconst paint: { \"line-dasharray\"?: any[] } = {};\n\n\t\tpaint[\"line-dasharray\"] = [\n\t\t\t\"coalesce\",\n\t\t\t[\"get\", \"lineStringDash\"],\n\t\t\t[\"literal\", []],\n\t\t];\n\n\t\tconst layer = this._map.addLayer({\n\t\t\tid,\n\t\t\tsource: id,\n\t\t\ttype: \"line\",\n\t\t\tlayout: {\n\t\t\t\t\"line-sort-key\": [\"get\", \"zIndex\"],\n\t\t\t},\n\t\t\t// No need for filters as style is driven by properties\n\t\t\tpaint: {\n\t\t\t\t...paint,\n\t\t\t\t\"line-width\": [\"get\", \"lineStringWidth\"],\n\t\t\t\t\"line-color\": [\"get\", \"lineStringColor\"],\n\t\t\t\t\"line-opacity\": [\"get\", \"lineStringOpacity\"],\n\t\t\t},\n\t\t} as LineLayerSpecification);\n\n\t\treturn layer;\n\t}\n\n\tprivate _addPointLayer(id: string) {\n\t\tconst layer = this._map.addLayer({\n\t\t\tid,\n\t\t\tsource: id,\n\t\t\ttype: \"circle\",\n\t\t\tlayout: {\n\t\t\t\t\"circle-sort-key\": [\"get\", \"zIndex\"],\n\t\t\t},\n\t\t\t// No need for filters as style is driven by properties\n\t\t\tpaint: {\n\t\t\t\t\"circle-stroke-color\": [\"get\", \"pointOutlineColor\"],\n\t\t\t\t\"circle-stroke-width\": [\"get\", \"pointOutlineWidth\"],\n\t\t\t\t\"circle-stroke-opacity\": [\"get\", \"pointOutlineOpacity\"],\n\t\t\t\t\"circle-radius\": [\"get\", \"pointWidth\"],\n\t\t\t\t\"circle-color\": [\"get\", \"pointColor\"],\n\t\t\t\t\"circle-opacity\": [\"get\", \"pointOpacity\"],\n\t\t\t},\n\t\t} as CircleLayerSpecification);\n\n\t\treturn layer;\n\t}\n\n\tprivate _addMarkerLayer(id: string) {\n\t\tconst layer = this._map.addLayer({\n\t\t\tid: id + \"-marker\",\n\t\t\tsource: id,\n\t\t\ttype: \"symbol\",\n\t\t\tfilter: [\"has\", \"markerId\"],\n\t\t\tlayout: {\n\t\t\t\t\"icon-image\": [\"get\", \"markerId\"],\n\t\t\t\t\"icon-anchor\": \"bottom\", // bottom center of icon will be aligned to point\n\t\t\t\t\"icon-allow-overlap\": true,\n\t\t\t},\n\t\t});\n\n\t\treturn layer;\n\t}\n\n\tprivate _addLayer(\n\t\tid: string,\n\t\tfeatureType: \"Point\" | \"LineString\" | \"Polygon\",\n\t) {\n\t\tif (featureType === \"Point\") {\n\t\t\tthis._addPointLayer(id);\n\t\t\tthis._addMarkerLayer(id);\n\t\t}\n\t\tif (featureType === \"LineString\") {\n\t\t\tthis._addLineLayer(id);\n\t\t}\n\t\tif (featureType === \"Polygon\") {\n\t\t\tthis._addFillLayer(id);\n\t\t\tthis._addFillOutlineLayer(id);\n\t\t}\n\t}\n\n\tprivate _addGeoJSONLayer<T extends GeoJSONStoreGeometries>(\n\t\tfeatureType: Feature<T>[\"geometry\"][\"type\"],\n\t\tfeatures: Feature<T>[],\n\t) {\n\t\tconst id = `${this._prefixId}-${featureType.toLowerCase()}`;\n\t\tthis._addGeoJSONSource(id, features);\n\t\tthis._addLayer(id, featureType);\n\n\t\treturn id;\n\t}\n\n\tprivate _setGeoJSONLayerData<T extends GeoJSONStoreGeometries>(\n\t\tfeatureType: Feature<T>[\"geometry\"][\"type\"],\n\t\tfeatures: Feature<T>[],\n\t) {\n\t\tconst id = `${this._prefixId}-${featureType.toLowerCase()}`;\n\t\t(this._map.getSource(id) as GeoJSONSource).setData({\n\t\t\ttype: \"FeatureCollection\",\n\t\t\tfeatures: features,\n\t\t});\n\t\treturn id;\n\t}\n\n\tprivate changedIds: {\n\t\tdeletion: boolean;\n\t\tpoints: boolean;\n\t\tlinestrings: boolean;\n\t\tpolygons: boolean;\n\t\tstyling: boolean;\n\t} = {\n\t\tdeletion: false,\n\t\tpoints: false,\n\t\tlinestrings: false,\n\t\tpolygons: false,\n\t\tstyling: false,\n\t};\n\n\tprivate updateChangedIds(changes: TerraDrawChanges) {\n\t\t[...changes.updated, ...changes.created].forEach((feature) => {\n\t\t\tif (feature.geometry.type === \"Point\") {\n\t\t\t\tthis.changedIds.points = true;\n\t\t\t} else if (feature.geometry.type === \"LineString\") {\n\t\t\t\tthis.changedIds.linestrings = true;\n\t\t\t} else if (feature.geometry.type === \"Polygon\") {\n\t\t\t\tthis.changedIds.polygons = true;\n\t\t\t}\n\t\t});\n\n\t\tif (changes.deletedIds.length > 0) {\n\t\t\tthis.changedIds.deletion = true;\n\t\t}\n\n\t\tif (\n\t\t\tchanges.created.length === 0 &&\n\t\t\tchanges.updated.length === 0 &&\n\t\t\tchanges.deletedIds.length === 0\n\t\t) {\n\t\t\tthis.changedIds.styling = true;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the longitude and latitude coordinates from a given PointerEvent on the map.\n\t * @param event The PointerEvent or MouseEvent containing the screen coordinates of the pointer.\n\t * @returns An object with 'lng' and 'lat' properties representing the longitude and latitude, or null if the conversion is not possible.\n\t */\n\tpublic getLngLatFromEvent(event: PointerEvent | MouseEvent) {\n\t\tconst { left, top } = this._container.getBoundingClientRect();\n\t\tconst x = event.clientX - left;\n\t\tconst y = event.clientY - top;\n\n\t\treturn this.unproject(x, y);\n\t}\n\n\t/**\n\t *Retrieves the HTML element of the Mapbox element that handles interaction events\n\t * @returns The HTMLElement representing the map container.\n\t */\n\tpublic getMapEventElement() {\n\t\treturn this._map.getCanvas();\n\t}\n\n\t/**\n\t * Enables or disables the draggable functionality of the map.\n\t * @param enabled Set to true to enable map dragging, or false to disable it.\n\t */\n\tpublic setDraggability(enabled: boolean) {\n\t\tif (enabled) {\n\t\t\t// Mapbox GL has both drag rotation and drag panning interactions\n\t\t\t// hence having to enable/disable both\n\t\t\tif (this._initialDragRotate) {\n\t\t\t\tthis._map.dragRotate.enable();\n\t\t\t}\n\t\t\tif (this._initialDragPan) {\n\t\t\t\tthis._map.dragPan.enable();\n\t\t\t}\n\t\t} else {\n\t\t\tif (this._initialDragRotate) {\n\t\t\t\tthis._map.dragRotate.disable();\n\t\t\t}\n\t\t\tif (this._initialDragPan) {\n\t\t\t\tthis._map.dragPan.disable();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Converts longitude and latitude coordinates to pixel coordinates in the map container.\n\t * @param lng The longitude coordinate to project.\n\t * @param lat The latitude coordinate to project.\n\t * @returns An object with 'x' and 'y' properties representing the pixel coordinates within the map container.\n\t */\n\tpublic project(lng: number, lat: number) {\n\t\tconst { x, y } = this._map.project({ lng, lat });\n\t\treturn { x, y };\n\t}\n\n\t/**\n\t * Converts pixel coordinates in the map container to longitude and latitude coordinates.\n\t * @param x The x-coordinate in the map container to unproject.\n\t * @param y The y-coordinate in the map container to unproject.\n\t * @returns An object with 'lng' and 'lat' properties representing the longitude and latitude coordinates.\n\t */\n\tpublic unproject(x: number, y: number) {\n\t\tconst { lng, lat } = this._map.unproject({ x, y } as PointLike);\n\t\treturn { lng, lat };\n\t}\n\n\t/**\n\t * Sets the cursor style for the map container.\n\t * @param cursor The CSS cursor style to apply, or 'unset' to remove any previously applied cursor style.\n\t */\n\tpublic setCursor(cursor: Parameters<SetCursor>[0]) {\n\t\tconst canvas = this._map.getCanvas();\n\t\tif (cursor === \"unset\") {\n\t\t\tcanvas.style.removeProperty(\"cursor\");\n\t\t} else {\n\t\t\tcanvas.style.cursor = cursor;\n\t\t}\n\t}\n\n\t/**\n\t * Enables or disables the double-click to zoom functionality on the map.\n\t * @param enabled Set to true to enable double-click to zoom, or false to disable it.\n\t */\n\tpublic setDoubleClickToZoom(enabled: boolean) {\n\t\tif (enabled) {\n\t\t\tthis._map.doubleClickZoom.enable();\n\t\t} else {\n\t\t\tthis._map.doubleClickZoom.disable();\n\t\t}\n\t}\n\n\t/**\n\t * Renders GeoJSON features on the map using the provided styling configuration.\n\t * @param changes An object containing arrays of created, updated, and unchanged features to render.\n\t * @param styling An object mapping draw modes to feature styling functions\n\t */\n\tpublic render(changes: TerraDrawChanges, styling: TerraDrawStylingFunction) {\n\t\tthis.updateChangedIds(changes);\n\n\t\tif (this._nextRender) {\n\t\t\tcancelAnimationFrame(this._nextRender);\n\t\t}\n\n\t\t// Because Mapbox GL makes us pass in a full re-render of all the features\n\t\t// we can do debounce rendering to only render the last render in a given\n\t\t// frame bucket (16ms)\n\t\tthis._nextRender = requestAnimationFrame(() => {\n\t\t\t// Get a map of the changed feature IDs by geometry type\n\t\t\t// We use this to determine which MB layers need to be updated\n\n\t\t\tconst features = [\n\t\t\t\t...changes.created,\n\t\t\t\t...changes.updated,\n\t\t\t\t...changes.unchanged,\n\t\t\t];\n\n\t\t\tconst points = [];\n\t\t\tconst linestrings = [];\n\t\t\tconst polygons = [];\n\n\t\t\tfor (let i = 0; i < features.length; i++) {\n\t\t\t\tconst feature = features[i];\n\t\t\t\tconst { properties } = feature;\n\t\t\t\tconst mode = properties.mode as string;\n\t\t\t\tconst styles = styling[mode](feature);\n\n\t\t\t\t// Set the zIndex property for the feature regardless of geometry type\n\t\t\t\t// NOTE: Render ordering is predominately controlled by the layer order.\n\t\t\t\t// In this instance we are only controlling the zIndex order in relation to the layer itself. Since we have a\n\t\t\t\t// layer for each geometry type, the zIndex is only used to control the order of features within that layer.\n\t\t\t\t// Long term we need to consider how to handle zIndex ordering across multiple geometry types.\n\t\t\t\tproperties.zIndex = styles.zIndex;\n\n\t\t\t\tif (feature.geometry.type === \"Point\") {\n\t\t\t\t\tconst pointOpacity = (styles as { pointOpacity?: number })\n\t\t\t\t\t\t.pointOpacity;\n\t\t\t\t\tconst pointOutlineOpacity = (\n\t\t\t\t\t\tstyles as { pointOutlineOpacity?: number }\n\t\t\t\t\t).pointOutlineOpacity;\n\n\t\t\t\t\tproperties.pointColor = styles.pointColor;\n\t\t\t\t\tproperties.pointOutlineColor = styles.pointOutlineColor;\n\t\t\t\t\tproperties.pointOutlineWidth = styles.pointOutlineWidth;\n\t\t\t\t\tproperties.pointOutlineOpacity =\n\t\t\t\t\t\tpointOutlineOpacity === undefined ? 1 : pointOutlineOpacity;\n\t\t\t\t\tproperties.pointWidth = styles.pointWidth;\n\t\t\t\t\tproperties.pointOpacity =\n\t\t\t\t\t\tpointOpacity === undefined ? 1 : pointOpacity;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tstyles.markerUrl &&\n\t\t\t\t\t\tstyles.markerWidth &&\n\t\t\t\t\t\tstyles.markerHeight &&\n\t\t\t\t\t\t!this.markerMap.has(styles.markerUrl)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst id = `marker-${this.markerCounter++}`;\n\n\t\t\t\t\t\tthis.resizeImage(\n\t\t\t\t\t\t\tstyles.markerUrl,\n\t\t\t\t\t\t\tstyles.markerWidth,\n\t\t\t\t\t\t\tstyles.markerHeight,\n\t\t\t\t\t\t\t(resizedDataURL) => {\n\t\t\t\t\t\t\t\tthis._map.loadImage(resizedDataURL, (error, image) => {\n\t\t\t\t\t\t\t\t\tif (!image || error) {\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t\t\t`Error loading marker image: ${styles.markerUrl}`,\n\t\t\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tthis._map.addImage(id, image);\n\n\t\t\t\t\t\t\t\t\t// We have to set these all explicitly as loadImage is async\n\t\t\t\t\t\t\t\t\t// and the render will have already happened at this point\n\n\t\t\t\t\t\t\t\t\tthis._map.setLayoutProperty(\n\t\t\t\t\t\t\t\t\t\t`${this._prefixId}-point-marker`,\n\t\t\t\t\t\t\t\t\t\t\"icon-image\",\n\t\t\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tthis.markerMap.set(styles.markerUrl as string, id);\n\t\t\t\t\t\tproperties.markerId = id;\n\t\t\t\t\t\tproperties.pointWidth = 0; // Make circle invisible\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tstyles.markerUrl &&\n\t\t\t\t\t\tthis.markerMap.has(styles.markerUrl as string)\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Image already loaded\n\t\t\t\t\t\tproperties.markerId = this.markerMap.get(\n\t\t\t\t\t\t\tstyles.markerUrl,\n\t\t\t\t\t\t) as string;\n\n\t\t\t\t\t\tproperties.pointWidth = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tpoints.push(feature);\n\t\t\t\t} else if (feature.geometry.type === \"LineString\") {\n\t\t\t\t\tproperties.lineStringDash = this.toGlDashArrayFromPixels(\n\t\t\t\t\t\t// Backwards compatible read: pre Terra Draw v1.24.0 will not have this field in the interface\n\t\t\t\t\t\t(styles as { lineStringDash?: [number, number] }).lineStringDash,\n\t\t\t\t\t\tstyles.lineStringWidth,\n\t\t\t\t\t);\n\n\t\t\t\t\tproperties.lineStringColor = styles.lineStringColor;\n\t\t\t\t\tproperties.lineStringWidth = styles.lineStringWidth;\n\t\t\t\t\t// Backwards compatible read: pre Terra Draw v1.24.0 will not have this field in the interface\n\t\t\t\t\tconst lineStringOpacity = (styles as { lineStringOpacity?: number })\n\t\t\t\t\t\t.lineStringOpacity;\n\t\t\t\t\tproperties.lineStringOpacity =\n\t\t\t\t\t\tlineStringOpacity === undefined ? 1 : lineStringOpacity;\n\t\t\t\t\tlinestrings.push(feature);\n\t\t\t\t} else if (feature.geometry.type === \"Polygon\") {\n\t\t\t\t\tconst polygonOutlineOpacity = (\n\t\t\t\t\t\tstyles as { polygonOutlineOpacity?: number }\n\t\t\t\t\t).polygonOutlineOpacity;\n\n\t\t\t\t\tproperties.polygonFillColor = styles.polygonFillColor;\n\t\t\t\t\tproperties.polygonFillOpacity = styles.polygonFillOpacity;\n\t\t\t\t\tproperties.polygonOutlineOpacity =\n\t\t\t\t\t\tpolygonOutlineOpacity === undefined ? 1 : polygonOutlineOpacity;\n\t\t\t\t\tproperties.polygonOutlineColor = styles.polygonOutlineColor;\n\t\t\t\t\tproperties.polygonOutlineWidth = styles.polygonOutlineWidth;\n\t\t\t\t\tpolygons.push(feature);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If deletion occurred we always have to update all layers\n\t\t\t// as we don't know the type (TODO: perhaps we could pass that back?)\n\t\t\tconst deletionOccurred = this.changedIds.deletion;\n\t\t\tconst styleUpdatedOccurred = this.changedIds.styling;\n\t\t\tconst forceUpdate = deletionOccurred || styleUpdatedOccurred;\n\n\t\t\t// Determine if we need to update each layer by geometry type\n\t\t\tconst updatePoints = forceUpdate || this.changedIds.points;\n\t\t\tconst updateLineStrings = forceUpdate || this.changedIds.linestrings;\n\t\t\tconst updatedPolygon = forceUpdate || this.changedIds.polygons;\n\n\t\t\tif (updatePoints) {\n\t\t\t\tthis._setGeoJSONLayerData<Point>(\"Point\", points as Feature<Point>[]);\n\t\t\t}\n\n\t\t\tif (updateLineStrings) {\n\t\t\t\tthis._setGeoJSONLayerData<LineString>(\n\t\t\t\t\t\"LineString\",\n\t\t\t\t\tlinestrings as Feature<LineString>[],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (updatedPolygon) {\n\t\t\t\tthis._setGeoJSONLayerData<Polygon>(\n\t\t\t\t\t\"Polygon\",\n\t\t\t\t\tpolygons as Feature<Polygon>[],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Reset changed ids\n\t\t\tthis.changedIds = {\n\t\t\t\tpoints: false,\n\t\t\t\tlinestrings: false,\n\t\t\t\tpolygons: false,\n\t\t\t\tdeletion: false,\n\t\t\t\tstyling: false,\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Clears the map and store of all rendered data layers\n\t * @returns void\n\t * */\n\tpublic clear() {\n\t\tif (this._currentModeCallbacks) {\n\t\t\t// Clear up state first\n\t\t\tthis._currentModeCallbacks.onClear();\n\n\t\t\t// TODO: This is necessary to prevent render artifacts, perhaps there is a nicer solution?\n\t\t\tif (this._nextRender) {\n\t\t\t\tcancelAnimationFrame(this._nextRender);\n\t\t\t\tthis._nextRender = undefined;\n\t\t\t}\n\n\t\t\tthis._setGeoJSONLayerData<Point>(\"Point\", []);\n\n\t\t\tthis._setGeoJSONLayerData<LineString>(\"LineString\", []);\n\n\t\t\tthis._setGeoJSONLayerData<Polygon>(\"Polygon\", []);\n\t\t}\n\t}\n\n\tpublic getCoordinatePrecision(): number {\n\t\treturn super.getCoordinatePrecision();\n\t}\n\n\tpublic unregister(): void {\n\t\tsuper.unregister();\n\n\t\tthis._map.removeLayer(`${this._prefixId}-point`);\n\t\tthis._map.removeLayer(`${this._prefixId}-point-marker`);\n\t\tthis._map.removeSource(`${this._prefixId}-point`);\n\t\tthis._map.removeLayer(`${this._prefixId}-linestring`);\n\t\tthis._map.removeSource(`${this._prefixId}-linestring`);\n\t\tthis._map.removeLayer(`${this._prefixId}-polygon`);\n\t\tthis._map.removeLayer(`${this._prefixId}-polygon-outline`);\n\t\tthis._map.removeSource(`${this._prefixId}-polygon`);\n\t}\n\n\tpublic register(callbacks: TerraDrawExtend.TerraDrawCallbacks) {\n\t\tsuper.register(callbacks);\n\n\t\tconst polygonStringId = this._addGeoJSONLayer<Polygon>(\n\t\t\t\"Polygon\",\n\t\t\t[] as Feature<Polygon>[],\n\t\t);\n\n\t\tconst lineStringId = this._addGeoJSONLayer<LineString>(\n\t\t\t\"LineString\",\n\t\t\t[] as Feature<LineString>[],\n\t\t);\n\n\t\tconst pointId = this._addGeoJSONLayer<Point>(\n\t\t\t\"Point\",\n\t\t\t[] as Feature<Point>[],\n\t\t);\n\n\t\tif (this._renderBeforeLayerId) {\n\t\t\tthis._map.moveLayer(pointId, this._renderBeforeLayerId);\n\t\t\tthis._map.moveLayer(lineStringId, pointId);\n\t\t\tthis._map.moveLayer(polygonStringId + \"-outline\", lineStringId);\n\t\t\tthis._map.moveLayer(polygonStringId, lineStringId);\n\t\t}\n\n\t\tif (this._currentModeCallbacks?.onReady) {\n\t\t\tthis._currentModeCallbacks.onReady();\n\t\t}\n\t}\n}\n"],"names":["_TerraDrawExtend$Terr","TerraDrawMapboxGLAdapter","config","_this","call","this","_renderBeforeLayerId","_prefixId","_initialDragPan","_initialDragRotate","_nextRender","_map","_container","markerCounter","markerMap","Map","changedIds","deletion","points","linestrings","polygons","styling","map","getContainer","dragRotate","isEnabled","dragPan","renderBelowLayerId","prefixId","_proto","prototype","toGlDashArrayFromPixels","dash","lineWidth","onPx","offPx","Number","isFinite","width","Math","max","resizeImage","imageUrl","height","callback","img","Image","crossOrigin","onload","canvas","document","createElement","ctx","getContext","Error","drawImage","resizedDataURL","toDataURL","src","_addGeoJSONSource","id","features","addSource","type","data","tolerance","_addFillLayer","addLayer","source","layout","paint","_addFillOutlineLayer","_addLineLayer","_extends","_addPointLayer","_addMarkerLayer","filter","_addLayer","featureType","_addGeoJSONLayer","toLowerCase","_setGeoJSONLayerData","getSource","setData","updateChangedIds","changes","_this2","concat","updated","created","forEach","feature","geometry","deletedIds","length","getLngLatFromEvent","event","_this$_container$getB","getBoundingClientRect","unproject","clientX","left","clientY","top","getMapEventElement","getCanvas","setDraggability","enabled","enable","disable","project","lng","lat","_this$_map$project","x","y","_this$_map$unproject","setCursor","cursor","style","removeProperty","setDoubleClickToZoom","doubleClickZoom","render","_this3","cancelAnimationFrame","requestAnimationFrame","unchanged","_loop","i","properties","styles","mode","zIndex","pointOpacity","pointOutlineOpacity","pointColor","pointOutlineColor","pointOutlineWidth","undefined","pointWidth","markerUrl","markerWidth","markerHeight","has","loadImage","error","image","addImage","setLayoutProperty","console","set","markerId","get","push","lineStringDash","lineStringWidth","lineStringColor","lineStringOpacity","polygonOutlineOpacity","polygonFillColor","polygonFillOpacity","polygonOutlineColor","polygonOutlineWidth","forceUpdate","updateLineStrings","updatedPolygon","clear","_currentModeCallbacks","onClear","getCoordinatePrecision","unregister","removeLayer","removeSource","register","callbacks","_this$_currentModeCal","polygonStringId","lineStringId","pointId","moveLayer","onReady","TerraDrawExtend","TerraDrawBaseAdapter"],"mappings":"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"}