From 9dac6862bfb6cb6a3136a350abe9682993f6bc82 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Fri, 29 Sep 2023 16:14:50 +0100 Subject: [PATCH] Arrows followup (#1972) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR includes a few followup small fixes for arrows. ### Change Type - [x] `patch` — Bug fix --- .../shapes/shared/arrow/curved-arrow.ts | 40 ++++++++-------- .../shapes/shared/arrow/straight-arrow.ts | 46 ++++++++++--------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/packages/editor/src/lib/editor/shapes/shared/arrow/curved-arrow.ts b/packages/editor/src/lib/editor/shapes/shared/arrow/curved-arrow.ts index e7d9d0192..fdc349fde 100644 --- a/packages/editor/src/lib/editor/shapes/shared/arrow/curved-arrow.ts +++ b/packages/editor/src/lib/editor/shapes/shared/arrow/curved-arrow.ts @@ -235,9 +235,7 @@ export function getCurvedArrowInfo( ) } - const dist = Vec2d.Dist(tA, tB) - - if (dist < MIN_ARROW_LENGTH) { + if (Vec2d.Dist(tA, tB) < MIN_ARROW_LENGTH) { if (offsetA !== 0 && offsetB !== 0) { offsetA *= -1.5 offsetB *= -1.5 @@ -266,29 +264,31 @@ export function getCurvedArrowInfo( ) // Did we miss intersections? This happens when we have overlapping shapes. - if ( - startShapeInfo && - endShapeInfo && - startShapeInfo.shape !== endShapeInfo.shape && - !startShapeInfo.isExact && - !endShapeInfo.isExact - ) { + if (startShapeInfo && endShapeInfo && !startShapeInfo.isExact && !endShapeInfo.isExact) { const startAngle = Vec2d.Angle(handleArc.center, tempA) const endAngle = Vec2d.Angle(handleArc.center, tempB) const length = getArcLength(handleArc.center, handleArc.radius, tempA, tempB) - if (startShapeInfo && !startShapeInfo.didIntersect) { - tempA.setTo(a) - } - - if (endShapeInfo && !endShapeInfo.didIntersect) { - const size = angleDelta(startAngle, endAngle) - let mid = lerpAngles(startAngle, endAngle, Math.abs(MIN_ARROW_LENGTH / length)) - if (+(size > 0) !== handleArc.sweepFlag) { - mid = PI2 - mid + if (startShapeInfo.shape === endShapeInfo.shape) { + if (Math.abs(length) < 100) { + tempA.setTo(a) + tempB.setTo(b) + tempC.setTo(c) + } + } else { + if (startShapeInfo && !startShapeInfo.didIntersect) { + tempA.setTo(a) } - tempB.setTo(getPointOnCircle(handleArc.center.x, handleArc.center.y, handleArc.radius, mid)) + if (endShapeInfo && !endShapeInfo.didIntersect) { + const size = angleDelta(startAngle, endAngle) + let mid = lerpAngles(startAngle, endAngle, Math.abs(MIN_ARROW_LENGTH / length)) + if (+(size > 0) !== handleArc.sweepFlag) { + mid = PI2 - mid + } + + tempB.setTo(getPointOnCircle(handleArc.center.x, handleArc.center.y, handleArc.radius, mid)) + } } } diff --git a/packages/editor/src/lib/editor/shapes/shared/arrow/straight-arrow.ts b/packages/editor/src/lib/editor/shapes/shared/arrow/straight-arrow.ts index 8fc604be8..866ebe83a 100644 --- a/packages/editor/src/lib/editor/shapes/shared/arrow/straight-arrow.ts +++ b/packages/editor/src/lib/editor/shapes/shared/arrow/straight-arrow.ts @@ -50,7 +50,8 @@ export function getStraightArrowInfo(editor: Editor, shape: TLArrowShape): TLArr startShapeInfo ) - let minDist = MIN_ARROW_LENGTH + let offsetA = 0 + let offsetB = 0 const isSelfIntersection = startShapeInfo && endShapeInfo && startShapeInfo.shape === endShapeInfo.shape @@ -66,14 +67,14 @@ export function getStraightArrowInfo(editor: Editor, shape: TLArrowShape): TLArr // ...and if only the end shape intersected, then make it // a short arrow ending at the end shape intersection. if (startShapeInfo.isClosed) { - a.setTo(Vec2d.Nudge(b, a, minDist)) + a.setTo(b.clone().add(uAB.clone().mul(MIN_ARROW_LENGTH))) } } else if (!endShapeInfo.didIntersect) { // ...and if only the end shape intersected, or if neither // shape intersected, then make it a short arrow starting // at the start shape intersection. if (endShapeInfo.isClosed) { - b.setTo(Vec2d.Nudge(a, b, minDist)) + b.setTo(a.clone().sub(uAB.clone().mul(MIN_ARROW_LENGTH))) } } } @@ -85,48 +86,49 @@ export function getStraightArrowInfo(editor: Editor, shape: TLArrowShape): TLArr // start point has an arrowhead offset the start point if (!isSelfIntersection) { if (startShapeInfo && arrowheadStart !== 'none' && !startShapeInfo.isExact) { - const offset = + offsetA = BOUND_ARROW_OFFSET + STROKE_SIZES[shape.props.size] / 2 + ('size' in startShapeInfo.shape.props ? STROKE_SIZES[startShapeInfo.shape.props.size] / 2 : 0) - - minDist -= offset - a.nudge(b, offset * (didFlip ? -1 : 1)) } // If the arrow is bound non-exact to an end shape and the // end point has an arrowhead offset the end point if (endShapeInfo && arrowheadEnd !== 'none' && !endShapeInfo.isExact) { - const offset = + offsetB = BOUND_ARROW_OFFSET + STROKE_SIZES[shape.props.size] / 2 + ('size' in endShapeInfo.shape.props ? STROKE_SIZES[endShapeInfo.shape.props.size] / 2 : 0) - - minDist -= offset - b.nudge(a, offset * (didFlip ? -1 : 1)) } } - if (startShapeInfo && endShapeInfo) { - // If we have two bound shapes... - if (didFlip) { - // If we flipped, then make the arrow a short arrow from - // the start point towards where the end point should be. - b.setTo(Vec2d.Add(a, u.mul(-minDist))) - } else if (Vec2d.Dist(a, b) < MIN_ARROW_LENGTH / 2) { - // Otherwise, if the arrow is too short, make it a short - // arrow from the start point towards where the end point - // should be. - b.setTo(Vec2d.Add(a, u.mul(MIN_ARROW_LENGTH / 2))) + const tA = a.clone().add(u.clone().mul(offsetA * (didFlip ? -1 : 1))) + const tB = b.clone().sub(u.clone().mul(offsetB * (didFlip ? -1 : 1))) + if (Vec2d.Dist(tA, tB) < MIN_ARROW_LENGTH) { + if (offsetA !== 0 && offsetB !== 0) { + offsetA *= -1.5 + offsetB *= -1.5 + } else if (offsetA !== 0) { + offsetA *= -2 + } else if (offsetB !== 0) { + offsetB *= -2 } } + a.add(u.clone().mul(offsetA * (didFlip ? -1 : 1))) + b.sub(u.clone().mul(offsetB * (didFlip ? -1 : 1))) + // If the handles flipped their order, then set the center handle // to the midpoint of the terminals (rather than the midpoint of the // arrow body); otherwise, it may not be "between" the other terminals. if (didFlip) { + if (startShapeInfo && endShapeInfo) { + // If we have two bound shapes...then make the arrow a short arrow from + // the start point towards where the end point should be. + b.setTo(Vec2d.Add(a, u.clone().mul(-MIN_ARROW_LENGTH))) + } c.setTo(Vec2d.Med(terminalsInArrowSpace.start, terminalsInArrowSpace.end)) } else { c.setTo(Vec2d.Med(a, b))