Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(terra-draw): add editable option for point mode to allow moving points whilst drawing #443

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/e2e/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ const example = {
},
},
}),
new TerraDrawPointMode(),
new TerraDrawPointMode({
editable: this.config?.includes("pointEditable"),
}),
new TerraDrawLineStringMode({
snapping: {
toCoordinate: this.config?.includes("snappingCoordinate"),
Expand Down
22 changes: 22 additions & 0 deletions packages/e2e/tests/leaflet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ test.describe("point mode", () => {

await expectPaths({ page, count: 3 });
});

test("mode can set with editable set to true and points can be moved", async ({
page,
}) => {
const mapDiv = await setupMap({
page,
configQueryParam: ["pointEditable"],
});
await changeMode({ page, mode });

await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
await expectGroupPosition({ page, x: 633, y: 353 });

await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
await page.mouse.down();
await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
await page.mouse.up();

await expectPaths({ page, count: 1 });

await expectGroupPosition({ page, x: 419, y: 233 });
});
});

test.describe("linestring mode", () => {
Expand Down
1 change: 1 addition & 0 deletions packages/e2e/tests/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Page, expect } from "@playwright/test";
export const pageUrl = "http://localhost:3000/";

export type TestConfigOptions =
| "pointEditable"
| "validationSuccess"
| "validationFailure"
| "insertCoordinates"
Expand Down
1 change: 1 addition & 0 deletions packages/terra-draw/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export const SELECT_PROPERTIES = {
} as const;

export const COMMON_PROPERTIES = {
EDITED: "edited",
CLOSING_POINT: "closingPoint",
SNAPPING_POINT: "snappingPoint",
};
284 changes: 265 additions & 19 deletions packages/terra-draw/src/modes/point/point.mode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ describe("TerraDrawPointMode", () => {

it("constructs with options", () => {
const pointMode = new TerraDrawPointMode({
cursors: {
create: "crosshair",
dragStart: "grabbing",
dragEnd: "crosshair",
},
styles: { pointOutlineColor: "#ffffff" },
});
expect(pointMode.styles).toStrictEqual({
Expand Down Expand Up @@ -180,7 +185,7 @@ describe("TerraDrawPointMode", () => {
});

describe("cleanUp", () => {
it("does nothing", () => {
it("does not throw", () => {
const pointMode = new TerraDrawPointMode();

expect(() => {
Expand All @@ -189,36 +194,241 @@ describe("TerraDrawPointMode", () => {
});
});

describe("onDrag", () => {
it("does nothing", () => {
const pointMode = new TerraDrawPointMode();
describe("onDragStart", () => {
it("does not set cursor on drag starting if editable false", () => {
const pointMode = new TerraDrawPointMode({
editable: false,
});

expect(() => {
pointMode.onDrag();
}).not.toThrow();
const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

expect(mockConfig.setCursor).toHaveBeenCalledTimes(0);
expect(setMapDraggability).toHaveBeenCalledTimes(0);
});

it("sets the cursor on drag starting when editable true", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
});

const mockConfig = MockModeConfig("point");

// Trigger the codepath which ignores none point geometries
mockConfig.store.create([
{
geometry: {
type: "Polygon",
coordinates: [
[
[0, 0],
[1, 0],
[1, 1],
[0, 1],
[0, 0],
],
],
},
properties: { mode: "polygon" },
},
]);

mockConfig.store.create([
{
geometry: {
type: "Point",
coordinates: [0.1, 0.1],
},
properties: { mode: "point" },
},
]);

mockConfig.store.create([
{
geometry: {
type: "Point",
coordinates: [0.2, 0.2],
},
properties: { mode: "point" },
},
]);

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

expect(mockConfig.setCursor).toHaveBeenCalledTimes(1);
expect(setMapDraggability).toHaveBeenCalledWith(false);
});
});

describe("onDragStart", () => {
it("does nothing", () => {
const pointMode = new TerraDrawPointMode();
describe("onDrag", () => {
it("does nothing if nothing currently edited when editable true", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
});
const mockConfig = MockModeConfig("point");

expect(() => {
pointMode.onDragStart();
}).not.toThrow();
pointMode.register(mockConfig);

const setMapDraggability = jest.fn();
pointMode.onDrag(MockCursorEvent({ lng: 0, lat: 0 }), setMapDraggability);

expect(mockConfig.onChange).toHaveBeenCalledTimes(0);
});

it("updates the point geometry on drag when editable true", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
});

const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

pointMode.onDrag(MockCursorEvent({ lng: 0, lat: 1 }), setMapDraggability);

expect(mockConfig.onChange).toHaveBeenCalledTimes(3);
expect(mockConfig.onChange).toHaveBeenNthCalledWith(
2,
[expect.any(String)],
"update",
);

// On finished called from onClick and is then only called after onDragEnd
expect(mockConfig.onFinish).toHaveBeenCalledTimes(1);
});

it("handles the falsy validation when editable true", () => {
let validations = 0;
const pointMode = new TerraDrawPointMode({
editable: true,
validation: () => {
validations++;
return {
valid: validations === 1,
};
},
});

const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

pointMode.onDrag(MockCursorEvent({ lng: 0, lat: 1 }), setMapDraggability);

expect(mockConfig.onChange).toHaveBeenCalledTimes(1);
expect(mockConfig.onFinish).toHaveBeenCalledTimes(1);
});

it("handles the truthy validation when editable true", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
validation: () => ({ valid: true }),
});

const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

pointMode.onDrag(MockCursorEvent({ lng: 0, lat: 1 }), setMapDraggability);

expect(mockConfig.onChange).toHaveBeenCalledTimes(3);
// On finished called from onClick and is then only called after onDragEnd
expect(mockConfig.onFinish).toHaveBeenCalledTimes(1);
});
});

describe("onDragEnd", () => {
it("does nothing", () => {
const pointMode = new TerraDrawPointMode();
it("doesn't set the cursor on drag ending if nothing currently edited", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
});

expect(() => {
pointMode.onDragEnd();
}).not.toThrow();
const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

const setMapDraggability = jest.fn();
pointMode.onDragEnd(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

expect(mockConfig.setCursor).toHaveBeenCalledTimes(0);
expect(setMapDraggability).toHaveBeenCalledTimes(0);
});
});

it("sets the cursor on drag ending", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
});

const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

const setMapDraggability = jest.fn();
pointMode.onDragStart(
MockCursorEvent({ lng: 0, lat: 0 }),
setMapDraggability,
);

pointMode.onDrag(MockCursorEvent({ lng: 1, lat: 0 }), setMapDraggability);

pointMode.onDragEnd(
MockCursorEvent({ lng: 1, lat: 0 }),
setMapDraggability,
);

expect(mockConfig.setCursor).toHaveBeenCalledTimes(2);
expect(mockConfig.setCursor).toHaveBeenNthCalledWith(1, "grabbing");
expect(mockConfig.setCursor).toHaveBeenNthCalledWith(2, "crosshair");
expect(setMapDraggability).toHaveBeenNthCalledWith(1, false);
expect(setMapDraggability).toHaveBeenNthCalledWith(2, true);
});
});
describe("styling", () => {
it("gets", () => {
const pointMode = new TerraDrawPointMode();
Expand Down Expand Up @@ -299,6 +509,42 @@ describe("TerraDrawPointMode", () => {
pointOutlineWidth: 2,
});
});

it("returns the correct styles for edited point", () => {
const pointMode = new TerraDrawPointMode({
editable: true,
styles: {
editedPointColor: "#222222",
editedPointWidth: 3,
editedPointOutlineColor: "#555555",
editedPointOutlineWidth: 3,
},
});

const mockConfig = MockModeConfig("point");

pointMode.register(mockConfig);

pointMode.onClick(MockCursorEvent({ lng: 0, lat: 0 }));

pointMode.onDragStart(MockCursorEvent({ lng: 0, lat: 0 }), jest.fn());

const id = mockConfig.onChange.mock.calls[0][0][0];

expect(
pointMode.styleFeature({
type: "Feature",
id,
geometry: { type: "Point", coordinates: [] },
properties: { mode: "point", edited: true },
}),
).toMatchObject({
pointColor: "#222222",
pointWidth: 3,
pointOutlineColor: "#555555",
pointOutlineWidth: 3,
});
});
});

describe("validateFeature", () => {
Expand Down
Loading
Loading