Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 54 additions & 49 deletions src/components/Board/Board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as fabricUtils from "../../fabric/utils";
import * as fabricActions from "../../fabric/actions";
import * as fabricTypes from "../../fabric/types";
import parse from "color-parse";
import { CustomCornerObject } from "../../fabric/classes";

export type BoardProps = {
items: CanvasObject[];
Expand Down Expand Up @@ -107,18 +108,20 @@ const Board = React.forwardRef<BoardActions, BoardProps>(
const customObjects =
fabricUtils.retrieveObjects<fabricTypes.CustomObject>(canvas);
if (!customObjects) return [];
return customObjects.map((co) => {
const info = getObjectInfo(co, includeContent);

return {
id: co.name!,
category: "TODO_category",
color: "TODO_color",
value: "TODO_value",
coords: info.coords,
content: info.content,
};
});
return customObjects
.filter((el) => el.name)
.map((co) => {
const info = getObjectInfo(co, includeContent);

return {
id: co.name!,
category: "TODO_category",
color: "TODO_color",
value: "TODO_value",
coords: info.coords,
content: info.content,
};
});
}
return [];
},
Expand Down Expand Up @@ -206,6 +209,40 @@ const Board = React.forwardRef<BoardActions, BoardProps>(
});
};

const addCornerObjectToPolygon = (
polygon: fabric.Object,
index: number,
) => {
if (!editor?.canvas) return;

const cornerObject = new CustomCornerObject({
number: index + 1,
});
const bounds = polygon.getBoundingRect();

cornerObject.set({
left: bounds.left + bounds.width,
top: bounds.top + bounds.height,
});

editor.canvas.add(cornerObject);

// Ensure the corner object moves with the polygon
polygon.on("moving", () => {
const newBounds = polygon.getBoundingRect();
cornerObject.set({
left: newBounds.left + newBounds.width,
top: newBounds.top + newBounds.height,
});
editor.canvas.renderAll();
});

// Ensure the corner object is removed when the polygon is removed
polygon.on("removed", () => {
editor.canvas?.remove(cornerObject);
});
};

useEffect(() => {
const parentCanvasElement = document.getElementById(
"react-annotator-canvas",
Expand Down Expand Up @@ -558,7 +595,7 @@ const Board = React.forwardRef<BoardActions, BoardProps>(
// Clear all objects from canvas
fabricActions.deleteAll(editor?.canvas);

for (const item of items) {
items.forEach((item) => {
const scaledCoords = item.coords.map((p) =>
fabricUtils.toScaledCoord({
cInfo: { width: canvas.getWidth(), height: canvas.getHeight() },
Expand Down Expand Up @@ -586,43 +623,11 @@ const Board = React.forwardRef<BoardActions, BoardProps>(
scaledCoords.length === 4, // Is a rectangle
);

// const renderIcon = (
// ctx: CanvasRenderingContext2D,
// left: number,
// top: number,
// styleOverride: unknown,
// fabricObject: fabric.Object,
// ) => {
// const deleteIcon =
// "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";

// const img = document.createElement("img");
// img.src = deleteIcon;
// const size = 24;
// ctx.save();
// ctx.translate(left, top);
// if (fabricObject.angle)
// ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
// ctx.drawImage(img, -size / 2, -size / 2, size, size);
// ctx.restore();
// };

// polygon.controls = {
// ...polygon.controls,
// onDelete: new fabric.Control({
// x: 0.5,
// y: -0.5,
// offsetY: 16,
// cursorStyle: "pointer",
// mouseUpHandler: () => {
// console.log("deleted up!");
// return true;
// },
// render: renderIcon,
// }),
// };
canvas.add(polygon);
}
if (item.numberFlag) {
addCornerObjectToPolygon(polygon, item.numberFlag);
}
});
}, [editor?.canvas, imageSize.width, imageSize.height, items, scaleRatio]);

const renderObjectHelper = () => {
Expand Down
1 change: 1 addition & 0 deletions src/components/Board/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export type CanvasObject = {
coords: { x: number; y: number }[];
opacity?: number;
content?: string;
numberFlag?: number;
};
52 changes: 52 additions & 0 deletions src/fabric/classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { fabric } from "fabric";

interface CustomCornerObjectOptions extends fabric.IGroupOptions {
number?: number;
color?: string;
}

export class CustomCornerObject extends fabric.Group {
constructor(options: CustomCornerObjectOptions = {}) {
const number =
options.number !== undefined ? options.number.toString() : "";
const size = 5;
const circle = new fabric.Circle({
radius: size / 2,
fill: "white",
stroke: options.color ?? "green",
strokeWidth: 0.8,
originX: "center",
originY: "center",
left: 1.5,
top: -1,
});

const text = new fabric.Text(number, {
fontSize: size / 2,
fontFamily: "Arial",
originX: "center",
originY: "center",
fill: "black",
left: 1.5,
top: -1,
});

const pointer = new fabric.Triangle({
width: size / 3,
height: size / 3,
fill: options.color ?? "green",
stroke: options.color ?? "green",
strokeWidth: 1,
originX: "center",
originY: "bottom",
top: -size / 2,
angle: -45,
});

const objects = [circle, text, pointer];
super(objects, options);

this.set("selectable", false);
this.set("evented", true);
}
}