diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts index a426a32a5..72a725500 100644 --- a/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts @@ -86,8 +86,8 @@ export const draw = async function (text: string, id: string, _version: string, // performRender(data4Rendering); data4Layout.type = diag.type; - // data4Layout.layoutAlgorithm = 'dagre-wrapper'; - data4Layout.layoutAlgorithm = 'elk'; + data4Layout.layoutAlgorithm = 'dagre-wrapper'; + // data4Layout.layoutAlgorithm = 'elk'; data4Layout.skin = 'roughjs'; data4Layout.direction = DIR; data4Layout.nodeSpacing = conf.nodeSpacing || 50; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js index 0b1ecd572..68e022828 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js +++ b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js @@ -6,6 +6,8 @@ import { select } from 'd3'; import { getConfig } from '$root/diagram-api/diagramAPI.js'; import { evaluate } from '$root/diagrams/common/common.js'; import { getSubGraphTitleMargins } from '$root/utils/subGraphTitleMargins.js'; +import rough from 'roughjs'; +import { createRoundedRectPathD } from './shapes/roundedRectPath.ts'; const rect = (parent, node) => { log.info('Creating subgraph rect for ', node.id, node); @@ -136,11 +138,11 @@ const roundedWithTitle = (parent, node) => { const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id); // add the rect - const rect = shapeSvg.insert('rect', ':first-child'); + const outerRectG = shapeSvg.insert('g', ':first-child'); // Create the label and insert it after the rect const label = shapeSvg.insert('g').attr('class', 'cluster-label'); - const innerRect = shapeSvg.append('rect'); + let innerRect = shapeSvg.append('rect'); const text = label .node() @@ -159,26 +161,52 @@ const roundedWithTitle = (parent, node) => { const padding = 0 * node.padding; const halfPadding = padding / 2; - const width = node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width; + const width = + (node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding; if (node.width <= bbox.width + node.padding) { node.diff = (bbox.width + node.padding * 0 - node.width) / 2; } else { node.diff = -node.padding / 2; } - // center the rect around its coordinate - rect - .attr('class', 'outer') - .attr('x', node.x - width / 2 - halfPadding) - .attr('y', node.y - node.height / 2 - halfPadding) - .attr('width', width + padding) - .attr('height', node.height + padding); - innerRect - .attr('class', 'inner') - .attr('x', node.x - width / 2 - halfPadding) - .attr('y', node.y - node.height / 2 - halfPadding + bbox.height - 1) - .attr('width', width + padding) - .attr('height', node.height + padding - bbox.height - 3); + const x = node.x - width / 2 - halfPadding; + const y = node.y - node.height / 2 - halfPadding; + const innerY = node.y - node.height / 2 - halfPadding + bbox.height - 1; + const height = node.height + padding; + const innerHeight = node.height + padding - bbox.height - 3; + + // add the rect + let rect; + if (node.useRough) { + const rc = rough.svg(shapeSvg); + const roughOuterNode = + node.rx || node.ry + ? rc.path(createRoundedRectPathD(x, y, width, height, 10), { + roughness: 0.7, + }) + : rc.rectangle(x, y, width, height); + + rect = shapeSvg.insert(() => roughOuterNode); + const roughInnerNode = rc.rectangle(x, innerY, width, innerHeight); + + rect = shapeSvg.insert(() => roughOuterNode); + innerRect = shapeSvg.insert(() => roughInnerNode); + } else { + rect = outerRectG.insert('rect', ':first-child'); + // center the rect around its coordinate + rect + .attr('class', 'outer') + .attr('x', x) + .attr('y', y) + .attr('width', width) + .attr('height', node.height + padding); + innerRect + .attr('class', 'inner') + .attr('x', x) + .attr('y', innerY) + .attr('width', width) + .attr('height', innerHeight); + } const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig); // Center the label diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/rect.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/rect.ts index 95f474e46..412c1eb5b 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/rect.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/rect.ts @@ -2,8 +2,8 @@ import { log } from '$root/logger.js'; import { labelHelper, updateNodeBounds } from './util.js'; import intersect from '../intersect/index.js'; import type { Node } from '$root/rendering-util/types.d.ts'; +import { createRoundedRectPathD } from './roundedRectPath.js'; import rough from 'roughjs'; -import { select } from 'd3'; /** * @@ -56,61 +56,6 @@ function applyNodePropertyBorders( rect.attr('stroke-dasharray', strokeDashArray.join(' ')); } -function createRoundedRectPathD( - x: number, - y: number, - totalWidth: number, - totalHeight: number, - radius: number -) { - return [ - 'M', - x + radius, - y, // Move to the first point - 'H', - x + totalWidth - radius, // Draw horizontal line to the beginning of the right corner - 'A', - radius, - radius, - 0, - 0, - 1, - x + totalWidth, - y + radius, // Draw arc to the right top corner - 'V', - y + totalHeight - radius, // Draw vertical line down to the beginning of the right bottom corner - 'A', - radius, - radius, - 0, - 0, - 1, - x + totalWidth - radius, - y + totalHeight, // Draw arc to the right bottom corner - 'H', - x + radius, // Draw horizontal line to the beginning of the left bottom corner - 'A', - radius, - radius, - 0, - 0, - 1, - x, - y + totalHeight - radius, // Draw arc to the left bottom corner - 'V', - y + radius, // Draw vertical line up to the beginning of the left top corner - 'A', - radius, - radius, - 0, - 0, - 1, - x + radius, - y, // Draw arc to the left top corner - 'Z', // Close the path - ].join(' '); -} - export const rect = async (parent: SVGAElement, node: Node) => { const { shapeSvg, bbox, halfPadding } = await labelHelper( parent, diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/roundedRectPath.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/roundedRectPath.ts new file mode 100644 index 000000000..031b935fd --- /dev/null +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/roundedRectPath.ts @@ -0,0 +1,53 @@ +export const createRoundedRectPathD = ( + x: number, + y: number, + totalWidth: number, + totalHeight: number, + radius: number +) => + [ + 'M', + x + radius, + y, // Move to the first point + 'H', + x + totalWidth - radius, // Draw horizontal line to the beginning of the right corner + 'A', + radius, + radius, + 0, + 0, + 1, + x + totalWidth, + y + radius, // Draw arc to the right top corner + 'V', + y + totalHeight - radius, // Draw vertical line down to the beginning of the right bottom corner + 'A', + radius, + radius, + 0, + 0, + 1, + x + totalWidth - radius, + y + totalHeight, // Draw arc to the right bottom corner + 'H', + x + radius, // Draw horizontal line to the beginning of the left bottom corner + 'A', + radius, + radius, + 0, + 0, + 1, + x, + y + totalHeight - radius, // Draw arc to the left bottom corner + 'V', + y + radius, // Draw vertical line up to the beginning of the left top corner + 'A', + radius, + radius, + 0, + 0, + 1, + x + radius, + y, // Draw arc to the left top corner + 'Z', // Close the path + ].join(' ');