diff --git a/src/adapters/common/base.adapter.ts b/src/adapters/common/base.adapter.ts index 9412c4a9..ed024ca3 100644 --- a/src/adapters/common/base.adapter.ts +++ b/src/adapters/common/base.adapter.ts @@ -124,6 +124,15 @@ export abstract class TerraDrawBaseAdapter { }); } + /** + * Gets the coordinate precision. + * @returns {number} The coordinate precision. + * @description The coordinate precision is the number of decimal places. Note that the precision will be overriden by the precision of the TerraDraw Adapter. + */ + public getCoordinatePrecision() { + return this._coordinatePrecision; + } + private getAdapterListeners() { return [ new AdapterListener({ diff --git a/src/common.ts b/src/common.ts index 48c0d9e3..15b5d3a5 100644 --- a/src/common.ts +++ b/src/common.ts @@ -83,6 +83,7 @@ export interface TerraDrawModeRegisterConfig { onFinish: (finishedId: string) => void; project: Project; unproject: Unproject; + coordinatePrecision: number; } export type TerraDrawModeState = @@ -136,6 +137,7 @@ export interface TerraDrawAdapter { unregister(): void; render(changes: TerraDrawChanges, styling: TerraDrawStylingFunction): void; clear(): void; + getCoordinatePrecision(): number; } export const SELECT_PROPERTIES = { diff --git a/src/modes/base.mode.ts b/src/modes/base.mode.ts index b45e9480..0ec50479 100644 --- a/src/modes/base.mode.ts +++ b/src/modes/base.mode.ts @@ -16,7 +16,7 @@ import { } from "../store/store"; import { isValidStoreFeature } from "../store/store-feature-validation"; -type CustomStyling = Record< +export type CustomStyling = Record< string, | string | number @@ -30,6 +30,12 @@ export enum ModeTypes { Static = "static", Render = "render", } + +export type BaseModeOptions = { + styles?: Partial; + pointerDistance?: number; +}; + export abstract class TerraDrawBaseDrawMode { protected _state: TerraDrawModeState; get state() { @@ -54,7 +60,7 @@ export abstract class TerraDrawBaseDrawMode { protected behaviors: TerraDrawModeBehavior[] = []; protected pointerDistance: number; - protected coordinatePrecision: number; + protected coordinatePrecision!: number; protected onStyleChange!: StoreChangeHandler; protected store!: GeoJSONStore; protected setDoubleClickToZoom!: TerraDrawModeRegisterConfig["setDoubleClickToZoom"]; @@ -63,18 +69,12 @@ export abstract class TerraDrawBaseDrawMode { protected setCursor!: TerraDrawModeRegisterConfig["setCursor"]; protected registerBehaviors(behaviorConfig: BehaviorConfig): void {} - constructor(options?: { - styles?: Partial; - pointerDistance?: number; - coordinatePrecision?: number; - }) { + constructor(options?: BaseModeOptions) { this._state = "unregistered"; this._styles = options && options.styles ? { ...options.styles } : ({} as Partial); - this.pointerDistance = (options && options.pointerDistance) || 40; - - this.coordinatePrecision = (options && options.coordinatePrecision) || 9; + this.coordinatePrecision = 9; } type = ModeTypes.Drawing; @@ -131,7 +131,7 @@ export abstract class TerraDrawBaseDrawMode { project: this.project, unproject: this.unproject, pointerDistance: this.pointerDistance, - coordinatePrecision: this.coordinatePrecision, + coordinatePrecision: config.coordinatePrecision, }); } else { throw new Error("Can not register unless mode is unregistered"); diff --git a/src/modes/circle/circle.mode.ts b/src/modes/circle/circle.mode.ts index aa32f28d..b3d366a2 100644 --- a/src/modes/circle/circle.mode.ts +++ b/src/modes/circle/circle.mode.ts @@ -11,7 +11,11 @@ import { haversineDistanceKilometers } from "../../geometry/measure/haversine-di import { circle } from "../../geometry/shape/create-circle"; import { GeoJSONStoreFeatures } from "../../store/store"; import { getDefaultStyling } from "../../util/styling"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { isValidNonIntersectingPolygonFeature } from "../../geometry/boolean/is-valid-polygon-feature"; type TerraDrawCircleModeKeyEvents = { @@ -30,6 +34,12 @@ interface Cursors { start?: Cursor; } +interface TerraDrawCircleModeOptions + extends BaseModeOptions { + keyEvents?: TerraDrawCircleModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawCircleMode extends TerraDrawBaseDrawMode { mode = "circle"; private center: Position | undefined; @@ -38,11 +48,7 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode; - constructor(options?: { - styles?: Partial; - keyEvents?: TerraDrawCircleModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawCircleModeOptions) { super(options); const defaultCursors = { diff --git a/src/modes/freehand/freehand.mode.ts b/src/modes/freehand/freehand.mode.ts index ad9b6693..5c7169a1 100644 --- a/src/modes/freehand/freehand.mode.ts +++ b/src/modes/freehand/freehand.mode.ts @@ -8,7 +8,11 @@ import { } from "../../common"; import { Polygon } from "geojson"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { getDefaultStyling } from "../../util/styling"; import { GeoJSONStoreFeatures } from "../../store/store"; import { pixelDistance } from "../../geometry/measure/pixel-distance"; @@ -35,6 +39,14 @@ interface Cursors { close?: Cursor; } +interface TerraDrawFreehandModeOptions + extends BaseModeOptions { + minDistance?: number; + preventPointsNearClose?: boolean; + keyEvents?: TerraDrawFreehandModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawFreehandMode extends TerraDrawBaseDrawMode { mode = "freehand"; @@ -46,13 +58,7 @@ export class TerraDrawFreehandMode extends TerraDrawBaseDrawMode; private preventPointsNearClose: boolean; - constructor(options?: { - styles?: Partial; - minDistance?: number; - preventPointsNearClose?: boolean; - keyEvents?: TerraDrawFreehandModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawFreehandModeOptions) { super(options); const defaultCursors = { diff --git a/src/modes/greatcircle/great-circle.mode.ts b/src/modes/greatcircle/great-circle.mode.ts index 372c7efe..5215d0d5 100644 --- a/src/modes/greatcircle/great-circle.mode.ts +++ b/src/modes/greatcircle/great-circle.mode.ts @@ -7,7 +7,11 @@ import { Cursor, } from "../../common"; import { LineString } from "geojson"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { BehaviorConfig } from "../base.behavior"; import { getDefaultStyling } from "../../util/styling"; import { GeoJSONStoreFeatures } from "../../store/store"; @@ -35,6 +39,14 @@ interface Cursors { close?: Cursor; } +interface TerraDrawGreatCircleModeOptions + extends BaseModeOptions { + snapping?: boolean; + pointerDistance?: number; + keyEvents?: TerraDrawGreateCircleModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawGreatCircleMode extends TerraDrawBaseDrawMode { mode = "greatcircle"; @@ -48,13 +60,7 @@ export class TerraDrawGreatCircleMode extends TerraDrawBaseDrawMode; - keyEvents?: TerraDrawGreateCircleModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawGreatCircleModeOptions) { super(options); const defaultCursors = { diff --git a/src/modes/linestring/linestring.mode.ts b/src/modes/linestring/linestring.mode.ts index 1900cc3b..409d450a 100644 --- a/src/modes/linestring/linestring.mode.ts +++ b/src/modes/linestring/linestring.mode.ts @@ -8,7 +8,11 @@ import { } from "../../common"; import { LineString } from "geojson"; import { selfIntersects } from "../../geometry/boolean/self-intersects"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { pixelDistance } from "../../geometry/measure/pixel-distance"; import { BehaviorConfig } from "../base.behavior"; import { ClickBoundingBoxBehavior } from "../click-bounding-box.behavior"; @@ -36,6 +40,15 @@ interface Cursors { close?: Cursor; } +interface TerraDrawLineStringModeOptions + extends BaseModeOptions { + snapping?: boolean; + allowSelfIntersections?: boolean; + pointerDistance?: number; + keyEvents?: TerraDrawLineStringModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawLineStringMode extends TerraDrawBaseDrawMode { mode = "linestring"; @@ -51,14 +64,7 @@ export class TerraDrawLineStringMode extends TerraDrawBaseDrawMode; - keyEvents?: TerraDrawLineStringModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawLineStringModeOptions) { super(options); const defaultCursors = { diff --git a/src/modes/point/point.mode.ts b/src/modes/point/point.mode.ts index b72439e0..91e0cd67 100644 --- a/src/modes/point/point.mode.ts +++ b/src/modes/point/point.mode.ts @@ -7,7 +7,11 @@ import { } from "../../common"; import { GeoJSONStoreFeatures } from "../../store/store"; import { getDefaultStyling } from "../../util/styling"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { isValidPoint } from "../../geometry/boolean/is-valid-point"; type PointModeStyling = { @@ -21,15 +25,17 @@ interface Cursors { create?: Cursor; } +interface TerraDrawPointModeOptions + extends BaseModeOptions { + cursors?: Cursors; +} + export class TerraDrawPointMode extends TerraDrawBaseDrawMode { mode = "point"; private cursors: Required; - constructor(options?: { - styles?: Partial; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawPointModeOptions) { super(options); const defaultCursors = { create: "crosshair", diff --git a/src/modes/polygon/polygon.mode.ts b/src/modes/polygon/polygon.mode.ts index 1197a9a1..fb33d156 100644 --- a/src/modes/polygon/polygon.mode.ts +++ b/src/modes/polygon/polygon.mode.ts @@ -8,7 +8,11 @@ import { } from "../../common"; import { Polygon } from "geojson"; import { selfIntersects } from "../../geometry/boolean/self-intersects"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + TerraDrawBaseDrawMode, + BaseModeOptions, + CustomStyling, +} from "../base.mode"; import { PixelDistanceBehavior } from "../pixel-distance.behavior"; import { ClickBoundingBoxBehavior } from "../click-bounding-box.behavior"; import { BehaviorConfig } from "../base.behavior"; @@ -41,6 +45,15 @@ interface Cursors { close?: Cursor; } +interface TerraDrawPolygonModeOptions + extends BaseModeOptions { + allowSelfIntersections?: boolean; + snapping?: boolean; + pointerDistance?: number; + keyEvents?: TerraDrawPolygonModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawPolygonMode extends TerraDrawBaseDrawMode { mode = "polygon"; @@ -57,14 +70,7 @@ export class TerraDrawPolygonMode extends TerraDrawBaseDrawMode private cursors: Required; private mouseMove = false; - constructor(options?: { - allowSelfIntersections?: boolean; - snapping?: boolean; - pointerDistance?: number; - styles?: Partial; - keyEvents?: TerraDrawPolygonModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawPolygonModeOptions) { super(options); const defaultCursors = { diff --git a/src/modes/rectangle/rectangle.mode.ts b/src/modes/rectangle/rectangle.mode.ts index 9ac957da..0e35bb7a 100644 --- a/src/modes/rectangle/rectangle.mode.ts +++ b/src/modes/rectangle/rectangle.mode.ts @@ -9,7 +9,11 @@ import { } from "../../common"; import { GeoJSONStoreFeatures } from "../../store/store"; import { getDefaultStyling } from "../../util/styling"; -import { TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { isValidNonIntersectingPolygonFeature } from "../../geometry/boolean/is-valid-polygon-feature"; type TerraDrawRectangleModeKeyEvents = { @@ -28,6 +32,12 @@ interface Cursors { start?: Cursor; } +interface TerraDrawRectangleModeOptions + extends BaseModeOptions { + keyEvents?: TerraDrawRectangleModeKeyEvents | null; + cursors?: Cursors; +} + export class TerraDrawRectangleMode extends TerraDrawBaseDrawMode { mode = "rectangle"; private center: Position | undefined; @@ -36,11 +46,9 @@ export class TerraDrawRectangleMode extends TerraDrawBaseDrawMode; - constructor(options?: { - styles?: Partial; - keyEvents?: TerraDrawRectangleModeKeyEvents | null; - cursors?: Cursors; - }) { + constructor( + options?: TerraDrawRectangleModeOptions, + ) { super(options); const defaultCursors = { diff --git a/src/modes/render/render.mode.ts b/src/modes/render/render.mode.ts index 82f6d416..4038b15a 100644 --- a/src/modes/render/render.mode.ts +++ b/src/modes/render/render.mode.ts @@ -3,7 +3,12 @@ import { NumericStyling, TerraDrawAdapterStyling, } from "../../common"; -import { ModeTypes, TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + ModeTypes, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { BehaviorConfig } from "../base.behavior"; import { getDefaultStyling } from "../../util/styling"; import { GeoJSONStoreFeatures } from "../../terra-draw"; @@ -25,14 +30,18 @@ type RenderModeStyling = { zIndex: NumericStyling; }; +interface TerraDrawRenderModeOptions + extends BaseModeOptions { + modeName: string; + // styles need to be there else we could fall back to BaseModeOptions + styles: Partial; +} + export class TerraDrawRenderMode extends TerraDrawBaseDrawMode { public type = ModeTypes.Render; // The type of the mode public mode = "render"; // This gets changed dynamically - constructor(options: { - modeName: string; - styles: Partial; - }) { + constructor(options: TerraDrawRenderModeOptions) { super({ styles: options.styles }); this.mode = options.modeName; } diff --git a/src/modes/select/select.mode.ts b/src/modes/select/select.mode.ts index 5988b10f..145bff01 100644 --- a/src/modes/select/select.mode.ts +++ b/src/modes/select/select.mode.ts @@ -8,7 +8,12 @@ import { Cursor, } from "../../common"; import { Point, Position } from "geojson"; -import { ModeTypes, TerraDrawBaseDrawMode } from "../base.mode"; +import { + BaseModeOptions, + CustomStyling, + ModeTypes, + TerraDrawBaseDrawMode, +} from "../base.mode"; import { MidPointBehavior } from "./behaviors/midpoint.behavior"; import { SelectionPointBehavior } from "./behaviors/selection-point.behavior"; import { FeatureAtPointerEventBehavior } from "./behaviors/feature-at-pointer-event.behavior"; @@ -80,6 +85,15 @@ interface Cursors { insertMidpoint?: Cursor; } +interface TerraDrawSelectModeOptions + extends BaseModeOptions { + pointerDistance?: number; + flags?: { [mode: string]: ModeFlags }; + keyEvents?: TerraDrawSelectModeKeyEvents | null; + dragEventThrottle?: number; + cursors?: Cursors; +} + export class TerraDrawSelectMode extends TerraDrawBaseDrawMode { public type = ModeTypes.Select; public mode = "select"; @@ -103,14 +117,7 @@ export class TerraDrawSelectMode extends TerraDrawBaseDrawMode private scaleFeature!: ScaleFeatureBehavior; private cursors: Required; - constructor(options?: { - styles?: Partial; - pointerDistance?: number; - flags?: { [mode: string]: ModeFlags }; - keyEvents?: TerraDrawSelectModeKeyEvents | null; - dragEventThrottle?: number; - cursors?: Cursors; - }) { + constructor(options?: TerraDrawSelectModeOptions) { super(options); this.flags = options && options.flags ? options.flags : {}; diff --git a/src/terra-draw.ts b/src/terra-draw.ts index 0c6b8604..53fbecf1 100644 --- a/src/terra-draw.ts +++ b/src/terra-draw.ts @@ -78,25 +78,23 @@ class TerraDraw { modes: TerraDrawBaseDrawMode[]; }) { this._adapter = options.adapter; + this._mode = new TerraDrawStaticMode(); // Keep track of if there are duplicate modes const duplicateModeTracker = new Set(); // Construct a map of the mode name to the mode - const modesMap = options.modes.reduce( - (modeMap, currentMode) => { - if (duplicateModeTracker.has(currentMode.mode)) { - throw new Error( - `There is already a ${currentMode.mode} mode provided`, - ); - } - duplicateModeTracker.add(currentMode.mode); - modeMap[currentMode.mode] = currentMode; - return modeMap; - }, - {} as { [mode: string]: TerraDrawBaseDrawMode }, - ); + const modesMap = options.modes.reduce<{ + [mode: string]: TerraDrawBaseDrawMode; + }>((modeMap, currentMode) => { + if (duplicateModeTracker.has(currentMode.mode)) { + throw new Error(`There is already a ${currentMode.mode} mode provided`); + } + duplicateModeTracker.add(currentMode.mode); + modeMap[currentMode.mode] = currentMode; + return modeMap; + }, {}); // Construct an array of the mode keys (names) const modeKeys = Object.keys(modesMap); @@ -255,6 +253,7 @@ class TerraDraw { onSelect: onSelect, onDeselect: onDeselect, onFinish: onFinish, + coordinatePrecision: this._adapter.getCoordinatePrecision(), }); }); } diff --git a/src/test/mock-config.ts b/src/test/mock-config.ts index bcbb2b5d..6c8c9dee 100644 --- a/src/test/mock-config.ts +++ b/src/test/mock-config.ts @@ -12,5 +12,6 @@ export function getMockModeConfig(mode: string) { unproject: jest.fn(), setDoubleClickToZoom: jest.fn(), onFinish: jest.fn(), + coordinatePrecision: 9, }; }