excalidraw/src/element/resizeTest.ts

220 lines
4.9 KiB
TypeScript
Raw Normal View History

import {
ExcalidrawElement,
PointerType,
NonDeletedExcalidrawElement,
} from "./types";
import {
OMIT_SIDES_FOR_MULTIPLE_ELEMENTS,
handlerRectanglesFromCoords,
handlerRectangles,
} from "./handlerRectangles";
import { AppState } from "../types";
2020-01-08 16:55:13 +01:00
type HandlerRectanglesRet = keyof ReturnType<typeof handlerRectangles>;
const isInHandlerRect = (
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
handler: [number, number, number, number],
x: number,
y: number,
) =>
x >= handler[0] &&
x <= handler[0] + handler[2] &&
y >= handler[1] &&
y <= handler[1] + handler[3];
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
export const resizeTest = (
element: NonDeletedExcalidrawElement,
appState: AppState,
x: number,
y: number,
zoom: number,
pointerType: PointerType,
): HandlerRectanglesRet | false => {
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
if (!appState.selectedElementIds[element.id]) {
return false;
}
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
const { rotation: rotationHandler, ...handlers } = handlerRectangles(
element,
zoom,
pointerType,
);
if (rotationHandler && isInHandlerRect(rotationHandler, x, y)) {
return "rotation" as HandlerRectanglesRet;
}
const filter = Object.keys(handlers).filter((key) => {
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
const handler = handlers[key as Exclude<HandlerRectanglesRet, "rotation">]!;
if (!handler) {
return false;
}
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
return isInHandlerRect(handler, x, y);
});
if (filter.length > 0) {
2020-01-08 16:55:13 +01:00
return filter[0] as HandlerRectanglesRet;
}
return false;
};
export const getElementWithResizeHandler = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
scenePointerX: number,
scenePointerY: number,
zoom: number,
pointerType: PointerType,
) => {
return elements.reduce((result, element) => {
if (result) {
return result;
}
const resizeHandle = resizeTest(
element,
appState,
scenePointerX,
scenePointerY,
zoom,
pointerType,
);
return resizeHandle ? { element, resizeHandle } : null;
}, null as { element: NonDeletedExcalidrawElement; resizeHandle: ReturnType<typeof resizeTest> } | null);
};
export const getResizeHandlerFromCoords = (
[x1, y1, x2, y2]: readonly [number, number, number, number],
scenePointerX: number,
scenePointerY: number,
zoom: number,
pointerType: PointerType,
) => {
const handlers = handlerRectanglesFromCoords(
[x1, y1, x2, y2],
0,
zoom,
pointerType,
OMIT_SIDES_FOR_MULTIPLE_ELEMENTS,
);
const found = Object.keys(handlers).find((key) => {
const handler = handlers[key as Exclude<HandlerRectanglesRet, "rotation">]!;
return handler && isInHandlerRect(handler, scenePointerX, scenePointerY);
});
return (found || false) as HandlerRectanglesRet;
};
const RESIZE_CURSORS = ["ns", "nesw", "ew", "nwse"];
const rotateResizeCursor = (cursor: string, angle: number) => {
const index = RESIZE_CURSORS.indexOf(cursor);
if (index >= 0) {
const a = Math.round(angle / (Math.PI / 4));
cursor = RESIZE_CURSORS[(index + a) % RESIZE_CURSORS.length];
}
return cursor;
};
/*
* Returns bi-directional cursor for the element being resized
*/
export const getCursorForResizingElement = (resizingElement: {
element?: ExcalidrawElement;
resizeHandle: ReturnType<typeof resizeTest>;
}): string => {
const { element, resizeHandle } = resizingElement;
const shouldSwapCursors =
element && Math.sign(element.height) * Math.sign(element.width) === -1;
let cursor = null;
switch (resizeHandle) {
case "n":
case "s":
cursor = "ns";
break;
case "w":
case "e":
cursor = "ew";
break;
case "nw":
case "se":
if (shouldSwapCursors) {
cursor = "nesw";
} else {
cursor = "nwse";
}
break;
case "ne":
case "sw":
if (shouldSwapCursors) {
cursor = "nwse";
} else {
cursor = "nesw";
}
break;
Rotation support (#1099) * rotate rectanble with fixed angle * rotate dashed rectangle with fixed angle * fix rotate handler rect * fix canvas size with rotation * angle in element base * fix bug in calculating canvas size * trial only for rectangle * hitTest for rectangle rotation * properly resize rotated rectangle * fix canvas size calculation * giving up... workaround for now * **experimental** handler to rotate rectangle * remove rotation on copy for debugging * update snapshots * better rotation handler with atan2 * rotate when drawImage * add rotation handler * hitTest for any shapes * fix hitTest for curved lines * rotate text element * rotation locking * hint messaage for rotating * show proper handlers on mobile (a workaround, there should be a better way) * refactor hitTest * support exporting png * support exporting svg * fix rotating curved line * refactor drawElementFromCanvas with getElementAbsoluteCoords * fix export png and svg * adjust resize positions for lines (N, E, S, W) * do not make handlers big on mobile * Update src/locales/en.json Alright! Co-Authored-By: Lipis <lipiridis@gmail.com> * do not show rotation/resizing hints on mobile * proper calculation for N and W positions * simplify calculation * use "rotation" as property name for clarification (may increase bundle size) * update snapshots excluding rotation handle * refactor with adjustPositionWithRotation * refactor with adjustXYWithRotation * forgot to rename rotation * rename internal function * initialize element angle on restore * rotate wysiwyg editor * fix shift-rotate around 270deg * improve rotation locking * refactor adjustXYWithRotation * avoid rotation degree becomes >=360 * refactor with generateHandler Co-authored-by: Lipis <lipiridis@gmail.com> Co-authored-by: dwelle <luzar.david@gmail.com>
2020-04-02 17:40:26 +09:00
case "rotation":
return "grab";
}
if (cursor && element) {
cursor = rotateResizeCursor(cursor, element.angle);
}
return cursor ? `${cursor}-resize` : "";
};
export const normalizeResizeHandle = (
element: ExcalidrawElement,
resizeHandle: HandlerRectanglesRet,
): HandlerRectanglesRet => {
if (element.width >= 0 && element.height >= 0) {
return resizeHandle;
}
if (element.width < 0 && element.height < 0) {
switch (resizeHandle) {
case "nw":
return "se";
case "ne":
return "sw";
case "se":
return "nw";
case "sw":
return "ne";
}
} else if (element.width < 0) {
switch (resizeHandle) {
case "nw":
return "ne";
case "ne":
return "nw";
case "se":
return "sw";
case "sw":
return "se";
case "e":
return "w";
case "w":
return "e";
}
} else {
switch (resizeHandle) {
case "nw":
return "sw";
case "ne":
return "se";
case "se":
return "ne";
case "sw":
return "nw";
case "n":
return "s";
case "s":
return "n";
}
}
return resizeHandle;
};