import { ExcalidrawElement, PointerType } from "./types"; import { getElementAbsoluteCoords } from "./bounds"; type Sides = "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se"; const handleSizes: { [k in PointerType]: number } = { mouse: 8, pen: 16, touch: 28, }; export function handlerRectangles( element: ExcalidrawElement, zoom: number, pointerType: PointerType = "mouse", ) { const size = handleSizes[pointerType]; const handlerWidth = size / zoom; const handlerHeight = size / zoom; const handlerMarginX = size / zoom; const handlerMarginY = size / zoom; const [elementX1, elementY1, elementX2, elementY2] = getElementAbsoluteCoords( element, ); const elementWidth = elementX2 - elementX1; const elementHeight = elementY2 - elementY1; const dashedLineMargin = 4 / zoom; const centeringOffset = (size - 8) / (2 * zoom); const handlers = { nw: [ elementX1 - dashedLineMargin - handlerMarginX + centeringOffset, elementY1 - dashedLineMargin - handlerMarginY + centeringOffset, handlerWidth, handlerHeight, ], ne: [ elementX2 + dashedLineMargin - centeringOffset, elementY1 - dashedLineMargin - handlerMarginY + centeringOffset, handlerWidth, handlerHeight, ], sw: [ elementX1 - dashedLineMargin - handlerMarginX + centeringOffset, elementY2 + dashedLineMargin - centeringOffset, handlerWidth, handlerHeight, ], se: [ elementX2 + dashedLineMargin - centeringOffset, elementY2 + dashedLineMargin - centeringOffset, handlerWidth, handlerHeight, ], } as { [T in Sides]: number[] }; // We only want to show height handlers (all cardinal directions) above a certain size const minimumSizeForEightHandlers = (5 * size) / zoom; if (Math.abs(elementWidth) > minimumSizeForEightHandlers) { handlers["n"] = [ elementX1 + elementWidth / 2 - handlerWidth / 2, elementY1 - dashedLineMargin - handlerMarginY + centeringOffset, handlerWidth, handlerHeight, ]; handlers["s"] = [ elementX1 + elementWidth / 2 - handlerWidth / 2, elementY2 + dashedLineMargin - centeringOffset, handlerWidth, handlerHeight, ]; } if (Math.abs(elementHeight) > minimumSizeForEightHandlers) { handlers["w"] = [ elementX1 - dashedLineMargin - handlerMarginX + centeringOffset, elementY1 + elementHeight / 2 - handlerHeight / 2, handlerWidth, handlerHeight, ]; handlers["e"] = [ elementX2 + dashedLineMargin - centeringOffset, elementY1 + elementHeight / 2 - handlerHeight / 2, handlerWidth, handlerHeight, ]; } if (element.type === "arrow" || element.type === "line") { if (element.points.length === 2) { // only check the last point because starting point is always (0,0) const [, p1] = element.points; if (p1[0] === 0 || p1[1] === 0) { return { nw: handlers.nw, se: handlers.se, } as typeof handlers; } if (p1[0] > 0 && p1[1] < 0) { return { ne: handlers.ne, sw: handlers.sw, } as typeof handlers; } if (p1[0] > 0 && p1[1] > 0) { return { nw: handlers.nw, se: handlers.se, } as typeof handlers; } if (p1[0] < 0 && p1[1] > 0) { return { ne: handlers.ne, sw: handlers.sw, } as typeof handlers; } if (p1[0] < 0 && p1[1] < 0) { return { nw: handlers.nw, se: handlers.se, } as typeof handlers; } } return { n: handlers.n, s: handlers.s, w: handlers.w, e: handlers.e, } as typeof handlers; } return handlers; }