Compare commits

..

22 Commits

Author SHA1 Message Date
omkarht
7eb14f09bf Merge branch 'refactor/shape-rendering-simplification' of https://github.com/mermaid-js/mermaid into refactor/shape-rendering-simplification 2025-12-18 16:38:08 +05:30
omkarht
b7c66a220a chore: add changeset to restore original hexagon and roundedRect implementations
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-12-18 16:37:55 +05:30
omkarht
87e2d819bf Merge branch 'develop' into refactor/shape-rendering-simplification 2025-12-18 16:36:42 +05:30
omkarht
93aa657578 chore: add changeset for reverting hexagon and roundedRect implementations
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
2025-12-18 16:36:10 +05:30
Shubham P
7b167cf331 Merge pull request #7242 from mermaid-js/renovate/patch-dompurify
fix(deps): update dependency dompurify to ^3.3.1
2025-12-15 11:41:32 +00:00
Shubham P
d435ac6fe1 Merge pull request #7228 from mermaid-js/renovate/peter-evans-create-pull-request-digest
chore(deps): update peter-evans/create-pull-request digest to 0979079
2025-12-15 06:47:12 +00:00
renovate[bot]
ed96d067fc fix(deps): update dependency dompurify to ^3.3.1 2025-12-15 00:42:27 +00:00
renovate[bot]
09c60be450 chore(deps): update peter-evans/create-pull-request digest to 0979079 2025-12-10 10:49:20 +00:00
Sidharth Vinod
39d070fdea Merge pull request #7215 from mermaid-js/update-timings
Update E2E Timings
2025-12-04 13:42:51 +05:30
github-actions[bot]
4f6f627e75 chore: update E2E timings 2025-12-04 04:17:52 +00:00
Sidharth Vinod
53570ee815 Merge pull request #7204 from leandroebner/patch-1
Add HackMD integration to community integrations list
2025-12-03 09:58:48 +00:00
Shubham P
a3a5040d79 Merge pull request #7206 from mermaid-js/renovate/patch-all-patch
fix(deps): update all patch dependencies (patch)
2025-12-02 08:57:58 +00:00
renovate[bot]
7ff9bf1a50 fix(deps): update all patch dependencies 2025-12-02 07:42:41 +00:00
Shubham P
ffd38716d0 Merge pull request #7208 from mermaid-js/renovate/npm-express-vulnerability
chore(deps): update dependency express to v5.2.0 [security]
2025-12-02 07:28:21 +00:00
Shubham P
4313f233d2 Merge pull request #7205 from mermaid-js/renovate/patch-eslint
chore(deps): update dependency @cspell/eslint-plugin to ^9.3.2
2025-12-02 07:27:24 +00:00
renovate[bot]
56564f3807 chore(deps): update dependency express to v5.2.0 [security] 2025-12-01 20:55:04 +00:00
renovate[bot]
7e1a1de5e9 chore(deps): update dependency @cspell/eslint-plugin to ^9.3.2 2025-12-01 02:27:03 +00:00
autofix-ci[bot]
b4b90417cf [autofix.ci] apply automated fixes 2025-11-30 19:33:42 +00:00
Leandro Ebner
6bf2b2108c Add HackMD integration to community integrations list
Works natively, see hackmd docs.
2025-11-30 20:22:15 +01:00
Shubham P
614129ca31 Merge pull request #7197 from mermaid-js/fix/5496-gantt-tickinterval-app-crash
5496 : fixed UI crash from excessive tick generation with invalid dates/intervals
2025-11-27 17:09:07 +00:00
omkarht
43b7db9d6a Merge branch 'develop' into refactor/shape-rendering-simplification 2025-11-07 14:02:10 +05:30
omkarht
df46b617d4 revert: restore original hexagon and roundedRect implementations 2025-11-07 13:58:10 +05:30
12 changed files with 393 additions and 752 deletions

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
revert: restore original hexagon and roundedRect implementations

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
chore: restore original hexagon and roundedRect implementations

View File

@@ -58,7 +58,7 @@ jobs:
echo "EOF" >> $GITHUB_OUTPUT
- name: Commit and create pull request
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412
uses: peter-evans/create-pull-request@0979079bc20c05bbbb590a56c21c4e2b1d1f1bbe
with:
add-paths: |
cypress/timings.json

View File

@@ -2,35 +2,35 @@
"durations": [
{
"spec": "cypress/integration/other/configuration.spec.js",
"duration": 6099
"duration": 5944
},
{
"spec": "cypress/integration/other/external-diagrams.spec.js",
"duration": 2236
"duration": 2180
},
{
"spec": "cypress/integration/other/ghsa.spec.js",
"duration": 3405
"duration": 3282
},
{
"spec": "cypress/integration/other/iife.spec.js",
"duration": 2176
"duration": 2137
},
{
"spec": "cypress/integration/other/interaction.spec.js",
"duration": 12300
"duration": 11926
},
{
"spec": "cypress/integration/other/rerender.spec.js",
"duration": 2089
"duration": 2021
},
{
"spec": "cypress/integration/other/xss.spec.js",
"duration": 32033
"duration": 31377
},
{
"spec": "cypress/integration/rendering/appli.spec.js",
"duration": 3672
"duration": 3442
},
{
"spec": "cypress/integration/rendering/architecture.spec.ts",
@@ -38,191 +38,191 @@
},
{
"spec": "cypress/integration/rendering/block.spec.js",
"duration": 18135
"duration": 18390
},
{
"spec": "cypress/integration/rendering/c4.spec.js",
"duration": 5661
"duration": 6468
},
{
"spec": "cypress/integration/rendering/classDiagram-elk-v3.spec.js",
"duration": 41456
"duration": 41282
},
{
"spec": "cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js",
"duration": 38910
"duration": 39226
},
{
"spec": "cypress/integration/rendering/classDiagram-v2.spec.js",
"duration": 24120
"duration": 25028
},
{
"spec": "cypress/integration/rendering/classDiagram-v3.spec.js",
"duration": 38454
"duration": 38458
},
{
"spec": "cypress/integration/rendering/classDiagram.spec.js",
"duration": 17099
"duration": 17305
},
{
"spec": "cypress/integration/rendering/conf-and-directives.spec.js",
"duration": 9844
"duration": 9762
},
{
"spec": "cypress/integration/rendering/current.spec.js",
"duration": 2951
"duration": 2923
},
{
"spec": "cypress/integration/rendering/erDiagram-unified.spec.js",
"duration": 90081
"duration": 89135
},
{
"spec": "cypress/integration/rendering/erDiagram.spec.js",
"duration": 19496
"duration": 18976
},
{
"spec": "cypress/integration/rendering/errorDiagram.spec.js",
"duration": 3829
"duration": 3643
},
{
"spec": "cypress/integration/rendering/flowchart-elk.spec.js",
"duration": 42517
"duration": 43103
},
{
"spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js",
"duration": 31541
"duration": 31637
},
{
"spec": "cypress/integration/rendering/flowchart-icon.spec.js",
"duration": 7749
"duration": 7630
},
{
"spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts",
"duration": 25230
"duration": 25642
},
{
"spec": "cypress/integration/rendering/flowchart-v2.spec.js",
"duration": 49359
"duration": 50365
},
{
"spec": "cypress/integration/rendering/flowchart.spec.js",
"duration": 33028
"duration": 32790
},
{
"spec": "cypress/integration/rendering/gantt.spec.js",
"duration": 22271
"duration": 23065
},
{
"spec": "cypress/integration/rendering/gitGraph.spec.js",
"duration": 51837
"duration": 52238
},
{
"spec": "cypress/integration/rendering/iconShape.spec.ts",
"duration": 285060
"duration": 289380
},
{
"spec": "cypress/integration/rendering/imageShape.spec.ts",
"duration": 59517
"duration": 59265
},
{
"spec": "cypress/integration/rendering/info.spec.ts",
"duration": 3501
"duration": 3269
},
{
"spec": "cypress/integration/rendering/journey.spec.js",
"duration": 7405
"duration": 7470
},
{
"spec": "cypress/integration/rendering/kanban.spec.ts",
"duration": 7975
"duration": 7980
},
{
"spec": "cypress/integration/rendering/katex.spec.js",
"duration": 4312
"duration": 3896
},
{
"spec": "cypress/integration/rendering/marker_unique_id.spec.js",
"duration": 2630
"duration": 2640
},
{
"spec": "cypress/integration/rendering/mindmap-tidy-tree.spec.js",
"duration": 4541
"duration": 4327
},
{
"spec": "cypress/integration/rendering/mindmap.spec.ts",
"duration": 12134
"duration": 12588
},
{
"spec": "cypress/integration/rendering/newShapes.spec.ts",
"duration": 151160
"duration": 153490
},
{
"spec": "cypress/integration/rendering/oldShapes.spec.ts",
"duration": 118044
"duration": 117833
},
{
"spec": "cypress/integration/rendering/packet.spec.ts",
"duration": 5166
"duration": 4975
},
{
"spec": "cypress/integration/rendering/pie.spec.ts",
"duration": 7074
"duration": 6682
},
{
"spec": "cypress/integration/rendering/quadrantChart.spec.js",
"duration": 9518
"duration": 8972
},
{
"spec": "cypress/integration/rendering/radar.spec.js",
"duration": 5846
"duration": 5631
},
{
"spec": "cypress/integration/rendering/requirement.spec.js",
"duration": 3089
"duration": 2776
},
{
"spec": "cypress/integration/rendering/requirementDiagram-unified.spec.js",
"duration": 55361
"duration": 54373
},
{
"spec": "cypress/integration/rendering/sankey.spec.ts",
"duration": 7236
"duration": 7203
},
{
"spec": "cypress/integration/rendering/sequencediagram-v2.spec.js",
"duration": 26057
"duration": 31707
},
{
"spec": "cypress/integration/rendering/sequencediagram.spec.js",
"duration": 48401
"duration": 48327
},
{
"spec": "cypress/integration/rendering/stateDiagram-v2.spec.js",
"duration": 30364
"duration": 30728
},
{
"spec": "cypress/integration/rendering/stateDiagram.spec.js",
"duration": 16862
"duration": 16881
},
{
"spec": "cypress/integration/rendering/theme.spec.js",
"duration": 30553
"duration": 30715
},
{
"spec": "cypress/integration/rendering/timeline.spec.ts",
"duration": 8962
"duration": 8586
},
{
"spec": "cypress/integration/rendering/treemap.spec.ts",
"duration": 12486
"duration": 15184
},
{
"spec": "cypress/integration/rendering/xyChart.spec.js",
"duration": 21718
"duration": 21282
},
{
"spec": "cypress/integration/rendering/zenuml.spec.js",
"duration": 3882
"duration": 3576
}
]
}

View File

@@ -59,6 +59,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) ✅
- [GNU Octave](https://octave.org/) ✅
- [octave_mermaid_js](https://github.com/CNOCTAVE/octave_mermaid_js) ✅
- [HackMD](https://hackmd.io/c/tutorials/%2F%40docs%2Fflowchart-en#Create-more-complex-flowcharts) ✅
- [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid)
- [MonsterWriter](https://www.monsterwriter.com/) ✅
- [Joplin](https://joplinapp.org) ✅

View File

@@ -65,14 +65,14 @@
"devDependencies": {
"@applitools/eyes-cypress": "^3.56.5",
"@argos-ci/cypress": "^6.2.2",
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.7",
"@cspell/eslint-plugin": "^9.3.0",
"@changesets/changelog-github": "^0.5.2",
"@changesets/cli": "^2.29.8",
"@cspell/eslint-plugin": "^9.3.2",
"@cypress/code-coverage": "^3.14.7",
"@eslint/js": "^9.26.0",
"@rollup/plugin-typescript": "^12.1.4",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.5",
"@types/express": "^5.0.6",
"@types/js-yaml": "^4.0.9",
"@types/jsdom": "^21.1.7",
"@types/lodash": "^4.17.21",
@@ -105,7 +105,7 @@
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-unicorn": "^62.0.0",
"express": "^5.1.0",
"express": "^5.2.1",
"globals": "^16.4.0",
"globby": "^14.1.0",
"husky": "^9.1.7",

View File

@@ -78,7 +78,7 @@
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.13",
"dayjs": "^1.11.19",
"dompurify": "^3.3.0",
"dompurify": "^3.3.1",
"katex": "^0.16.25",
"khroma": "^2.1.0",
"lodash-es": "^4.17.21",
@@ -123,7 +123,7 @@
"rimraf": "^6.0.1",
"start-server-and-test": "^2.1.3",
"type-fest": "^4.41.0",
"typedoc": "^0.28.14",
"typedoc": "^0.28.15",
"typedoc-plugin-markdown": "^4.8.1",
"typescript": "~5.7.3",
"unist-util-flatmap": "^1.0.0",

View File

@@ -54,6 +54,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) ✅
- [GNU Octave](https://octave.org/) ✅
- [octave_mermaid_js](https://github.com/CNOCTAVE/octave_mermaid_js) ✅
- [HackMD](https://hackmd.io/c/tutorials/%2F%40docs%2Fflowchart-en#Create-more-complex-flowcharts) ✅
- [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid)
- [MonsterWriter](https://www.monsterwriter.com/) ✅
- [Joplin](https://joplinapp.org) ✅

View File

@@ -21,7 +21,7 @@
"font-awesome": "^4.7.0",
"jiti": "^2.4.2",
"mermaid": "workspace:^",
"vue": "^3.5.24"
"vue": "^3.5.25"
},
"devDependencies": {
"@iconify-json/carbon": "^1.2.14",

View File

@@ -1,8 +1,9 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
export const createHexagonPathD = (
@@ -28,50 +29,42 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const h = bbox.height + (node.padding ?? 0);
const w = bbox.width + (node.padding ?? 0) * 2.5;
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
let halfWidth = w / 2;
const m = halfWidth / 6; // Margin for label
halfWidth = halfWidth + m; // Adjusted half width for hexagon
const halfHeight = h / 2;
const fixedLength = halfHeight / 2;
const deducedWidth = halfWidth - fixedLength;
const f = 4;
const h = bbox.height + node.padding;
const m = h / f;
const w = bbox.width + 2 * m + node.padding;
const points = [
{ x: -deducedWidth, y: -halfHeight },
{ x: 0, y: -halfHeight },
{ x: deducedWidth, y: -halfHeight },
{ x: halfWidth, y: 0 },
{ x: deducedWidth, y: halfHeight },
{ x: 0, y: halfHeight },
{ x: -deducedWidth, y: halfHeight },
{ x: -halfWidth, y: 0 },
{ x: m, y: 0 },
{ x: w - m, y: 0 },
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: m, y: -h },
{ x: 0, y: -h / 2 },
];
const pathData = createPathFromPoints(points);
const shapeNode = rc.path(pathData, options);
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
const { cssStyles } = node;
const polygon = shapeSvg.insert(() => shapeNode, ':first-child');
polygon.attr('class', 'basic label-container');
if (node.look === 'handDrawn') {
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createHexagonPathD(0, 0, w, h, m);
const roughNode = rc.path(pathData, options);
if (cssStyles && node.look !== 'handDrawn') {
polygon.selectChildren('path').attr('style', cssStyles);
polygon = shapeSvg
.insert(() => roughNode, ':first-child')
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
if (cssStyles) {
polygon.attr('style', cssStyles);
}
} else {
polygon = insertPolygonShape(shapeSvg, w, h, points);
}
if (nodeStyles && node.look !== 'handDrawn') {
polygon.selectChildren('path').attr('style', nodeStyles);
if (nodeStyles) {
polygon.attr('style', nodeStyles);
}
node.width = w;

View File

@@ -1,161 +1,18 @@
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { Node, RectOptions } from '../../types.js';
import type { D3Selection } from '../../../types.js';
/**
* Generates evenly spaced points along an elliptical arc connecting two points.
*
* @param x1 - x-coordinate of the start point of the arc
* @param y1 - y-coordinate of the start point of the arc
* @param x2 - x-coordinate of the end point of the arc
* @param y2 - y-coordinate of the end point of the arc
* @param rx - horizontal radius of the ellipse
* @param ry - vertical radius of the ellipse
* @param clockwise - direction of the arc; true for clockwise, false for counterclockwise
* @returns Array of points `{ x, y }` along the elliptical arc
*
* @throws Error if the given radii are too small to draw an arc between the points
*/
export function generateArcPoints(
x1: number,
y1: number,
x2: number,
y2: number,
rx: number,
ry: number,
clockwise: boolean
) {
const numPoints = 20;
// Calculate midpoint
const midX = (x1 + x2) / 2;
const midY = (y1 + y2) / 2;
// Calculate the angle of the line connecting the points
const angle = Math.atan2(y2 - y1, x2 - x1);
// Calculate transformed coordinates for the ellipse
const dx = (x2 - x1) / 2;
const dy = (y2 - y1) / 2;
// Scale to unit circle
const transformedX = dx / rx;
const transformedY = dy / ry;
// Calculate the distance between points on the unit circle
const distance = Math.sqrt(transformedX ** 2 + transformedY ** 2);
// Check if the ellipse can be drawn with the given radii
if (distance > 1) {
throw new Error('The given radii are too small to create an arc between the points.');
}
// Calculate the distance from the midpoint to the center of the ellipse
const scaledCenterDistance = Math.sqrt(1 - distance ** 2);
// Calculate the center of the ellipse
const centerX = midX + scaledCenterDistance * ry * Math.sin(angle) * (clockwise ? -1 : 1);
const centerY = midY - scaledCenterDistance * rx * Math.cos(angle) * (clockwise ? -1 : 1);
// Calculate the start and end angles on the ellipse
const startAngle = Math.atan2((y1 - centerY) / ry, (x1 - centerX) / rx);
const endAngle = Math.atan2((y2 - centerY) / ry, (x2 - centerX) / rx);
// Adjust angles for clockwise/counterclockwise
let angleRange = endAngle - startAngle;
if (clockwise && angleRange < 0) {
angleRange += 2 * Math.PI;
}
if (!clockwise && angleRange > 0) {
angleRange -= 2 * Math.PI;
}
// Generate points
const points = [];
for (let i = 0; i < numPoints; i++) {
const t = i / (numPoints - 1);
const angle = startAngle + t * angleRange;
const x = centerX + rx * Math.cos(angle);
const y = centerY + ry * Math.sin(angle);
points.push({ x, y });
}
return points;
}
import { drawRect } from './drawRect.js';
export async function roundedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const options = {
rx: 5,
ry: 5,
classes: '',
labelPaddingX: (node?.padding || 0) * 1,
labelPaddingY: (node?.padding || 0) * 1,
} as RectOptions;
const labelPaddingX = node?.padding ?? 0;
const labelPaddingY = node?.padding ?? 0;
const w = (node?.width ? node?.width : bbox.width) + labelPaddingX * 2;
const h = (node?.height ? node?.height : bbox.height) + labelPaddingY * 2;
const radius = node.radius || 5;
const taper = node.taper || 5; // Taper width for the rounded corners
const { cssStyles } = node;
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.stroke) {
options.stroke = node.stroke;
}
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
const points = [
// Top edge (left to right)
{ x: -w / 2 + taper, y: -h / 2 }, // Top-left corner start (1)
{ x: w / 2 - taper, y: -h / 2 }, // Top-right corner start (2)
...generateArcPoints(w / 2 - taper, -h / 2, w / 2, -h / 2 + taper, radius, radius, true), // Top-left arc (2 to 3)
// Right edge (top to bottom)
{ x: w / 2, y: -h / 2 + taper }, // Top-right taper point (3)
{ x: w / 2, y: h / 2 - taper }, // Bottom-right taper point (4)
...generateArcPoints(w / 2, h / 2 - taper, w / 2 - taper, h / 2, radius, radius, true), // Top-left arc (4 to 5)
// Bottom edge (right to left)
{ x: w / 2 - taper, y: h / 2 }, // Bottom-right corner start (5)
{ x: -w / 2 + taper, y: h / 2 }, // Bottom-left corner start (6)
...generateArcPoints(-w / 2 + taper, h / 2, -w / 2, h / 2 - taper, radius, radius, true), // Top-left arc (4 to 5)
// Left edge (bottom to top)
{ x: -w / 2, y: h / 2 - taper }, // Bottom-left taper point (7)
{ x: -w / 2, y: -h / 2 + taper }, // Top-left taper point (8)
...generateArcPoints(-w / 2, -h / 2 + taper, -w / 2 + taper, -h / 2, radius, radius, true), // Top-left arc (4 to 5)
];
const pathData = createPathFromPoints(points);
const shapeNode = rc.path(pathData, options);
const polygon = shapeSvg.insert(() => shapeNode, ':first-child');
polygon.attr('class', 'basic label-container outer-path');
if (cssStyles && node.look !== 'handDrawn') {
polygon.selectChildren('path').attr('style', cssStyles);
}
if (nodeStyles && node.look !== 'handDrawn') {
polygon.selectChildren('path').attr('style', nodeStyles);
}
updateNodeBounds(node, polygon);
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;
};
return shapeSvg;
return drawRect(parent, node, options);
}

773
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff