) {
+ // get HTML Element from jquery element
+ const svgElement = $p[0];
+ expect(svgElement.nodeName).equal('svg');
+
+ const sectionRoots = svgElement.getElementsByClassName('mindmap-node section-root');
+ // mindmap should have at least one root section
+ expect(sectionRoots).to.have.lengthOf.at.least(1);
+}
+
+describe('Mindmaps', () => {
+ it('Only a root', () => {
+ imgSnapshotTest(
+ `mindmap
+root
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('a root with a shape', () => {
+ imgSnapshotTest(
+ `mindmap
+root[root]
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('a root with wrapping text and a shape', () => {
+ imgSnapshotTest(
+ `mindmap
+root[A root with a long text that wraps to keep the node size in check]
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('a root with an icon', () => {
+ imgSnapshotTest(
+ `mindmap
+root[root]
+::icon(mdi mdi-fire)
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('Blang and cloud shape', () => {
+ imgSnapshotTest(
+ `mindmap
+root))bang((
+ ::icon(mdi mdi-fire)
+ a))Another bang((
+ ::icon(mdi mdi-fire)
+ a)A cloud(
+ ::icon(mdi mdi-fire)
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('Blang and cloud shape with icons', () => {
+ imgSnapshotTest(
+ `mindmap
+root))bang((
+
+ a))Another bang((
+ a)A cloud(
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('braches', () => {
+ imgSnapshotTest(
+ `mindmap
+root
+ child1
+ grandchild 1
+ grandchild 2
+ child2
+ grandchild 3
+ grandchild 4
+ child3
+ grandchild 5
+ grandchild 6
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
+ it('braches with shapes and labels', () => {
+ imgSnapshotTest(
+ `mindmap
+root
+ child1((Circle))
+ grandchild 1
+ grandchild 2
+ child2(Round rectangle)
+ grandchild 3
+ grandchild 4
+ child3[Square]
+ grandchild 5
+ ::icon(mdi mdi-fire)
+ gc6((grand
child 6))
+ ::icon(mdi mdi-fire)
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+ it('text shouhld wrap with icon', () => {
+ imgSnapshotTest(
+ `mindmap
+root
+ Child3(A node with an icon and with a long text that wraps to keep the node size in check)
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+ it('square shape', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ root[
+ The root
+ ]
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ it('rounded rect shape', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ root((
+ The root
+ ))
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ it('circle shape', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ root(
+ The root
+ )
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ it('default shape', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ The root
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ it('adding children', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ The root
+ child1
+ child2
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ it('adding grand children', () => {
+ imgSnapshotTest(
+ `
+mindmap
+ The root
+ child1
+ child2
+ child3
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ cy.get('svg');
+ });
+ /* The end */
+});
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 0000000000..e3351cebeb
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "target": "es2020",
+ "lib": ["es2020", "dom"],
+ "types": ["cypress", "node"]
+ },
+ "include": ["**/*.ts"]
+}
diff --git a/demos/index.html b/demos/index.html
index a65681ddf1..da27cdcff3 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -48,6 +48,9 @@
+
+
+
diff --git a/demos/mindmap.html b/demos/mindmap.html
new file mode 100644
index 0000000000..a5b554a1a0
--- /dev/null
+++ b/demos/mindmap.html
@@ -0,0 +1,108 @@
+
+
+
+
+
+ Mindmap Mermaid Quick Test Page
+
+
+
+
+
+ Mindmap diagram demo
+
+ mindmap
+ root
+ child1((Circle))
+ grandchild 1
+ grandchild 2
+ child2(Round rectangle)
+ grandchild 3
+ grandchild 4
+ child3[Square]
+ grandchild 5
+ ::icon(mdi mdi-fire)
+ gc6((grand
child 6))
+ ::icon(mdi mdi-fire)
+ gc7((grand
grand
child 8))
+
+
+ Mindmap with root wrapping text and a shape
+
+ mindmap
+ root[A root with a long text that wraps to keep the node size in check]
+
+
+
+
+
diff --git a/package.json b/package.json
index 7bd6488777..70fac0ea97 100644
--- a/package.json
+++ b/package.json
@@ -105,9 +105,6 @@
"vitepress-plugin-search": "^1.0.4-alpha.15",
"vitest": "^0.25.1"
},
- "resolutions": {
- "d3": "^7.6.1"
- },
"sideEffects": [
"**/*.css",
"**/*.scss"
diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json
index 842e9ba9ab..f79ffe6f3b 100644
--- a/packages/mermaid/package.json
+++ b/packages/mermaid/package.json
@@ -54,8 +54,7 @@
"dependencies": {
"@braintree/sanitize-url": "^6.0.0",
"d3": "^7.0.0",
- "dagre": "^0.8.5",
- "dagre-d3": "^0.6.4",
+ "dagre-d3-es": "7.0.2",
"dompurify": "2.4.1",
"fast-clone": "^1.5.13",
"graphlib": "^2.1.8",
@@ -98,9 +97,6 @@
"typescript": "^4.8.4",
"unist-util-flatmap": "^1.0.0"
},
- "resolutions": {
- "d3": "^7.0.0"
- },
"files": [
"dist",
"README.md"
diff --git a/packages/mermaid/src/dagre-wrapper/index.js b/packages/mermaid/src/dagre-wrapper/index.js
index 72652ff8c5..43fe311b39 100644
--- a/packages/mermaid/src/dagre-wrapper/index.js
+++ b/packages/mermaid/src/dagre-wrapper/index.js
@@ -1,4 +1,4 @@
-import dagre from 'dagre';
+import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import graphlib from 'graphlib';
import insertMarkers from './markers';
import { updateNodeBounds } from './shapes/util';
@@ -95,7 +95,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('### Layout ###');
log.info('#############################################');
log.info(graph);
- dagre.layout(graph);
+ dagreLayout(graph);
log.info('Graph after layout:', graphlib.json.write(graph));
// Move the nodes to the correct place
let diff = 0;
diff --git a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
index 8155bbf700..a09e17f023 100644
--- a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
+++ b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
@@ -1,5 +1,4 @@
import graphlib from 'graphlib';
-import dagre from 'dagre';
import {
validate,
adjustClustersAndEdges,
diff --git a/packages/mermaid/src/diagrams/class/classRenderer.js b/packages/mermaid/src/diagrams/class/classRenderer.js
index 23b5861928..357647427e 100644
--- a/packages/mermaid/src/diagrams/class/classRenderer.js
+++ b/packages/mermaid/src/diagrams/class/classRenderer.js
@@ -1,5 +1,5 @@
import { select } from 'd3';
-import dagre from 'dagre';
+import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import graphlib from 'graphlib';
import { log } from '../../logger';
import svgDraw from './svgDraw';
@@ -238,7 +238,7 @@ export const draw = function (text, id, _version, diagObj) {
}
});
- dagre.layout(g);
+ dagreLayout(g);
g.nodes().forEach(function (v) {
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js
index 323bb4607c..57aa737abb 100644
--- a/packages/mermaid/src/diagrams/er/erRenderer.js
+++ b/packages/mermaid/src/diagrams/er/erRenderer.js
@@ -1,6 +1,6 @@
import graphlib from 'graphlib';
import { line, curveBasis, select } from 'd3';
-import dagre from 'dagre';
+import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import { getConfig } from '../../config';
import { log } from '../../logger';
import erMarkers from './erMarkers';
@@ -637,7 +637,7 @@ export const draw = function (text, id, _version, diagObj) {
// Add all the relationships to the graph
const relationships = addRelationships(diagObj.db.getRelationships(), g);
- dagre.layout(g); // Node and edge positions will be updated
+ dagreLayout(g); // Node and edge positions will be updated
// Adjust the positions of the entities so that they adhere to the layout
adjustEntities(svg, g);
diff --git a/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js b/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js
index b66bfe730f..d02d484c4f 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js
@@ -1,4 +1,5 @@
-import dagreD3 from 'dagre-d3';
+import { intersectPolygon } from 'dagre-d3-es/src/dagre-js/intersect/intersect-polygon.js';
+import { intersectRect } from 'dagre-d3-es/src/dagre-js/intersect/intersect-rect.js';
/**
* @param parent
@@ -17,7 +18,7 @@ function question(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, s, s, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -42,7 +43,7 @@ function hexagon(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -64,7 +65,7 @@ function rect_left_inv_arrow(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -85,7 +86,7 @@ function lean_right(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -106,7 +107,7 @@ function lean_left(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -127,7 +128,7 @@ function trapezoid(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -148,7 +149,7 @@ function inv_trapezoid(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -170,7 +171,7 @@ function rect_right_inv_arrow(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -194,7 +195,7 @@ function stadium(parent, bbox, node) {
.attr('height', h);
node.intersect = function (point) {
- return dagreD3.intersect.rect(node, point);
+ return intersectRect(node, point);
};
return shapeSvg;
}
@@ -221,7 +222,7 @@ function subroutine(parent, bbox, node) {
];
const shapeSvg = insertPolygonShape(parent, w, h, points);
node.intersect = function (point) {
- return dagreD3.intersect.polygon(node, points, point);
+ return intersectPolygon(node, points, point);
};
return shapeSvg;
}
@@ -270,7 +271,7 @@ function cylinder(parent, bbox, node) {
.attr('transform', 'translate(' + -w / 2 + ',' + -(h / 2 + ry) + ')');
node.intersect = function (point) {
- const pos = dagreD3.intersect.rect(node, point);
+ const pos = intersectRect(node, point);
const x = pos.x - node.x;
if (
diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
index 6b7c4c1bfe..86eb525040 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
@@ -5,7 +5,7 @@ import flowDb from './flowDb';
import { getConfig } from '../../config';
import { render } from '../../dagre-wrapper/index.js';
-import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
+import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray } from '../../utils';
diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
index c403b7fe32..0fcbce5451 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
@@ -1,8 +1,9 @@
import graphlib from 'graphlib';
import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../config';
-import dagreD3 from 'dagre-d3';
-import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
+import { render as Render } from 'dagre-d3-es';
+import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
+import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray } from '../../utils';
@@ -370,7 +371,6 @@ export const draw = function (text, id, _version, diagObj) {
addEdges(edges, g, diagObj);
// Create the renderer
- const Render = dagreD3.render;
const render = new Render();
// Add custom shapes
@@ -390,7 +390,7 @@ export const draw = function (text, id, _version, diagObj) {
.attr('orient', 'auto');
const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z');
- dagreD3.util.applyStyle(path, edge[type + 'Style']);
+ applyStyle(path, edge[type + 'Style']);
};
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
diff --git a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
index 79d67e76ed..0338ec50c8 100644
--- a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
+++ b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
@@ -1,5 +1,5 @@
import { line, select } from 'd3';
-import dagre from 'dagre';
+import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import graphlib from 'graphlib';
import { log } from '../../logger';
import { configureSvgSize } from '../../setupGraphViewbox';
@@ -348,7 +348,7 @@ export const draw = (text, id, _version, diagObj) => {
drawReqs(requirements, g, svg);
drawElements(elements, g, svg);
addRelationships(relationships, g);
- dagre.layout(g);
+ dagreLayout(g);
adjustEntities(svg, g);
relationships.forEach(function (rel) {
diff --git a/packages/mermaid/src/diagrams/state/stateRenderer.js b/packages/mermaid/src/diagrams/state/stateRenderer.js
index 73717a645c..783460cc69 100644
--- a/packages/mermaid/src/diagrams/state/stateRenderer.js
+++ b/packages/mermaid/src/diagrams/state/stateRenderer.js
@@ -1,5 +1,5 @@
import { select } from 'd3';
-import dagre from 'dagre';
+import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import graphlib from 'graphlib';
import { log } from '../../logger';
import common from '../common/common';
@@ -239,7 +239,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) =
);
});
- dagre.layout(graph);
+ dagreLayout(graph);
log.debug('Graph after layout', graph.nodes());
const svgElem = diagram.node();
diff --git a/packages/mermaid/src/tests/setup.ts b/packages/mermaid/src/tests/setup.ts
index e8058c5179..b3330787cc 100644
--- a/packages/mermaid/src/tests/setup.ts
+++ b/packages/mermaid/src/tests/setup.ts
@@ -1,3 +1,3 @@
import { vi } from 'vitest';
vi.mock('d3');
-vi.mock('dagre-d3');
+vi.mock('dagre-d3-es');
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 11703bd03e..0a04f741e9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,8 +1,5 @@
lockfileVersion: 5.4-inlineSpecifiers
-overrides:
- d3: ^7.6.1
-
importers:
.:
@@ -167,14 +164,11 @@ importers:
specifier: ^6.0.0
version: 6.0.0
d3:
- specifier: ^7.6.1
+ specifier: ^7.0.0
version: 7.6.1
- dagre:
- specifier: ^0.8.5
- version: 0.8.5
- dagre-d3:
- specifier: ^0.6.4
- version: 0.6.4
+ dagre-d3-es:
+ specifier: 7.0.2
+ version: 7.0.2
dompurify:
specifier: 2.4.1
version: 2.4.1
@@ -318,7 +312,7 @@ importers:
specifier: ^2.1.0
version: 2.1.0_cytoscape@3.23.0
d3:
- specifier: ^7.6.1
+ specifier: ^7.0.0
version: 7.6.1
khroma:
specifier: ^2.0.0
@@ -4800,20 +4794,11 @@ packages:
d3-zoom: 3.0.0
dev: false
- /dagre-d3/0.6.4:
- resolution: {integrity: sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==}
+ /dagre-d3-es/7.0.2:
+ resolution: {integrity: sha512-m9+5yhzkf9gyklDMdWlQC/8bayGVlTF8GspmN6XC6nnZjas6kAmffvh0c/EcyFhQ+fp4QIl0fMpNdv76AJGlVQ==}
dependencies:
d3: 7.6.1
- dagre: 0.8.5
- graphlib: 2.1.8
- lodash: 4.17.21
- dev: false
-
- /dagre/0.8.5:
- resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
- dependencies:
- graphlib: 2.1.8
- lodash: 4.17.21
+ lodash-es: 4.17.21
dev: false
/dargs/7.0.0:
@@ -7905,6 +7890,10 @@ packages:
p-locate: 5.0.0
dev: true
+ /lodash-es/4.17.21:
+ resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+ dev: false
+
/lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true