diff --git a/cypress/integration/rendering/newShapes.spec.ts b/cypress/integration/rendering/newShapes.spec.ts index e993b010b..6bbb648ca 100644 --- a/cypress/integration/rendering/newShapes.spec.ts +++ b/cypress/integration/rendering/newShapes.spec.ts @@ -10,7 +10,7 @@ const newShapesSet1 = [ 'flippedTriangle', 'hourglass', ] as const; -const newShapesSet2 = ['taggedRect', 'multiRect'] as const; +const newShapesSet2 = ['taggedRect', 'multiRect', 'lightningBolt', 'filledCircle'] as const; // Aggregate all shape sets into a single array const newShapesSets = [newShapesSet1, newShapesSet2] as const; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js index 80a082930..52604cfad 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js +++ b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js @@ -43,6 +43,7 @@ import { multiRect } from './shapes/multiRect.js'; import { linedCylinder } from './shapes/linedCylinder.js'; import { waveEdgedRectangle } from './shapes/waveEdgedRectangle.js'; import { lightningBolt } from './shapes/lightningBolt.js'; +import { filledCircle } from './shapes/filledCircle.js'; const shapes = { state, @@ -89,6 +90,7 @@ const shapes = { linedCylinder, waveEdgedRectangle, lightningBolt, + filledCircle, }; const nodeElems = new Map(); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts new file mode 100644 index 000000000..a7fdd9c23 --- /dev/null +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts @@ -0,0 +1,52 @@ +import { log } from '$root/logger.js'; +import { labelHelper, getNodeClasses, updateNodeBounds } from './util.js'; +import type { Node } from '$root/rendering-util/types.d.ts'; +import { + styles2String, + userNodeOverrides, +} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; +import rough from 'roughjs'; +import intersect from '../intersect/index.js'; + +export const filledCircle = async (parent: SVGAElement, node: Node) => { + const { labelStyles, nodeStyles } = styles2String(node); + node.label = ''; + node.labelStyle = labelStyles; + const { shapeSvg } = await labelHelper(parent, node, getNodeClasses(node)); + const radius = 4; + const { cssStyles } = node; + + // @ts-ignore - rough is not typed + const rc = rough.svg(shapeSvg); + const options = userNodeOverrides(node, {}); + + if (node.look !== 'handDrawn') { + options.roughness = 0; + options.fillStyle = 'solid'; + } + + const circleNode = rc.circle(0, 0, radius * 2, options); + + const filledCircle = shapeSvg.insert('g', ':first-child'); + filledCircle.insert(() => circleNode, ':first-child'); + + filledCircle.attr('class', 'basic label-container'); + + if (cssStyles) { + filledCircle.attr('style', cssStyles); + } + + if (nodeStyles) { + filledCircle.attr('style', nodeStyles); + } + + updateNodeBounds(node, filledCircle); + + node.intersect = function (point) { + log.info('filledCircle intersect', node, { radius, point }); + const pos = intersect.circle(node, radius, point); + return pos; + }; + + return shapeSvg; +}; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/slopedRect.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/slopedRect.ts index b27bb7144..bf9a0ad2b 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/slopedRect.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/slopedRect.ts @@ -7,28 +7,14 @@ import { } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; import rough from 'roughjs'; -function createSlopedRectPathD(x: number, y: number, totalWidth: number, totalHeight: number) { - const rw = totalWidth; - const rh = totalHeight; - - const points = [ - { x, y }, - { x: x + rw, y: y - rh * 0.6 }, - { x: x + rw, y: y + rh }, - { x, y: y + rh }, - ]; - - const rectPath = createPathFromPoints(points); - - return rectPath; -} - export const slopedRect = async (parent: SVGAElement, node: Node) => { const { labelStyles, nodeStyles } = styles2String(node); node.labelStyle = labelStyles; - const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node)); - const w = bbox.width + node.padding; - const h = bbox.height + node.padding; + const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node)); + const w = Math.max(bbox.width + (node.padding ?? 0) * 2, node?.width ?? 0); + const h = Math.max(bbox.height + (node.padding ?? 0) * 2, node?.height ?? 0); + const x = -w / 2; + const y = -h / 2; const { cssStyles } = node; @@ -41,7 +27,14 @@ export const slopedRect = async (parent: SVGAElement, node: Node) => { options.fillStyle = 'solid'; } - const pathData = createSlopedRectPathD(0, 0, w, h); + const points = [ + { x, y }, + { x, y: y + h }, + { x: x + w, y: y + h }, + { x: x + w, y: y - h / 2 }, + ]; + + const pathData = createPathFromPoints(points); const shapeNode = rc.path(pathData, options); const polygon = shapeSvg.insert(() => shapeNode, ':first-child'); @@ -55,12 +48,13 @@ export const slopedRect = async (parent: SVGAElement, node: Node) => { polygon.attr('style', nodeStyles); } - polygon.attr('transform', `translate(${-w / 2}, ${-h / 2})`); + polygon.attr('transform', `translate(0, ${h / 4})`); + label.attr('transform', `translate(${-w / 2 + (node.padding ?? 0)}, ${-(node.padding ?? 0)})`); updateNodeBounds(node, polygon); node.intersect = function (point) { - const pos = intersect.polygon(node, point); + const pos = intersect.polygon(node, points, point); return pos; };