mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Initial commit
This commit is contained in:
parent
4ec812bc18
commit
c22407b3ae
5 changed files with 171 additions and 0 deletions
136
packages/utils/snapToShape.ts
Normal file
136
packages/utils/snapToShape.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
import type {
|
||||
ExcalidrawArrowElement,
|
||||
ExcalidrawDiamondElement,
|
||||
ExcalidrawElement,
|
||||
ExcalidrawEllipseElement,
|
||||
ExcalidrawFreeDrawElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawRectangleElement,
|
||||
} from "../excalidraw/element/types";
|
||||
import type { BoundingBox } from "../excalidraw/element/bounds";
|
||||
import { getCommonBoundingBox } from "../excalidraw/element/bounds";
|
||||
import { newElement } from "../excalidraw/element";
|
||||
// @ts-ignore
|
||||
import shapeit from "@amaplex-software/shapeit";
|
||||
|
||||
type Shape =
|
||||
| ExcalidrawRectangleElement["type"]
|
||||
| ExcalidrawEllipseElement["type"]
|
||||
| ExcalidrawDiamondElement["type"]
|
||||
// | ExcalidrawArrowElement["type"]
|
||||
// | ExcalidrawLinearElement["type"]
|
||||
| ExcalidrawFreeDrawElement["type"];
|
||||
|
||||
interface ShapeRecognitionResult {
|
||||
type: Shape;
|
||||
confidence: number;
|
||||
boundingBox: BoundingBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recognizes common shapes from free-draw input
|
||||
* @param element The freedraw element to analyze
|
||||
* @returns Information about the recognized shape, or null if no shape is recognized
|
||||
*/
|
||||
export const recognizeShape = (
|
||||
element: ExcalidrawFreeDrawElement,
|
||||
): ShapeRecognitionResult => {
|
||||
const boundingBox = getCommonBoundingBox([element]);
|
||||
|
||||
// We need at least a few points to recognize a shape
|
||||
if (!element.points || element.points.length < 3) {
|
||||
return { type: "freedraw", confidence: 1, boundingBox };
|
||||
}
|
||||
|
||||
console.log("Recognizing shape from points:", element.points);
|
||||
|
||||
const shapethat = shapeit.new({
|
||||
atlas: {},
|
||||
output: {},
|
||||
thresholds: {},
|
||||
});
|
||||
|
||||
const shape = shapethat(element.points);
|
||||
|
||||
console.log("Shape recognized:", shape);
|
||||
|
||||
const mappedShape = (name: string): Shape => {
|
||||
switch (name) {
|
||||
case "rectangle":
|
||||
return "rectangle";
|
||||
case "square":
|
||||
return "rectangle";
|
||||
case "circle":
|
||||
return "ellipse";
|
||||
case "open polygon":
|
||||
return "diamond";
|
||||
default:
|
||||
return "freedraw";
|
||||
}
|
||||
};
|
||||
|
||||
const recognizedShape: ShapeRecognitionResult = {
|
||||
type: mappedShape(shape.name),
|
||||
confidence: 0.8,
|
||||
boundingBox,
|
||||
};
|
||||
|
||||
return recognizedShape;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new element based on the recognized shape from a freedraw element
|
||||
* @param freedrawElement The original freedraw element
|
||||
* @param recognizedShape The recognized shape information
|
||||
* @returns A new element of the recognized shape type
|
||||
*/
|
||||
export const createElementFromRecognizedShape = (
|
||||
freedrawElement: ExcalidrawFreeDrawElement,
|
||||
recognizedShape: ShapeRecognitionResult,
|
||||
): ExcalidrawElement => {
|
||||
if (!recognizedShape.type || recognizedShape.type === "freedraw") {
|
||||
return freedrawElement;
|
||||
}
|
||||
|
||||
// if (recognizedShape.type === "rectangle") {
|
||||
return newElement({
|
||||
...freedrawElement,
|
||||
type: recognizedShape.type,
|
||||
x: recognizedShape.boundingBox.minX,
|
||||
y: recognizedShape.boundingBox.minY,
|
||||
width: recognizedShape.boundingBox.width!,
|
||||
height: recognizedShape.boundingBox.height!,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if shape recognition should be applied based on app state
|
||||
* @param element The freedraw element to potentially snap
|
||||
* @param minConfidence The minimum confidence level required to apply snapping
|
||||
* @returns Whether to apply shape snapping
|
||||
*/
|
||||
export const shouldApplyShapeSnapping = (
|
||||
recognizedShape: ShapeRecognitionResult,
|
||||
minConfidence: number = 0.75,
|
||||
): boolean => {
|
||||
return (
|
||||
!!recognizedShape.type && (recognizedShape.confidence || 0) >= minConfidence
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a freedraw element to the detected shape
|
||||
*/
|
||||
export const convertToShape = (
|
||||
freeDrawElement: ExcalidrawFreeDrawElement,
|
||||
): ExcalidrawElement => {
|
||||
const recognizedShape = recognizeShape(freeDrawElement);
|
||||
|
||||
if (shouldApplyShapeSnapping(recognizedShape)) {
|
||||
return createElementFromRecognizedShape(freeDrawElement, recognizedShape);
|
||||
}
|
||||
|
||||
// Add more shape conversions as needed
|
||||
return freeDrawElement;
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue