diff --git a/src/VisualEditor/VisualEditor.css b/src/VisualEditor/VisualEditor.css index 74e15dd..6dddec4 100644 --- a/src/VisualEditor/VisualEditor.css +++ b/src/VisualEditor/VisualEditor.css @@ -99,4 +99,9 @@ text.selected, text.selected:hover { text:hover { fill: rgba(0, 200, 0, 1); /* cursor: grab; */ +} + +.highlight { + stroke: green; + stroke-width: 4px; } \ No newline at end of file diff --git a/src/VisualEditor/VisualEditor.tsx b/src/VisualEditor/VisualEditor.tsx index ca2a5e9..f5b0de9 100644 --- a/src/VisualEditor/VisualEditor.tsx +++ b/src/VisualEditor/VisualEditor.tsx @@ -1,5 +1,5 @@ import { Dispatch, MouseEventHandler, SetStateAction, useEffect, useRef, useState } from "react"; -import { Line2D, Rect2D, Vec2D, addV2D, area, isEntirelyWithin, normalizeRect, subtractV2D, transformLine, transformRect } from "./geometry"; +import { Line2D, Rect2D, Vec2D, addV2D, area, euclideanDistance, getBottomSide, getLeftSide, getRightSide, getTopSide, intersectLines, isEntirelyWithin, isWithin, lineBBox, normalizeRect, subtractV2D, transformLine, transformRect } from "./geometry"; import "./VisualEditor.css"; import { getBBoxInSvgCoords } from "./svg_helper"; @@ -79,6 +79,34 @@ type HistoryState = { future: VisualEditorState[], } +const threshold = 20; + +const sides: [RountanglePart, (r:Rect2D)=>Line2D][] = [ + ["left", getLeftSide], + ["top", getTopSide], + ["right", getRightSide], + ["bottom", getBottomSide], +]; + +function findNearestRountangleSide(arrow: Line2D, arrowPart: "start"|"end", candidates: Rountangle[]): RountangleSelectable | undefined { + let best = Infinity; + let bestSide: undefined | RountangleSelectable; + for (const rountangle of candidates) { + for (const [side, getSide] of sides) { + const asLine = getSide(rountangle); + const intersection = intersectLines(arrow, asLine); + if (intersection !== null) { + const bbox = lineBBox(asLine, threshold); + const dist = euclideanDistance(arrow[arrowPart], intersection); + if (isWithin(arrow[arrowPart], bbox) && dist r.uid === rountangle.uid)?.parts || []} + highlight={sidesToHighlight[rountangle.uid] || []} />)} {state.arrows.map(arrow =>