summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/masks/definitions/rectangle.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-15 15:45:50 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-15 15:45:50 +0200
commitc46d28891fee62ca2d3132da876af6411a41d9da (patch)
treef856f71d04c69628f26b904088d675dd298a5080 /apps/web/src/lib/masks/definitions/rectangle.ts
parent66e4367bc4727f1d0bcf8f869529c7518812277e (diff)
downloadopencut-c46d28891fee62ca2d3132da876af6411a41d9da.tar.gz
feat: text / custom masks, fix preview pan, refactor selection
Diffstat (limited to 'apps/web/src/lib/masks/definitions/rectangle.ts')
-rw-r--r--apps/web/src/lib/masks/definitions/rectangle.ts191
1 files changed, 97 insertions, 94 deletions
diff --git a/apps/web/src/lib/masks/definitions/rectangle.ts b/apps/web/src/lib/masks/definitions/rectangle.ts
index 08f969ea..832b8307 100644
--- a/apps/web/src/lib/masks/definitions/rectangle.ts
+++ b/apps/web/src/lib/masks/definitions/rectangle.ts
@@ -1,94 +1,97 @@
-import type { MaskDefinition, RectangleMaskParams } from "@/lib/masks/types";
-import {
- BOX_LIKE_MASK_PARAMS,
- computeBoxMaskParamUpdate,
- getBoxLikeGeometry,
- getDefaultSquareMaskParams,
- getStrokeOffset,
- rotatePoint,
-} from "./box-like";
-
-function buildRectanglePath({
- centerX,
- centerY,
- halfWidth,
- halfHeight,
- rotationRad,
-}: {
- centerX: number;
- centerY: number;
- halfWidth: number;
- halfHeight: number;
- rotationRad: number;
-}): Path2D {
- const corners = [
- { x: centerX - halfWidth, y: centerY - halfHeight },
- { x: centerX + halfWidth, y: centerY - halfHeight },
- { x: centerX + halfWidth, y: centerY + halfHeight },
- { x: centerX - halfWidth, y: centerY + halfHeight },
- ].map((point) =>
- rotatePoint({
- ...point,
- centerX,
- centerY,
- rotationRad,
- }),
- );
-
- const path = new Path2D();
- path.moveTo(corners[0].x, corners[0].y);
- for (const corner of corners.slice(1)) {
- path.lineTo(corner.x, corner.y);
- }
- path.closePath();
- return path;
-}
-
-export const rectangleMaskDefinition: MaskDefinition<RectangleMaskParams> = {
- type: "rectangle",
- name: "Rectangle",
- overlayShape: "box",
- features: {
- hasPosition: true,
- hasRotation: true,
- sizeMode: "width-height",
- },
- params: BOX_LIKE_MASK_PARAMS,
- buildDefault(context) {
- return {
- type: "rectangle",
- params: getDefaultSquareMaskParams(context),
- };
- },
- computeParamUpdate: computeBoxMaskParamUpdate,
- renderer: {
- buildPath({ resolvedParams, width, height }) {
- const params = resolvedParams as RectangleMaskParams;
- const { centerX, centerY, maskWidth, maskHeight, rotationRad } =
- getBoxLikeGeometry({ params, width, height });
- return buildRectanglePath({
- centerX,
- centerY,
- halfWidth: maskWidth / 2,
- halfHeight: maskHeight / 2,
- rotationRad,
- });
- },
- buildStrokePath({ resolvedParams, width, height }) {
- const params = resolvedParams as RectangleMaskParams;
- const { centerX, centerY, maskWidth, maskHeight, rotationRad } =
- getBoxLikeGeometry({ params, width, height });
- const offset = getStrokeOffset({
- strokeAlign: params.strokeAlign,
- strokeWidth: params.strokeWidth,
- });
- return buildRectanglePath({
- centerX,
- centerY,
- halfWidth: Math.max(1, maskWidth / 2 + offset),
- halfHeight: Math.max(1, maskHeight / 2 + offset),
- rotationRad,
- });
- },
- },
-};
+import type { MaskDefinition, RectangleMaskParams } from "@/lib/masks/types";
+import {
+ BOX_LIKE_MASK_PARAMS,
+ buildBoxMaskInteraction,
+ computeBoxMaskParamUpdate,
+ getBoxLikeGeometry,
+ getDefaultSquareMaskParams,
+ getStrokeOffset,
+ rotatePoint,
+} from "./box-like";
+
+function buildRectanglePath({
+ centerX,
+ centerY,
+ halfWidth,
+ halfHeight,
+ rotationRad,
+}: {
+ centerX: number;
+ centerY: number;
+ halfWidth: number;
+ halfHeight: number;
+ rotationRad: number;
+}): Path2D {
+ const corners = [
+ { x: centerX - halfWidth, y: centerY - halfHeight },
+ { x: centerX + halfWidth, y: centerY - halfHeight },
+ { x: centerX + halfWidth, y: centerY + halfHeight },
+ { x: centerX - halfWidth, y: centerY + halfHeight },
+ ].map((point) =>
+ rotatePoint({
+ ...point,
+ centerX,
+ centerY,
+ rotationRad,
+ }),
+ );
+
+ const path = new Path2D();
+ path.moveTo(corners[0].x, corners[0].y);
+ for (const corner of corners.slice(1)) {
+ path.lineTo(corner.x, corner.y);
+ }
+ path.closePath();
+ return path;
+}
+
+export const rectangleMaskDefinition: MaskDefinition<RectangleMaskParams> = {
+ type: "rectangle",
+ name: "Rectangle",
+ features: {
+ hasPosition: true,
+ hasRotation: true,
+ sizeMode: "width-height",
+ },
+ params: BOX_LIKE_MASK_PARAMS,
+ interaction: buildBoxMaskInteraction({
+ sizeMode: "width-height",
+ }),
+ buildDefault(context) {
+ return {
+ type: "rectangle",
+ params: getDefaultSquareMaskParams(context),
+ };
+ },
+ computeParamUpdate: computeBoxMaskParamUpdate,
+ renderer: {
+ buildPath({ resolvedParams, width, height }) {
+ const params = resolvedParams as RectangleMaskParams;
+ const { centerX, centerY, maskWidth, maskHeight, rotationRad } =
+ getBoxLikeGeometry({ params, width, height });
+ return buildRectanglePath({
+ centerX,
+ centerY,
+ halfWidth: maskWidth / 2,
+ halfHeight: maskHeight / 2,
+ rotationRad,
+ });
+ },
+ buildStrokePath({ resolvedParams, width, height }) {
+ const params = resolvedParams as RectangleMaskParams;
+ const { centerX, centerY, maskWidth, maskHeight, rotationRad } =
+ getBoxLikeGeometry({ params, width, height });
+ const offset = getStrokeOffset({
+ strokeAlign: params.strokeAlign,
+ strokeWidth: params.strokeWidth,
+ });
+ return buildRectanglePath({
+ centerX,
+ centerY,
+ halfWidth: Math.max(1, maskWidth / 2 + offset),
+ halfHeight: Math.max(1, maskHeight / 2 + offset),
+ rotationRad,
+ });
+ },
+ },
+};