feat: cursor alignment when creating linear elements with shift pressed (#5518)

* feat: cursor alignment when creating linear elements

* feat: apply cursor alignment to multi-point linear elements

* refactor: rename size helper function
This commit is contained in:
Ryan Di 2022-08-02 18:13:19 +08:00 committed by GitHub
parent 54c7ec416a
commit 865d29388c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 9 deletions

View File

@ -87,9 +87,9 @@ import {
getDragOffsetXY, getDragOffsetXY,
getElementWithTransformHandleType, getElementWithTransformHandleType,
getNormalizedDimensions, getNormalizedDimensions,
getPerfectElementSize,
getResizeArrowDirection, getResizeArrowDirection,
getResizeOffsetXY, getResizeOffsetXY,
getLockedLinearCursorAlignSize,
getTransformHandleTypeFromCoords, getTransformHandleTypeFromCoords,
hitTest, hitTest,
isHittingElementBoundingBoxWithoutHittingElement, isHittingElementBoundingBoxWithoutHittingElement,
@ -2768,10 +2768,13 @@ class App extends React.Component<AppProps, AppState> {
if (shouldRotateWithDiscreteAngle(event)) { if (shouldRotateWithDiscreteAngle(event)) {
({ width: dxFromLastCommitted, height: dyFromLastCommitted } = ({ width: dxFromLastCommitted, height: dyFromLastCommitted } =
getPerfectElementSize( getLockedLinearCursorAlignSize(
this.state.activeTool.type, // actual coordinate of the last committed point
dxFromLastCommitted, lastCommittedX + rx,
dyFromLastCommitted, lastCommittedY + ry,
// cursor-grid coordinate
gridX,
gridY,
)); ));
} }
@ -4241,10 +4244,11 @@ class App extends React.Component<AppProps, AppState> {
let dy = gridY - draggingElement.y; let dy = gridY - draggingElement.y;
if (shouldRotateWithDiscreteAngle(event) && points.length === 2) { if (shouldRotateWithDiscreteAngle(event) && points.length === 2) {
({ width: dx, height: dy } = getPerfectElementSize( ({ width: dx, height: dy } = getLockedLinearCursorAlignSize(
this.state.activeTool.type, draggingElement.x,
dx, draggingElement.y,
dy, pointerCoords.x,
pointerCoords.y,
)); ));
} }

View File

@ -53,6 +53,7 @@ export { textWysiwyg } from "./textWysiwyg";
export { redrawTextBoundingBox } from "./textElement"; export { redrawTextBoundingBox } from "./textElement";
export { export {
getPerfectElementSize, getPerfectElementSize,
getLockedLinearCursorAlignSize,
isInvisiblySmallElement, isInvisiblySmallElement,
resizePerfectLineForNWHandler, resizePerfectLineForNWHandler,
getNormalizedDimensions, getNormalizedDimensions,

View File

@ -47,6 +47,46 @@ export const getPerfectElementSize = (
return { width, height }; return { width, height };
}; };
export const getLockedLinearCursorAlignSize = (
originX: number,
originY: number,
x: number,
y: number,
) => {
let width = x - originX;
let height = y - originY;
const lockedAngle =
Math.round(Math.atan(height / width) / SHIFT_LOCKING_ANGLE) *
SHIFT_LOCKING_ANGLE;
if (lockedAngle === 0) {
height = 0;
} else if (lockedAngle === Math.PI / 2) {
width = 0;
} else {
// locked angle line, y = mx + b => mx - y + b = 0
const a1 = Math.tan(lockedAngle);
const b1 = -1;
const c1 = originY - a1 * originX;
// line through cursor, perpendicular to locked angle line
const a2 = -1 / a1;
const b2 = -1;
const c2 = y - a2 * x;
// intersection of the two lines above
const intersectX = Math.round((b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1));
const intersectY = Math.round((c1 * a2 - c2 * a1) / (a1 * b2 - a2 * b1));
// delta
width = intersectX - originX;
height = intersectY - originY;
}
return { width, height };
};
export const resizePerfectLineForNWHandler = ( export const resizePerfectLineForNWHandler = (
element: ExcalidrawElement, element: ExcalidrawElement,
x: number, x: number,