Files
moteva/frontend/tests/pathPen.test.mjs
T
root d424b56076 feat: add CanvasPathEditor and editable path functionality
- Implemented CanvasPathEditor component for editing paths on the canvas.
- Created editablePath module to handle path data manipulation and conversion to SVG.
- Introduced pathPen module for managing path drawing with a pen tool, including anchor management and path data generation.
- Added tests for editablePath and pathPen functionalities to ensure correctness of path editing and drawing behavior.
2026-07-17 11:28:29 +08:00

69 lines
2.5 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
appendPathPenAnchor,
closePathPenDraft,
constrainPathPenPoint,
createPathPenNode,
pathPenDraftToPathData,
setLastPathPenAnchorHandles,
startPathPenDraft
} from "../src/ui/pages/CanvasWorkspace/canvas/pathPen.ts";
const settings = { color: "#123456", width: 3 };
function point(x, y) {
return { screen: { x, y }, world: { x, y } };
}
test("creates one Pen anchor for each user click", () => {
let draft = startPathPenDraft(settings, 1, point(10, 20));
draft = appendPathPenAnchor(draft, point(110, 20));
draft = appendPathPenAnchor(draft, point(110, 80));
assert.equal(draft.anchors.length, 3);
assert.deepEqual(pathPenDraftToPathData(draft), [1, 10, 20, 2, 110, 20, 2, 110, 80]);
});
test("turns click-drag anchors into Photoshop-style mirrored Bezier handles", () => {
let draft = startPathPenDraft(settings, 1, point(10, 20));
draft = setLastPathPenAnchorHandles(draft, point(40, 20));
draft = appendPathPenAnchor(draft, point(110, 80));
draft = setLastPathPenAnchorHandles(draft, point(130, 100));
assert.deepEqual(draft.anchors[0].handleIn?.world, { x: -20, y: 20 });
assert.deepEqual(draft.anchors[0].handleOut?.world, { x: 40, y: 20 });
assert.deepEqual(draft.anchors[1].handleIn?.world, { x: 90, y: 60 });
assert.deepEqual(pathPenDraftToPathData(draft), [1, 10, 20, 5, 40, 20, 90, 60, 110, 80]);
});
test("constrains Pen anchors and handles to 45-degree increments with Shift", () => {
const constrained = constrainPathPenPoint({ x: 10, y: 10 }, { x: 42, y: 24 });
assert.equal(Math.round(constrained.x), 35);
assert.equal(Math.round(constrained.y), 35);
});
test("closes a Pen path back to its first user anchor", () => {
let draft = startPathPenDraft(settings, 1, point(0, 0));
draft = appendPathPenAnchor(draft, point(100, 0));
draft = appendPathPenAnchor(draft, point(100, 100));
draft = closePathPenDraft(draft);
assert.deepEqual(pathPenDraftToPathData(draft), [1, 0, 0, 2, 100, 0, 2, 100, 100, 11]);
});
test("persists a completed Pen path as an editable shape node", () => {
let draft = startPathPenDraft(settings, 1, point(10, 20));
draft = appendPathPenAnchor(draft, point(110, 20));
const node = createPathPenNode(draft, "Pen");
const options = JSON.parse(node.content);
assert.equal(node.type, "frame");
assert.equal(node.layerRole, "shape");
assert.equal(node.strokeColor, settings.color);
assert.equal(options.kind, "path");
assert.deepEqual(options.pathData, [1, 0.04955, 0.5, 2, 0.95045, 0.5]);
});