account for rotation when moving the crop region
This commit is contained in:
parent
80ff1562b8
commit
e30fd9960d
@ -445,7 +445,18 @@ import {
|
|||||||
} from "../element/flowchart";
|
} from "../element/flowchart";
|
||||||
import { searchItemInFocusAtom } from "./SearchMenu";
|
import { searchItemInFocusAtom } from "./SearchMenu";
|
||||||
import type { LocalPoint, Radians } from "../../math";
|
import type { LocalPoint, Radians } from "../../math";
|
||||||
import { clamp, pointFrom, pointDistance, vector } from "../../math";
|
import {
|
||||||
|
clamp,
|
||||||
|
pointFrom,
|
||||||
|
pointDistance,
|
||||||
|
vector,
|
||||||
|
pointRotateRads,
|
||||||
|
vectorScale,
|
||||||
|
vectorFromPoint,
|
||||||
|
vectorSubtract,
|
||||||
|
vectorDot,
|
||||||
|
vectorMagnitude,
|
||||||
|
} from "../../math";
|
||||||
import { cropElement } from "../element/cropElement";
|
import { cropElement } from "../element/cropElement";
|
||||||
|
|
||||||
const AppContext = React.createContext<AppClassProperties>(null!);
|
const AppContext = React.createContext<AppClassProperties>(null!);
|
||||||
@ -7921,22 +7932,84 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.imageCache.get(croppingElement.fileId)?.image;
|
this.imageCache.get(croppingElement.fileId)?.image;
|
||||||
|
|
||||||
if (image && !(image instanceof Promise)) {
|
if (image && !(image instanceof Promise)) {
|
||||||
const instantDragOffset = {
|
// scale the offset by at least a factor of 2 to improve ux
|
||||||
x: pointerCoords.x - lastPointerCoords.x,
|
let instantDragOffset = vectorScale(
|
||||||
y: pointerCoords.y - lastPointerCoords.y,
|
vector(
|
||||||
};
|
pointerCoords.x - lastPointerCoords.x,
|
||||||
|
pointerCoords.y - lastPointerCoords.y,
|
||||||
|
),
|
||||||
|
Math.max(this.state.zoom.value, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (croppingElement.angle !== 0) {
|
||||||
|
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(
|
||||||
|
croppingElement,
|
||||||
|
elementsMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
const topLeft = vectorFromPoint(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom(x1, y1),
|
||||||
|
pointFrom(cx, cy),
|
||||||
|
croppingElement.angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const topRight = vectorFromPoint(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom(x2, y1),
|
||||||
|
pointFrom(cx, cy),
|
||||||
|
croppingElement.angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const bottomLeft = vectorFromPoint(
|
||||||
|
pointRotateRads(
|
||||||
|
pointFrom(x1, y2),
|
||||||
|
pointFrom(cx, cy),
|
||||||
|
croppingElement.angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const topEdge = vectorSubtract(topRight, topLeft);
|
||||||
|
const leftEdge = vectorSubtract(bottomLeft, topLeft);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* project instantDrafOffset onto leftEdge to find out the y scalar
|
||||||
|
* topEdge to find out the x scalar
|
||||||
|
*/
|
||||||
|
|
||||||
|
const scaleY =
|
||||||
|
vectorDot(instantDragOffset, leftEdge) /
|
||||||
|
vectorDot(leftEdge, leftEdge);
|
||||||
|
const scaleX =
|
||||||
|
vectorDot(instantDragOffset, topEdge) /
|
||||||
|
vectorDot(topEdge, topEdge);
|
||||||
|
|
||||||
|
instantDragOffset = vectorScale(
|
||||||
|
vector(scaleX, scaleY),
|
||||||
|
/**
|
||||||
|
* projection results in small x and y scalars
|
||||||
|
* scale to account for this
|
||||||
|
*/
|
||||||
|
Math.min(
|
||||||
|
Math.max(
|
||||||
|
vectorMagnitude(topEdge),
|
||||||
|
vectorMagnitude(leftEdge),
|
||||||
|
),
|
||||||
|
100,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const nextCrop = {
|
const nextCrop = {
|
||||||
...crop,
|
...crop,
|
||||||
x: clamp(
|
x: clamp(
|
||||||
crop.x -
|
crop.x -
|
||||||
instantDragOffset.x * Math.sign(croppingElement.scale[0]),
|
instantDragOffset[0] * Math.sign(croppingElement.scale[0]),
|
||||||
0,
|
0,
|
||||||
image.naturalWidth - crop.width,
|
image.naturalWidth - crop.width,
|
||||||
),
|
),
|
||||||
y: clamp(
|
y: clamp(
|
||||||
crop.y -
|
crop.y -
|
||||||
instantDragOffset.y * Math.sign(croppingElement.scale[1]),
|
instantDragOffset[1] * Math.sign(croppingElement.scale[1]),
|
||||||
0,
|
0,
|
||||||
image.naturalHeight - crop.height,
|
image.naturalHeight - crop.height,
|
||||||
),
|
),
|
||||||
|
@ -139,3 +139,10 @@ export const vectorNormalize = (v: Vector): Vector => {
|
|||||||
|
|
||||||
return vector(v[0] / m, v[1] / m);
|
return vector(v[0] / m, v[1] / m);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project the first vector onto the second vector
|
||||||
|
*/
|
||||||
|
export const vectorProjection = (a: Vector, b: Vector) => {
|
||||||
|
return vectorScale(b, vectorDot(a, b) / vectorDot(b, b));
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user