From a02c4cb140d98f7174bdbe2014abc12cfdf2e236 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 4 Oct 2024 16:50:42 +0800 Subject: [PATCH] adjust crop handles --- .../excalidraw/renderer/interactiveScene.ts | 185 ++++++++++-------- 1 file changed, 98 insertions(+), 87 deletions(-) diff --git a/packages/excalidraw/renderer/interactiveScene.ts b/packages/excalidraw/renderer/interactiveScene.ts index eeb76f228e..db349559b1 100644 --- a/packages/excalidraw/renderer/interactiveScene.ts +++ b/packages/excalidraw/renderer/interactiveScene.ts @@ -305,38 +305,42 @@ const renderBindingHighlightForSuggestedPointBinding = ( }); }; +type ElementSelectionBorder = { + angle: number; + x1: number; + y1: number; + x2: number; + y2: number; + selectionColors: string[]; + dashed?: boolean; + cx: number; + cy: number; + activeEmbeddable: boolean; + padding?: number; +}; + const renderSelectionBorder = ( context: CanvasRenderingContext2D, appState: InteractiveCanvasAppState, - elementProperties: { - angle: number; - elementX1: number; - elementY1: number; - elementX2: number; - elementY2: number; - selectionColors: string[]; - dashed?: boolean; - cx: number; - cy: number; - activeEmbeddable: boolean; - }, + elementProperties: ElementSelectionBorder, ) => { const { angle, - elementX1, - elementY1, - elementX2, - elementY2, + x1, + y1, + x2, + y2, selectionColors, cx, cy, dashed, activeEmbeddable, } = elementProperties; - const elementWidth = elementX2 - elementX1; - const elementHeight = elementY2 - elementY1; + const elementWidth = x2 - x1; + const elementHeight = y2 - y1; - const padding = DEFAULT_TRANSFORM_HANDLE_SPACING * 2; + const padding = + elementProperties.padding ?? DEFAULT_TRANSFORM_HANDLE_SPACING * 2; const linePadding = padding / appState.zoom.value; const lineWidth = 8 / appState.zoom.value; @@ -358,8 +362,8 @@ const renderSelectionBorder = ( context.lineDashOffset = (lineWidth + spaceWidth) * index; strokeRectWithRotation( context, - elementX1 - linePadding, - elementY1 - linePadding, + x1 - linePadding, + y1 - linePadding, elementWidth + linePadding * 2, elementHeight + linePadding * 2, cx, @@ -431,18 +435,17 @@ const renderElementsBoxHighlight = ( ); const getSelectionFromElements = (elements: ExcalidrawElement[]) => { - const [elementX1, elementY1, elementX2, elementY2] = - getCommonBounds(elements); + const [x1, y1, x2, y2] = getCommonBounds(elements); return { angle: 0, - elementX1, - elementX2, - elementY1, - elementY2, + x1, + x2, + y1, + y2, selectionColors: ["rgb(0,118,255)"], dashed: false, - cx: elementX1 + (elementX2 - elementX1) / 2, - cy: elementY1 + (elementY2 - elementY1) / 2, + cx: x1 + (x2 - x1) / 2, + cy: y1 + (y2 - y1) / 2, activeEmbeddable: false, }; }; @@ -599,24 +602,33 @@ const renderCropHandles = ( croppingElement: ExcalidrawImageElement, elementsMap: ElementsMap, ): void => { - const lineWidth = 3 / appState.zoom.value; - const length = 15 / appState.zoom.value; - const [x1, y1, , , cx, cy] = getElementAbsoluteCoords( croppingElement, elementsMap, ); - const halfWidth = - cx - x1 + (DEFAULT_TRANSFORM_HANDLE_SPACING * 2) / appState.zoom.value; - const halfHeight = - cy - y1 + (DEFAULT_TRANSFORM_HANDLE_SPACING * 2) / appState.zoom.value; + + const LINE_WIDTH = 3; + const LINE_LENGTH = 20; + + const ZOOMED_LINE_WIDTH = LINE_WIDTH / appState.zoom.value; + const ZOOMED_HALF_LINE_WIDTH = ZOOMED_LINE_WIDTH / 2; + + const HALF_WIDTH = cx - x1 + ZOOMED_LINE_WIDTH; + const HALF_HEIGHT = cy - y1 + ZOOMED_LINE_WIDTH; + + const HORIZONTAL_LINE_LENGTH = Math.min( + LINE_LENGTH / appState.zoom.value, + HALF_WIDTH, + ); + const VERTICAL_LINE_LENGTH = Math.min( + LINE_LENGTH / appState.zoom.value, + HALF_HEIGHT, + ); context.save(); context.fillStyle = renderConfig.selectionColor; context.strokeStyle = renderConfig.selectionColor; - context.lineWidth = lineWidth; - - const halfLineWidth = lineWidth / 2; + context.lineWidth = ZOOMED_LINE_WIDTH; const handles: Array< [ @@ -629,34 +641,40 @@ const renderCropHandles = ( > = [ [ // x, y - [-halfWidth, -halfHeight], - // first start and t0 - [0, halfLineWidth], - [length, halfLineWidth], - // second start and to - [halfLineWidth, 0], - [halfLineWidth, length - halfLineWidth], + [-HALF_WIDTH, -HALF_HEIGHT], + // horizontal line: first start and to + [0, ZOOMED_HALF_LINE_WIDTH], + [HORIZONTAL_LINE_LENGTH, ZOOMED_HALF_LINE_WIDTH], + // vertical line: second start and to + [ZOOMED_HALF_LINE_WIDTH, 0], + [ZOOMED_HALF_LINE_WIDTH, VERTICAL_LINE_LENGTH], ], [ - [halfWidth - halfLineWidth, -halfHeight + halfLineWidth], - [halfLineWidth, 0], - [-length + halfLineWidth, 0], - [0, -halfLineWidth], - [0, length - lineWidth], + [HALF_WIDTH - ZOOMED_HALF_LINE_WIDTH, -HALF_HEIGHT], + [ZOOMED_HALF_LINE_WIDTH, ZOOMED_HALF_LINE_WIDTH], + [ + -HORIZONTAL_LINE_LENGTH + ZOOMED_HALF_LINE_WIDTH, + ZOOMED_HALF_LINE_WIDTH, + ], + [0, 0], + [0, VERTICAL_LINE_LENGTH], ], [ - [-halfWidth, halfHeight], - [0, -halfLineWidth], - [length, -halfLineWidth], - [halfLineWidth, 0], - [halfLineWidth, -length + halfLineWidth], + [-HALF_WIDTH, HALF_HEIGHT], + [0, -ZOOMED_HALF_LINE_WIDTH], + [HORIZONTAL_LINE_LENGTH, -ZOOMED_HALF_LINE_WIDTH], + [ZOOMED_HALF_LINE_WIDTH, 0], + [ZOOMED_HALF_LINE_WIDTH, -VERTICAL_LINE_LENGTH], ], [ - [halfWidth - halfLineWidth, halfHeight - halfLineWidth], - [halfLineWidth, 0], - [-length + halfLineWidth, 0], - [0, halfLineWidth], - [0, -length + lineWidth], + [HALF_WIDTH - ZOOMED_HALF_LINE_WIDTH, HALF_HEIGHT], + [ZOOMED_HALF_LINE_WIDTH, -ZOOMED_HALF_LINE_WIDTH], + [ + -HORIZONTAL_LINE_LENGTH + ZOOMED_HALF_LINE_WIDTH, + -ZOOMED_HALF_LINE_WIDTH, + ], + [0, 0], + [0, -VERTICAL_LINE_LENGTH], ], ]; @@ -871,18 +889,7 @@ const _renderInteractiveScene = ({ // Optimisation for finding quickly relevant element ids const locallySelectedIds = arrayToMap(selectedElements); - const selections: { - angle: number; - elementX1: number; - elementY1: number; - elementX2: number; - elementY2: number; - selectionColors: string[]; - dashed?: boolean; - cx: number; - cy: number; - activeEmbeddable: boolean; - }[] = []; + const selections: ElementSelectionBorder[] = []; for (const element of elementsMap.values()) { const selectionColors = []; @@ -922,14 +929,17 @@ const _renderInteractiveScene = ({ } if (selectionColors.length) { - const [elementX1, elementY1, elementX2, elementY2, cx, cy] = - getElementAbsoluteCoords(element, elementsMap, true); + const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords( + element, + elementsMap, + true, + ); selections.push({ angle: element.angle, - elementX1, - elementY1, - elementX2, - elementY2, + x1, + y1, + x2, + y2, selectionColors, dashed: !!remoteClients, cx, @@ -937,24 +947,25 @@ const _renderInteractiveScene = ({ activeEmbeddable: appState.activeEmbeddable?.element === element && appState.activeEmbeddable.state === "active", + padding: + element.id === appState.croppingElement?.id ? 0 : undefined, }); } } const addSelectionForGroupId = (groupId: GroupId) => { const groupElements = getElementsInGroup(elementsMap, groupId); - const [elementX1, elementY1, elementX2, elementY2] = - getCommonBounds(groupElements); + const [x1, y1, x2, y2] = getCommonBounds(groupElements); selections.push({ angle: 0, - elementX1, - elementX2, - elementY1, - elementY2, + x1, + x2, + y1, + y2, selectionColors: [oc.black], dashed: true, - cx: elementX1 + (elementX2 - elementX1) / 2, - cy: elementY1 + (elementY2 - elementY1) / 2, + cx: x1 + (x2 - x1) / 2, + cy: y1 + (y2 - y1) / 2, activeEmbeddable: false, }); };