Fix wrong mask position after merging groups (#2682)

This commit is contained in:
Abdo 2023-09-26 06:14:13 +03:00 committed by GitHub
parent bae8038178
commit bccc5b0995
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,6 +2,7 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { Canvas, Object as FabricObject } from "fabric"; import type { Canvas, Object as FabricObject } from "fabric";
import { fabric } from "fabric";
import { makeMaskTransparent } from "../tools/lib"; import { makeMaskTransparent } from "../tools/lib";
import type { Size } from "../types"; import type { Size } from "../types";
@ -10,7 +11,10 @@ import { Ellipse } from "./ellipse";
import { Polygon } from "./polygon"; import { Polygon } from "./polygon";
import { Rectangle } from "./rectangle"; import { Rectangle } from "./rectangle";
export function exportShapesToClozeDeletions(occludeInactive: boolean): { clozes: string; noteCount: number } { export function exportShapesToClozeDeletions(occludeInactive: boolean): {
clozes: string;
noteCount: number;
} {
const shapes = baseShapesFromFabric(occludeInactive); const shapes = baseShapesFromFabric(occludeInactive);
let clozes = ""; let clozes = "";
@ -28,14 +32,15 @@ function baseShapesFromFabric(occludeInactive: boolean): ShapeOrShapes[] {
const canvas = globalThis.canvas as Canvas; const canvas = globalThis.canvas as Canvas;
makeMaskTransparent(canvas, false); makeMaskTransparent(canvas, false);
const objects = canvas.getObjects() as FabricObject[]; const objects = canvas.getObjects() as FabricObject[];
return objects.map((object) => { return objects
return fabricObjectToBaseShapeOrShapes(canvas, object, occludeInactive); .map((object) => {
}).filter((o): o is ShapeOrShapes => o !== null); return fabricObjectToBaseShapeOrShapes(
} canvas,
object,
interface TopAndLeftOffset { occludeInactive,
top: number; );
left: number; })
.filter((o): o is ShapeOrShapes => o !== null);
} }
/** Convert a single Fabric object/group to one or more BaseShapes. */ /** Convert a single Fabric object/group to one or more BaseShapes. */
@ -43,9 +48,10 @@ function fabricObjectToBaseShapeOrShapes(
size: Size, size: Size,
object: FabricObject, object: FabricObject,
occludeInactive: boolean, occludeInactive: boolean,
groupOffset: TopAndLeftOffset = { top: 0, left: 0 }, parentObject?: FabricObject,
): ShapeOrShapes | null { ): ShapeOrShapes | null {
let shape: Shape; let shape: Shape;
switch (object.type) { switch (object.type) {
case "rect": case "rect":
shape = new Rectangle(object); shape = new Rectangle(object);
@ -57,28 +63,37 @@ function fabricObjectToBaseShapeOrShapes(
shape = new Polygon(object); shape = new Polygon(object);
break; break;
case "group": case "group":
// Positions inside a group are relative to the group, so we return object._objects.map((child) => {
// need to pass in an offset. We do not support nested groups. return fabricObjectToBaseShapeOrShapes(
groupOffset = { size,
left: object.left + object.width / 2, child,
top: object.top + object.height / 2, occludeInactive,
}; object,
return object._objects.map((obj) => { );
return fabricObjectToBaseShapeOrShapes(size, obj, occludeInactive, groupOffset);
}); });
default: default:
return null; return null;
} }
shape.occludeInactive = occludeInactive; shape.occludeInactive = occludeInactive;
shape.left += groupOffset.left; if (parentObject) {
shape.top += groupOffset.top; const newPosition = fabric.util.transformPoint(
{ x: shape.left, y: shape.top },
parentObject.calcTransformMatrix(),
);
shape.left = newPosition.x;
shape.top = newPosition.y;
}
shape.makeNormal(size); shape.makeNormal(size);
return shape; return shape;
} }
/** generate cloze data in form of /** generate cloze data in form of
{{c1::image-occlusion:rect:top=.1:left=.23:width=.4:height=.5}} */ {{c1::image-occlusion:rect:top=.1:left=.23:width=.4:height=.5}} */
function shapeOrShapesToCloze(shapeOrShapes: ShapeOrShapes, index: number): string { function shapeOrShapesToCloze(
shapeOrShapes: ShapeOrShapes,
index: number,
): string {
let text = ""; let text = "";
function addKeyValue(key: string, value: string) { function addKeyValue(key: string, value: string) {
if (Number.isNaN(Number(value))) { if (Number.isNaN(Number(value))) {
@ -89,7 +104,9 @@ function shapeOrShapesToCloze(shapeOrShapes: ShapeOrShapes, index: number): stri
let type: string; let type: string;
if (Array.isArray(shapeOrShapes)) { if (Array.isArray(shapeOrShapes)) {
return shapeOrShapes.map((shape) => shapeOrShapesToCloze(shape, index)).join(""); return shapeOrShapes
.map((shape) => shapeOrShapesToCloze(shape, index))
.join("");
} else if (shapeOrShapes instanceof Rectangle) { } else if (shapeOrShapes instanceof Rectangle) {
type = "rect"; type = "rect";
} else if (shapeOrShapes instanceof Ellipse) { } else if (shapeOrShapes instanceof Ellipse) {