From 0c28593ea5ce1dab4af755e689f4c0da2a4a98b0 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 30 Nov 2024 10:54:18 +0100 Subject: [PATCH] #6097 Implemented calcIntersect for the first round of shapes --- .../rendering-elements/shapes/bowTieRect.ts | 17 +++++-- .../rendering-elements/shapes/card.ts | 19 ++++++-- .../rendering-elements/shapes/choice.ts | 12 +++-- .../rendering-elements/shapes/classBox.ts | 4 +- .../shapes/crossedCircle.ts | 3 +- .../shapes/curlyBraceLeft.ts | 20 ++++++-- .../shapes/curlyBraceRight.ts | 20 ++++++-- .../rendering-elements/shapes/curlyBraces.ts | 47 ++++++++++--------- .../shapes/curvedTrapezoid.ts | 32 ++++++++----- 9 files changed, 122 insertions(+), 52 deletions(-) diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/bowTieRect.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/bowTieRect.ts index 20e8e9d4a..f578824b6 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/bowTieRect.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/bowTieRect.ts @@ -120,9 +120,20 @@ export async function bowTieRect(parent: D3Selecti updateNodeBounds(node, bowTieRectShape); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const w = bounds.width; + const h = bounds.height; + + const ry = h / 2; + const rx = ry / (2.5 + h / 50); + + const points = [ + { x: w / 2, y: -h / 2 }, + { x: -w / 2, y: -h / 2 }, + ...generateArcPoints(-w / 2, -h / 2, -w / 2, h / 2, rx, ry, false), + { x: w / 2, y: h / 2 }, + ...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true), + ]; + return intersect.polygon(bounds, points, point); }; node.intersect = function (point) { const pos = intersect.polygon(node, points, point); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/card.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/card.ts index 82a2efcaa..a4a48a822 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/card.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/card.ts @@ -57,9 +57,22 @@ export async function card(parent: D3Selection, updateNodeBounds(node, polygon); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const h = bounds.height; + const padding = 12; + const w = bounds.width; + const left = 0; + const right = w; + const top = -h; + const bottom = 0; + const points = [ + { x: left + padding, y: top }, + { x: right, y: top }, + { x: right, y: bottom }, + { x: left, y: bottom }, + { x: left, y: top + padding }, + { x: left + padding, y: top }, + ]; + return intersect.polygon(bounds, points, point); }; node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/choice.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/choice.ts index da213844b..9be5c3b73 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/choice.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/choice.ts @@ -49,9 +49,15 @@ export function choice(parent: D3Selection, nod node.height = 28; node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const s = Math.max(28, bounds.width ?? 0); + + const points = [ + { x: 0, y: s / 2 }, + { x: s / 2, y: 0 }, + { x: 0, y: -s / 2 }, + { x: -s / 2, y: 0 }, + ]; + return intersect.circle(bounds, points, point); }; node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts index 81c28b2f6..a01774f9f 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts @@ -201,9 +201,7 @@ export async function classBox(parent: D3Selection updateNodeBounds(node, rect); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + return intersect.rect(bounds, point); }; node.intersect = function (point) { return intersect.rect(node, point); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/crossedCircle.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/crossedCircle.ts index 2302fe1ae..8f268c4c5 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/crossedCircle.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/crossedCircle.ts @@ -59,8 +59,7 @@ export function crossedCircle(parent: D3Selection< updateNodeBounds(node, crossedCircle); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; + const radius = Math.max(30, bounds?.width ?? 0); return intersect.circle(bounds, radius, point); }; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts index 7f5409c39..ec6c1aab9 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts @@ -107,9 +107,23 @@ export async function curlyBraceLeft( updateNodeBounds(node, curlyBraceLeftShape); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const w = bounds.width; + const h = bounds.height; + const radius = Math.max(5, h * 0.1); + + const rectPoints = [ + { x: w / 2, y: -h / 2 - radius }, + { x: -w / 2, y: -h / 2 - radius }, + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: -w / 2 - radius, y: -radius }, + ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + { x: -w / 2, y: h / 2 + radius }, + { x: w / 2, y: h / 2 + radius }, + ]; + return intersect.polygon(bounds, rectPoints, point); }; node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts index 4b078769f..8d70f408b 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts @@ -107,9 +107,23 @@ export async function curlyBraceRight( updateNodeBounds(node, curlyBraceRightShape); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const w = bounds.width; + const h = bounds.height; + const radius = Math.max(5, h * 0.1); + + const rectPoints = [ + { x: -w / 2, y: -h / 2 - radius }, + { x: w / 2, y: -h / 2 - radius }, + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: w / 2 + radius, y: -radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: w / 2 + radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + { x: w / 2, y: h / 2 + radius }, + { x: -w / 2, y: h / 2 + radius }, + ]; + return intersect.polygon(bounds, rectPoints, point); }; node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts index 100e2f0a9..84e3d6648 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts @@ -36,6 +36,25 @@ function generateCirclePoints( return points; } +const getRectPoints = (w: number, h: number, radius: number) => [ + { x: w / 2, y: -h / 2 - radius }, + { x: -w / 2, y: -h / 2 - radius }, + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: -w / 2 - radius, y: -radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + { x: -w / 2, y: h / 2 + radius }, + { x: w / 2 - radius - radius / 2, y: h / 2 + radius }, + ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180), + { x: w / 2 - radius / 2, y: radius }, + ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90), + ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0), + { x: w / 2 - radius / 2, y: -radius }, + ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270), +]; + export async function curlyBraces( parent: D3Selection, node: Node @@ -67,24 +86,7 @@ export async function curlyBraces( ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270), ]; - const rectPoints = [ - { x: w / 2, y: -h / 2 - radius }, - { x: -w / 2, y: -h / 2 - radius }, - ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), - { x: -w / 2 - radius, y: -radius }, - ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), - ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), - { x: -w / 2 - radius, y: h / 2 }, - ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), - { x: -w / 2, y: h / 2 + radius }, - { x: w / 2 - radius - radius / 2, y: h / 2 + radius }, - ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180), - { x: w / 2 - radius / 2, y: radius }, - ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90), - ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0), - { x: w / 2 - radius / 2, y: -radius }, - ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270), - ]; + const rectPoints = getRectPoints(w, h, radius); // @ts-expect-error -- Passing a D3.Selection seems to work for some reason const rc = rough.svg(shapeSvg); @@ -126,9 +128,12 @@ export async function curlyBraces( updateNodeBounds(node, curlyBracesShape); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const w = bounds.width; + const h = bounds.height; + const radius = Math.max(5, h * 0.1); + + const rectPoints = getRectPoints(w, h, radius); + return intersect.polygon(bounds, rectPoints, point); }; node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curvedTrapezoid.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curvedTrapezoid.ts index e85e55a79..4f832ba4b 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curvedTrapezoid.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curvedTrapezoid.ts @@ -12,6 +12,15 @@ import rough from 'roughjs'; import type { D3Selection } from '../../../types.js'; import type { Bounds, Point } from '../../../types.js'; +const getTrapezoidPoints = (rw: number, tw: number, totalHeight: number, radius: number) => [ + { x: rw, y: 0 }, + { x: tw, y: 0 }, + { x: 0, y: totalHeight / 2 }, + { x: tw, y: totalHeight }, + { x: rw, y: totalHeight }, + ...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90), +]; + export async function curvedTrapezoid( parent: D3Selection, node: Node @@ -40,14 +49,7 @@ export async function curvedTrapezoid( const rw = totalWidth - radius; const tw = totalHeight / 4; - const points = [ - { x: rw, y: 0 }, - { x: tw, y: 0 }, - { x: 0, y: totalHeight / 2 }, - { x: tw, y: totalHeight }, - { x: rw, y: totalHeight }, - ...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90), - ]; + const points = getTrapezoidPoints(rw, tw, totalHeight, radius); const pathData = createPathFromPoints(points); const shapeNode = rc.path(pathData, options); @@ -68,9 +70,17 @@ export async function curvedTrapezoid( updateNodeBounds(node, polygon); node.calcIntersect = function (bounds: Bounds, point: Point) { - // TODO: Implement intersect for this shape - const radius = bounds.width / 2; - return intersect.circle(bounds, radius, point); + const w = bounds.width; + const h = bounds.height; + const radius = h / 2; + + const totalWidth = w, + totalHeight = h; + const rw = totalWidth - radius; + const tw = totalHeight / 4; + const points = getTrapezoidPoints(rw, tw, totalHeight, radius); + + return intersect.polygon(bounds, points, point); }; node.intersect = function (point) {