feat(transform): add transform session commands
This commit is contained in:
112
commands/transform.ts
Normal file
112
commands/transform.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import type { Rect, Vec2D } from "@core/geometry";
|
||||
import type { TransformHandle, TransformTarget } from "@editor/transform";
|
||||
import type { Command } from "./command";
|
||||
import { commandIds } from "./ids";
|
||||
|
||||
export type TransformBeginPayload = {
|
||||
target: TransformTarget;
|
||||
handle: TransformHandle;
|
||||
point: Vec2D;
|
||||
initialBounds: Rect;
|
||||
};
|
||||
|
||||
export type TransformUpdatePayload = {
|
||||
point: Vec2D;
|
||||
};
|
||||
|
||||
export const transformBeginCommand: Command<TransformBeginPayload> = {
|
||||
id: commandIds.transformBegin,
|
||||
name: "Begin transform",
|
||||
execute({ state }, payload) {
|
||||
return {
|
||||
...state,
|
||||
editor: {
|
||||
...state.editor,
|
||||
transformSession: {
|
||||
target: payload.target,
|
||||
handle: payload.handle,
|
||||
startPoint: payload.point,
|
||||
initialBounds: payload.initialBounds,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const transformUpdateCommand: Command<TransformUpdatePayload> = {
|
||||
id: commandIds.transformUpdate,
|
||||
name: "Update transform",
|
||||
execute({ state }, payload) {
|
||||
const session = state.editor.transformSession;
|
||||
if (!session) return state;
|
||||
|
||||
const nextBounds = transformBounds(session.initialBounds, session.handle, {
|
||||
x: payload.point.x - session.startPoint.x,
|
||||
y: payload.point.y - session.startPoint.y,
|
||||
});
|
||||
|
||||
if (session.target.type === "artboard") {
|
||||
return {
|
||||
...state,
|
||||
document: {
|
||||
...state.document,
|
||||
artboards: state.document.artboards.map((artboard) =>
|
||||
artboard.id === session.target.id ? { ...artboard, bounds: nextBounds } : artboard,
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
};
|
||||
|
||||
export const transformEndCommand: Command = {
|
||||
id: commandIds.transformEnd,
|
||||
name: "End transform",
|
||||
execute({ state }) {
|
||||
if (!state.editor.transformSession) return state;
|
||||
|
||||
return {
|
||||
...state,
|
||||
editor: {
|
||||
...state.editor,
|
||||
transformSession: undefined,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const transformCommands = [transformBeginCommand, transformUpdateCommand, transformEndCommand] satisfies Command<unknown>[];
|
||||
|
||||
function transformBounds(bounds: Rect, handle: TransformHandle, delta: Vec2D): Rect {
|
||||
if (handle === "body") return { ...bounds, x: bounds.x + delta.x, y: bounds.y + delta.y };
|
||||
|
||||
let x = bounds.x;
|
||||
let y = bounds.y;
|
||||
let w = bounds.w;
|
||||
let h = bounds.h;
|
||||
|
||||
if (handle.includes("w")) {
|
||||
x = bounds.x + delta.x;
|
||||
w = bounds.w - delta.x;
|
||||
}
|
||||
if (handle.includes("e")) w = bounds.w + delta.x;
|
||||
if (handle.includes("n")) {
|
||||
y = bounds.y + delta.y;
|
||||
h = bounds.h - delta.y;
|
||||
}
|
||||
if (handle.includes("s")) h = bounds.h + delta.y;
|
||||
|
||||
return normalizeRect({ x, y, w, h });
|
||||
}
|
||||
|
||||
function normalizeRect(rect: Rect): Rect {
|
||||
const minSize = 1;
|
||||
return {
|
||||
x: rect.w < minSize ? rect.x + rect.w - minSize : rect.x,
|
||||
y: rect.h < minSize ? rect.y + rect.h - minSize : rect.y,
|
||||
w: Math.max(minSize, rect.w),
|
||||
h: Math.max(minSize, rect.h),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user