Skip to content

Commit

Permalink
feat: for circle mode provide minimum radius config and store radius …
Browse files Browse the repository at this point in the history
…in circle properties (#223)
  • Loading branch information
JamesLMilner committed Mar 12, 2024
1 parent 5993130 commit ca301ef
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 46 deletions.
162 changes: 119 additions & 43 deletions src/modes/circle/circle.mode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ describe("TerraDrawCircleMode", () => {
keyEvents: { cancel: null, finish: null },
});
});

it("constructs minimumRadiusKilometers", () => {
new TerraDrawCircleMode({
minimumRadiusKilometers: 0.00001,
});
});
});

describe("lifecycle", () => {
Expand Down Expand Up @@ -131,60 +137,130 @@ describe("TerraDrawCircleMode", () => {
});

describe("registered", () => {
beforeEach(() => {
const mockConfig = getMockModeConfig(circleMode.mode);
describe("default minimumRadiusKilometers", () => {
beforeEach(() => {
const mockConfig = getMockModeConfig(circleMode.mode);

store = mockConfig.store;
onChange = mockConfig.onChange;
onFinish = mockConfig.onFinish;
store = mockConfig.store;
onChange = mockConfig.onChange;
onFinish = mockConfig.onFinish;

circleMode.register(mockConfig);
circleMode.start();
});
circleMode.register(mockConfig);
circleMode.start();
});

it("adds a circle to store if registered", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
it("adds a circle to store if registered", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

expect(onChange).toBeCalledTimes(1);
expect(onChange).toBeCalledWith([expect.any(String)], "create");
});

expect(onChange).toBeCalledTimes(1);
expect(onChange).toBeCalledWith([expect.any(String)], "create");
it("finishes drawing circle on second click", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

let features = store.copyAll();
expect(features.length).toBe(1);

circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

features = store.copyAll();
expect(features.length).toBe(1);

expect(onChange).toBeCalledTimes(3);
expect(onChange).toBeCalledWith([expect.any(String)], "create");

expect(onFinish).toBeCalledTimes(1);
});
});

it("finishes drawing circle on second click", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});
describe("set minimumRadiusKilometers", () => {
beforeEach(() => {
circleMode = new TerraDrawCircleMode({
minimumRadiusKilometers: 1000,
});
const mockConfig = getMockModeConfig(circleMode.mode);

let features = store.copyAll();
expect(features.length).toBe(1);
store = mockConfig.store;
onChange = mockConfig.onChange;
onFinish = mockConfig.onFinish;

circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
circleMode.register(mockConfig);
circleMode.start();
});

features = store.copyAll();
expect(features.length).toBe(1);

expect(onChange).toBeCalledTimes(2);
expect(onChange).toBeCalledWith([expect.any(String)], "create");
it("adds a circle to store if registered with the minimum radius", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

expect(onChange).toBeCalledTimes(1);
expect(onChange).toBeCalledWith([expect.any(String)], "create");
expect(store.copyAll()[0].properties.radiusKilometers).toStrictEqual(
1000,
);
});

expect(onFinish).toBeCalledTimes(1);
it("finishes drawing circle on second click using the minimum radius", () => {
circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

let features = store.copyAll();
expect(features.length).toBe(1);

circleMode.onClick({
lng: 0,
lat: 0,
containerX: 0,
containerY: 0,
button: "left",
heldKeys: [],
});

features = store.copyAll();
expect(features.length).toBe(1);

expect(onChange).toBeCalledTimes(3);
expect(onChange).toBeCalledWith([expect.any(String)], "create");

expect(store.copyAll()[0].properties.radiusKilometers).toStrictEqual(
1000,
);

expect(onFinish).toBeCalledTimes(1);
});
});
});
});
Expand Down Expand Up @@ -280,7 +356,7 @@ describe("TerraDrawCircleMode", () => {
button: "left",
heldKeys: [],
});
expect(onChange).toBeCalledTimes(2);
expect(onChange).toBeCalledTimes(3);
expect(onChange).toHaveBeenNthCalledWith(
2,
[expect.any(String)],
Expand Down
32 changes: 29 additions & 3 deletions src/modes/circle/circle.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface TerraDrawCircleModeOptions<T extends CustomStyling>
extends BaseModeOptions<T> {
keyEvents?: TerraDrawCircleModeKeyEvents | null;
cursors?: Cursors;
minimumRadiusKilometers?: number;
}

export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyling> {
Expand All @@ -47,7 +48,17 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyl
private currentCircleId: FeatureId | undefined;
private keyEvents: TerraDrawCircleModeKeyEvents;
private cursors: Required<Cursors>;

private minimumRadiusKilometers: number;

/**
* Create a new circle mode instance
* @param options - Options to customize the behavior of the circle mode
* @param options.keyEvents - Key events to cancel or finish the mode
* @param options.cursors - Cursors to use for the mode
* @param options.minimumRadiusKilometers - Minimum radius for the circle
* @param options.styles - Custom styling for the circle
* @param options.pointerDistance - Distance in pixels to consider a pointer close to a vertex
*/
constructor(options?: TerraDrawCircleModeOptions<CirclePolygonStyling>) {
super(options);

Expand All @@ -72,6 +83,8 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyl
? { ...defaultKeyEvents, ...options.keyEvents }
: defaultKeyEvents;
}

this.minimumRadiusKilometers = options?.minimumRadiusKilometers ?? 0.00001;
}

private close() {
Expand Down Expand Up @@ -112,7 +125,7 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyl
this.center = [event.lng, event.lat];
const startingCircle = circle({
center: this.center,
radiusKilometers: 0.00001,
radiusKilometers: this.minimumRadiusKilometers,
coordinatePrecision: this.coordinatePrecision,
});

Expand All @@ -121,6 +134,7 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyl
geometry: startingCircle.geometry,
properties: {
mode: this.mode,
radiusKilometers: this.minimumRadiusKilometers,
},
},
]);
Expand Down Expand Up @@ -239,15 +253,27 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<CirclePolygonStyl
event.lat,
]);

const newRadius =
distanceKm > this.minimumRadiusKilometers
? distanceKm
: this.minimumRadiusKilometers;

const updatedCircle = circle({
center: this.center,
radiusKilometers: distanceKm,
radiusKilometers: newRadius,
coordinatePrecision: this.coordinatePrecision,
});

this.store.updateGeometry([
{ id: this.currentCircleId, geometry: updatedCircle.geometry },
]);
this.store.updateProperty([
{
id: this.currentCircleId,
property: "radiusKilometers",
value: newRadius,
},
]);
}
}
}

0 comments on commit ca301ef

Please sign in to comment.