feat(editor): visualize binding midpoints + support for simple arrows (#10611)
* feat: Force exact center focus point When the projected point is close to center snap it to the exact center. Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Snap to center around side mid point. Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * Trigger CI * fix: Midpoint outline focus point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Dragging existing arrow reset focus point on outline Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Midpoint indicator Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Rotated mid points Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: No hole Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Cache hits and scene lookups Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Remove debug Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Consider hit threshold and inside override too Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Increase outline midpoint sticky distance Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Don't show midpoint indicator when no snapping is possible Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Indicate lock-in Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Remove Map caching Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: incorrect threshold Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: threshold setting Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Hit caching Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Simple arrow mid point selection inconsistency Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: cache override Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Precise know dragging with midpoint refactor Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fear: Frame support Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Crossing arrow won't trigger mid point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Arrow creation point highlight Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Restore types & tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Restore restore.ts Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: restore.ts Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Elbow arrows reliably highlight center point Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Highlight point ordering Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * feat: Bind with focus point across shape Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Lint * fix: Midpoint and binding alignment Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: Indicator color Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * chore: More knob tuning Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Radius Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * fix: Tests Signed-off-by: Mark Tolmacs <mark@lazycat.hu> * simplify point indicators --------- Signed-off-by: Mark Tolmacs <mark@lazycat.hu> Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -249,6 +249,7 @@ import {
|
||||
maxBindingDistance_simple,
|
||||
convertToExcalidrawElements,
|
||||
type ExcalidrawElementSkeleton,
|
||||
getSnapOutlineMidPoint,
|
||||
handleFocusPointDrag,
|
||||
handleFocusPointHover,
|
||||
handleFocusPointPointerDown,
|
||||
@@ -6400,15 +6401,28 @@ class App extends React.Component<AppProps, AppState> {
|
||||
// and point
|
||||
const { newElement } = this.state;
|
||||
if (!newElement && isBindingEnabled(this.state)) {
|
||||
const globalPoint = pointFrom<GlobalPoint>(
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
);
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
const hoveredElement = getHoveredElementForBinding(
|
||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||
globalPoint,
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
elementsMap,
|
||||
maxBindingDistance_simple(this.state.zoom),
|
||||
);
|
||||
if (hoveredElement) {
|
||||
this.setState({
|
||||
suggestedBinding: hoveredElement,
|
||||
suggestedBinding: {
|
||||
element: hoveredElement,
|
||||
midPoint: getSnapOutlineMidPoint(
|
||||
globalPoint,
|
||||
hoveredElement,
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
),
|
||||
},
|
||||
});
|
||||
} else if (this.state.suggestedBinding) {
|
||||
this.setState({
|
||||
@@ -6591,16 +6605,19 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
maxBindingDistance_simple(this.state.zoom),
|
||||
);
|
||||
if (
|
||||
hit &&
|
||||
!isPointInElement(
|
||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||
hit,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
)
|
||||
) {
|
||||
const scenePointer = pointFrom<GlobalPoint>(scenePointerX, scenePointerY);
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
if (hit && !isPointInElement(scenePointer, hit, elementsMap)) {
|
||||
this.setState({
|
||||
suggestedBinding: hit,
|
||||
suggestedBinding: {
|
||||
element: hit,
|
||||
midPoint: getSnapOutlineMidPoint(
|
||||
scenePointer,
|
||||
hit,
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8762,7 +8779,18 @@ class App extends React.Component<AppProps, AppState> {
|
||||
bindMode: "orbit",
|
||||
newElement: element,
|
||||
startBoundElement: boundElement,
|
||||
suggestedBinding: boundElement || null,
|
||||
suggestedBinding:
|
||||
boundElement && isBindingElement(element)
|
||||
? {
|
||||
element: boundElement,
|
||||
midPoint: getSnapOutlineMidPoint(
|
||||
point,
|
||||
boundElement,
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
),
|
||||
}
|
||||
: null,
|
||||
selectedElementIds: nextSelectedElementIds,
|
||||
selectedLinearElement: linearElementEditor,
|
||||
};
|
||||
|
||||
@@ -135,7 +135,6 @@ describe("binding with linear elements", () => {
|
||||
) as HTMLInputElement;
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
expect(inputX).not.toBeNull();
|
||||
|
||||
UI.updateInput(inputX, String("184"));
|
||||
expect(linear.startBinding).not.toBe(null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user