fix: free draw flip not scaling correctly (#5752)

This commit is contained in:
Antonio Della Fortuna 2022-10-19 00:03:58 +02:00 committed by GitHub
parent 941b2d7042
commit 55110bf1b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 145 additions and 47 deletions

View file

@ -6,10 +6,14 @@ import { ExcalidrawElement, NonDeleted } from "../element/types";
import { normalizeAngle, resizeSingleElement } from "../element/resizeElements";
import { AppState } from "../types";
import { getTransformHandles } from "../element/transformHandles";
import { isFreeDrawElement, isLinearElement } from "../element/typeChecks";
import { updateBoundElements } from "../element/binding";
import { LinearElementEditor } from "../element/linearElementEditor";
import { arrayToMap } from "../utils";
import {
getElementAbsoluteCoords,
getElementPointsCoords,
} from "../element/bounds";
import { isLinearElement } from "../element/typeChecks";
import { LinearElementEditor } from "../element/linearElementEditor";
const enableActionFlipHorizontal = (
elements: readonly ExcalidrawElement[],
@ -118,13 +122,6 @@ const flipElement = (
const height = element.height;
const originalAngle = normalizeAngle(element.angle);
let finalOffsetX = 0;
if (isLinearElement(element) || isFreeDrawElement(element)) {
finalOffsetX =
element.points.reduce((max, point) => Math.max(max, point[0]), 0) * 2 -
element.width;
}
// Rotate back to zero, if necessary
mutateElement(element, {
angle: normalizeAngle(0),
@ -132,7 +129,6 @@ const flipElement = (
// Flip unrotated by pulling TransformHandle to opposite side
const transformHandles = getTransformHandles(element, appState.zoom);
let usingNWHandle = true;
let newNCoordsX = 0;
let nHandle = transformHandles.nw;
if (!nHandle) {
// Use ne handle instead
@ -146,30 +142,51 @@ const flipElement = (
}
}
let finalOffsetX = 0;
if (isLinearElement(element) && element.points.length < 3) {
finalOffsetX =
element.points.reduce((max, point) => Math.max(max, point[0]), 0) * 2 -
element.width;
}
let initialPointsCoords;
if (isLinearElement(element)) {
initialPointsCoords = getElementPointsCoords(
element,
element.points,
element.strokeSharpness,
);
}
const initialElementAbsoluteCoords = getElementAbsoluteCoords(element);
if (isLinearElement(element) && element.points.length < 3) {
for (let index = 1; index < element.points.length; index++) {
LinearElementEditor.movePoints(element, [
{ index, point: [-element.points[index][0], element.points[index][1]] },
{
index,
point: [-element.points[index][0], element.points[index][1]],
},
]);
}
LinearElementEditor.normalizePoints(element);
} else {
// calculate new x-coord for transformation
newNCoordsX = usingNWHandle ? element.x + 2 * width : element.x - 2 * width;
const elWidth = initialPointsCoords
? initialPointsCoords[2] - initialPointsCoords[0]
: initialElementAbsoluteCoords[2] - initialElementAbsoluteCoords[0];
const startPoint = initialPointsCoords
? [initialPointsCoords[0], initialPointsCoords[1]]
: [initialElementAbsoluteCoords[0], initialElementAbsoluteCoords[1]];
resizeSingleElement(
new Map().set(element.id, element),
true,
false,
element,
usingNWHandle ? "nw" : "ne",
false,
newNCoordsX,
nHandle[1],
true,
usingNWHandle ? startPoint[0] + elWidth : startPoint[0] - elWidth,
startPoint[1],
);
// fix the size to account for handle sizes
mutateElement(element, {
width,
height,
});
}
// Rotate by (360 degrees - original angle)
@ -186,9 +203,34 @@ const flipElement = (
mutateElement(element, {
x: originalX + finalOffsetX,
y: originalY,
width,
height,
});
updateBoundElements(element);
if (initialPointsCoords && isLinearElement(element)) {
// Adjusting origin because when a beizer curve path exceeds min/max points it offsets the origin.
// There's still room for improvement since when the line roughness is > 1
// we still have a small offset of the origin when fliipping the element.
const finalPointsCoords = getElementPointsCoords(
element,
element.points,
element.strokeSharpness,
);
const topLeftCoordsDiff = initialPointsCoords[0] - finalPointsCoords[0];
const topRightCoordDiff = initialPointsCoords[2] - finalPointsCoords[2];
const coordsDiff = topLeftCoordsDiff + topRightCoordDiff;
mutateElement(element, {
x: element.x + coordsDiff * 0.5,
y: element.y,
width,
height,
});
}
};
const rotateElement = (element: ExcalidrawElement, rotationAngle: number) => {