diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index fb423b9b0d..62aa3bb833 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -14,6 +14,9 @@ export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: * @privateRemarks This is exported as part of the public mermaidAPI. */ export class Diagram { + + graphData: string | null = null; + public static async fromText(text: string, metadata: Pick = {}) { const config = configApi.getConfig(); const type = detectType(text, config); @@ -64,4 +67,12 @@ export class Diagram { getType() { return this.type; } + + setGraphData(graphString: string) { + this.graphData = graphString; + } + + getGraphData(): string | null { + return this.graphData; + } } diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts index 0f02efa0d6..155924dfba 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts @@ -1,6 +1,7 @@ // @ts-nocheck - don't check until handle it import { select, curveLinear } from 'd3'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; +import * as graphlibJson from 'dagre-d3-es/src/graphlib/json.js'; import { log } from '../../logger.js'; import { getConfig } from '../../diagram-api/diagramAPI.js'; import { render } from '../../dagre-wrapper/index.js'; @@ -357,6 +358,9 @@ export const draw = async function (text: string, id: string, _version: string, id ); + const jsonData = graphlibJson.write(g); + diagObj.setGraphData(JSON.stringify(jsonData)); + utils.insertTitle(svg, 'classTitleText', conf?.titleTopMargin ?? 5, diagObj.db.getDiagramTitle()); setupGraphViewbox(g, svg, conf?.diagramPadding, conf?.useMaxWidth); diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts index 670f93f165..d44ac45155 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts @@ -60,7 +60,7 @@ export const draw = async function (text: string, id: string, _version: string, data4Layout.rankSpacing = conf?.rankSpacing || 50; data4Layout.markers = ['aggregation', 'extension', 'composition', 'dependency', 'lollipop']; data4Layout.diagramId = id; - await render(data4Layout, svg); + await render(data4Layout, svg, (data) => diag.setGraphData(data)); const padding = 8; utils.insertTitle( svg, diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js index 0327bfc9d5..4f0a39f354 100644 --- a/packages/mermaid/src/diagrams/er/erRenderer.js +++ b/packages/mermaid/src/diagrams/er/erRenderer.js @@ -1,4 +1,5 @@ import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; +import * as graphlibJson from 'dagre-d3-es/src/graphlib/json.js'; import { line, curveBasis, select } from 'd3'; import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import { getConfig } from '../../diagram-api/diagramAPI.js'; @@ -656,6 +657,10 @@ export const draw = function (text, id, _version, diagObj) { configureSvgSize(svg, height, width, conf.useMaxWidth); svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`); + + const jsonData = graphlibJson.write(g); + diagObj.setGraphData(JSON.stringify(jsonData)); + }; // draw /** diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts index 6cc15258d4..3086860175 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts @@ -53,7 +53,7 @@ export const draw = async function (text: string, id: string, _version: string, data4Layout.diagramId = id; log.debug('REF1:', data4Layout); - await render(data4Layout, svg); + await render(data4Layout, svg, (data) => diag.setGraphData(data)); const padding = data4Layout.config.flowchart?.diagramPadding ?? 8; utils.insertTitle( svg, diff --git a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts index 951d84b862..5c7b44746b 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts @@ -163,7 +163,13 @@ export const bounds = { return activation.actor; }) .lastIndexOf(message.from); - return this.activations.splice(lastActorActivationIdx, 1)[0]; + const activationData = this.activations.splice(lastActorActivationIdx, 1)[0]; + bounds.models.addMessage({ + activation: activationData, + type: message.type, + order: lastActorActivationIdx, + }); + return activationData; }, createLoop: function (title = { message: undefined, wrap: false, width: undefined }, fill) { return { @@ -176,6 +182,7 @@ export const bounds = { width: title.width, height: 0, fill: fill, + type: title.type, }; }, newLoop: function (title = { message: undefined, wrap: false, width: undefined }, fill) { @@ -1143,6 +1150,7 @@ export const draw = async function (_text: string, id: string, _version: string, ); log.debug(`models:`, bounds.models); + diagObj.setGraphData(JSON.stringify(bounds.models)); }; /** diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts index 109417c035..369a31e674 100644 --- a/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts @@ -67,7 +67,7 @@ export const draw = async function (text: string, id: string, _version: string, data4Layout.markers = ['barb']; data4Layout.diagramId = id; // console.log('REF1:', data4Layout); - await render(data4Layout, svg); + await render(data4Layout, svg, (data) => diag.setGraphData(data)); const padding = 8; utils.insertTitle( svg, diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 910ecb5e88..3e22089ead 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -466,9 +466,11 @@ const render = async function ( } removeTempElements(); + const graph = diag.getGraphData(); return { diagramType, + graph, svg: svgCode, bindFunctions: diag.db.bindFunctions, }; diff --git a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/index.js b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/index.js index 6f1fa7d3bf..f4aca4c895 100644 --- a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/index.js +++ b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/index.js @@ -268,7 +268,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit return { elem, diff }; }; -export const render = async (data4Layout, svg) => { +export const render = async (data4Layout, svg, _svghelpers, _options, setGraphData) => { const graph = new graphlib.Graph({ multigraph: true, compound: true, @@ -374,4 +374,10 @@ export const render = async (data4Layout, svg) => { undefined, siteConfig ); + + if (setGraphData) { + const jsonData = graphlibJson.write(graph); + const graphData = JSON.stringify(jsonData) + setGraphData(graphData); + } }; diff --git a/packages/mermaid/src/rendering-util/render.ts b/packages/mermaid/src/rendering-util/render.ts index b975e7bf97..387e84396f 100644 --- a/packages/mermaid/src/rendering-util/render.ts +++ b/packages/mermaid/src/rendering-util/render.ts @@ -13,7 +13,8 @@ export interface LayoutAlgorithm { layoutData: LayoutData, svg: SVG, helpers: InternalHelpers, - options?: RenderOptions + options?: RenderOptions, + setGraphData?: (data: string) => void ): Promise; } @@ -44,16 +45,19 @@ const registerDefaultLayoutLoaders = () => { registerDefaultLayoutLoaders(); -export const render = async (data4Layout: LayoutData, svg: SVG) => { +export const render = async (data4Layout: LayoutData, svg: SVG, setGraphData?: (data: string) => void) => { if (!(data4Layout.layoutAlgorithm in layoutAlgorithms)) { throw new Error(`Unknown layout algorithm: ${data4Layout.layoutAlgorithm}`); } const layoutDefinition = layoutAlgorithms[data4Layout.layoutAlgorithm]; const layoutRenderer = await layoutDefinition.loader(); - return layoutRenderer.render(data4Layout, svg, internalHelpers, { - algorithm: layoutDefinition.algorithm, - }); + return layoutRenderer.render(data4Layout, + svg, + internalHelpers, + { algorithm: layoutDefinition.algorithm }, + setGraphData + ); }; /** diff --git a/packages/mermaid/src/types.ts b/packages/mermaid/src/types.ts index 5587ca3f4d..b65281c226 100644 --- a/packages/mermaid/src/types.ts +++ b/packages/mermaid/src/types.ts @@ -78,6 +78,12 @@ export type D3Element = any; export type D3Selection = d3.Selection; export interface RenderResult { + + /** + * Graphical stringified JSON representation of the diagram + */ + graph: string | null; + /** * The svg code for the rendered graph. */