104 lines
2.4 KiB
TypeScript
104 lines
2.4 KiB
TypeScript
import type { MaskDefinition } from "@/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<"rectangle"> = {
|
|
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: {
|
|
body: {
|
|
kind: "fillPath",
|
|
buildPath({ resolvedParams, width, height }) {
|
|
const params = resolvedParams;
|
|
const { centerX, centerY, maskWidth, maskHeight, rotationRad } =
|
|
getBoxLikeGeometry({ params, width, height });
|
|
return buildRectanglePath({
|
|
centerX,
|
|
centerY,
|
|
halfWidth: maskWidth / 2,
|
|
halfHeight: maskHeight / 2,
|
|
rotationRad,
|
|
});
|
|
},
|
|
},
|
|
stroke: {
|
|
kind: "strokeFromPath",
|
|
buildStrokePath({ resolvedParams, width, height }) {
|
|
const params = resolvedParams;
|
|
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,
|
|
});
|
|
},
|
|
},
|
|
},
|
|
};
|