mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-02-04 07:13:25 +08:00
#5237 WIP, testing common layoutAndRender
This commit is contained in:
parent
6b7e1225dd
commit
8205e3619a
@ -58,10 +58,17 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
|
stateDiagram-v2
|
||||||
|
Second
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
state First {
|
state First {
|
||||||
Second
|
Second
|
||||||
} </pre>
|
}
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
flowchart TB
|
flowchart TB
|
||||||
subgraph First
|
subgraph First
|
||||||
|
209
packages/mermaid/src/dagre-wrapper/index-refactored.js
Normal file
209
packages/mermaid/src/dagre-wrapper/index-refactored.js
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
|
||||||
|
import * as graphlibJson from 'dagre-d3-es/src/graphlib/json.js';
|
||||||
|
import insertMarkers from './markers.js';
|
||||||
|
import { updateNodeBounds } from './shapes/util.js';
|
||||||
|
import {
|
||||||
|
clear as clearGraphlib,
|
||||||
|
clusterDb,
|
||||||
|
adjustClustersAndEdges,
|
||||||
|
findNonClusterChild,
|
||||||
|
sortNodesByHierarchy,
|
||||||
|
} from './mermaid-graphlib.js';
|
||||||
|
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||||
|
import { insertNode, positionNode, clear as clearNodes, setNodeElem } from './nodes.js';
|
||||||
|
import { insertCluster, clear as clearClusters } from './clusters.js';
|
||||||
|
import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges.js';
|
||||||
|
import { log } from '../logger.js';
|
||||||
|
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
|
||||||
|
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||||
|
// import type { LayoutData, LayoutMethod } from '../rendering-util/types.js';
|
||||||
|
// import type { MermaidConfig } from '../config.type.js';
|
||||||
|
|
||||||
|
const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, siteConfig) => {
|
||||||
|
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
|
||||||
|
const dir = graph.graph().rankdir;
|
||||||
|
log.trace('Dir in recursive render - dir:', dir);
|
||||||
|
|
||||||
|
const elem = _elem.insert('g').attr('class', 'root');
|
||||||
|
if (!graph.nodes()) {
|
||||||
|
log.info('No nodes found for', graph);
|
||||||
|
} else {
|
||||||
|
log.info('Recursive render XXX', graph.nodes());
|
||||||
|
}
|
||||||
|
if (graph.edges().length > 0) {
|
||||||
|
log.trace('Recursive edges', graph.edge(graph.edges()[0]));
|
||||||
|
}
|
||||||
|
const clusters = elem.insert('g').attr('class', 'clusters');
|
||||||
|
const edgePaths = elem.insert('g').attr('class', 'edgePaths');
|
||||||
|
const edgeLabels = elem.insert('g').attr('class', 'edgeLabels');
|
||||||
|
const nodes = elem.insert('g').attr('class', 'nodes');
|
||||||
|
|
||||||
|
// Insert nodes, this will insert them into the dom and each node will get a size. The size is updated
|
||||||
|
// to the abstract node and is later used by dagre for the layout
|
||||||
|
await Promise.all(
|
||||||
|
graph.nodes().map(async function (v) {
|
||||||
|
const node = graph.node(v);
|
||||||
|
if (parentCluster !== undefined) {
|
||||||
|
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
|
||||||
|
// data.clusterPositioning = true;
|
||||||
|
log.info('Setting data for cluster XXX (', v, ') ', data, parentCluster);
|
||||||
|
graph.setNode(parentCluster.id, data);
|
||||||
|
if (!graph.parent(v)) {
|
||||||
|
log.trace('Setting parent', v, parentCluster.id);
|
||||||
|
graph.setParent(v, parentCluster.id, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
|
||||||
|
if (node && node.clusterNode) {
|
||||||
|
// const children = graph.children(v);
|
||||||
|
log.info('Cluster identified', v, node.width, graph.node(v));
|
||||||
|
const o = await recursiveRender(
|
||||||
|
nodes,
|
||||||
|
node.graph,
|
||||||
|
diagramtype,
|
||||||
|
id,
|
||||||
|
graph.node(v),
|
||||||
|
siteConfig
|
||||||
|
);
|
||||||
|
const newEl = o.elem;
|
||||||
|
updateNodeBounds(node, newEl);
|
||||||
|
node.diff = o.diff || 0;
|
||||||
|
log.info('Node bounds (abc123)', v, node, node.width, node.x, node.y);
|
||||||
|
setNodeElem(newEl, node);
|
||||||
|
|
||||||
|
log.warn('Recursive render complete ', newEl, node);
|
||||||
|
} else {
|
||||||
|
if (graph.children(v).length > 0) {
|
||||||
|
// This is a cluster but not to be rendered recursively
|
||||||
|
// Render as before
|
||||||
|
log.info('Cluster - the non recursive path XXX', v, node.id, node, graph);
|
||||||
|
log.info(findNonClusterChild(node.id, graph));
|
||||||
|
clusterDb[node.id] = { id: findNonClusterChild(node.id, graph), node };
|
||||||
|
// insertCluster(clusters, graph.node(v));
|
||||||
|
} else {
|
||||||
|
log.info('Node - the non recursive path', v, node.id, node);
|
||||||
|
await insertNode(nodes, graph.node(v), dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Insert labels, this will insert them into the dom so that the width can be calculated
|
||||||
|
// Also figure out which edges point to/from clusters and adjust them accordingly
|
||||||
|
// Edges from/to clusters really points to the first child in the cluster.
|
||||||
|
// TODO: pick optimal child in the cluster to us as link anchor
|
||||||
|
graph.edges().forEach(function (e) {
|
||||||
|
const edge = graph.edge(e.v, e.w, e.name);
|
||||||
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
|
||||||
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ', e, ' ', JSON.stringify(graph.edge(e)));
|
||||||
|
|
||||||
|
// Check if link is either from or to a cluster
|
||||||
|
log.info('Fix', clusterDb, 'ids:', e.v, e.w, 'Translateing: ', clusterDb[e.v], clusterDb[e.w]);
|
||||||
|
insertEdgeLabel(edgeLabels, edge);
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.edges().forEach(function (e) {
|
||||||
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
|
||||||
|
});
|
||||||
|
log.info('#############################################');
|
||||||
|
log.info('### Layout ###');
|
||||||
|
log.info('#############################################');
|
||||||
|
log.info(graph);
|
||||||
|
dagreLayout(graph);
|
||||||
|
log.info('Graph after layout:', graphlibJson.write(graph));
|
||||||
|
// Move the nodes to the correct place
|
||||||
|
let diff = 0;
|
||||||
|
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
|
||||||
|
sortNodesByHierarchy(graph).forEach(function (v) {
|
||||||
|
const node = graph.node(v);
|
||||||
|
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
|
||||||
|
log.info(
|
||||||
|
'Position ' + v + ': (' + node.x,
|
||||||
|
',' + node.y,
|
||||||
|
') width: ',
|
||||||
|
node.width,
|
||||||
|
' height: ',
|
||||||
|
node.height
|
||||||
|
);
|
||||||
|
if (node && node.clusterNode) {
|
||||||
|
// clusterDb[node.id].node = node;
|
||||||
|
node.y += subGraphTitleTotalMargin;
|
||||||
|
positionNode(node);
|
||||||
|
} else {
|
||||||
|
// Non cluster node
|
||||||
|
if (graph.children(v).length > 0) {
|
||||||
|
// A cluster in the non-recursive way
|
||||||
|
// positionCluster(node);
|
||||||
|
node.height += subGraphTitleTotalMargin;
|
||||||
|
insertCluster(clusters, node);
|
||||||
|
clusterDb[node.id].node = node;
|
||||||
|
} else {
|
||||||
|
node.y += subGraphTitleTotalMargin / 2;
|
||||||
|
positionNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move the edge labels to the correct place after layout
|
||||||
|
graph.edges().forEach(function (e) {
|
||||||
|
const edge = graph.edge(e);
|
||||||
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
||||||
|
|
||||||
|
edge.points.forEach((point) => (point.y += subGraphTitleTotalMargin / 2));
|
||||||
|
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id);
|
||||||
|
positionEdgeLabel(edge, paths);
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.nodes().forEach(function (v) {
|
||||||
|
const n = graph.node(v);
|
||||||
|
log.info(v, n.type, n.diff);
|
||||||
|
if (n.type === 'group') {
|
||||||
|
diff = n.diff;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { elem, diff };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const render = async (data4Layout, svg, element) => {
|
||||||
|
// Create the input mermaid.graph
|
||||||
|
const graph = new graphlib.Graph({
|
||||||
|
multigraph: true,
|
||||||
|
compound: true,
|
||||||
|
})
|
||||||
|
.setGraph({
|
||||||
|
rankdir: data4Layout.direction,
|
||||||
|
nodesep: data4Layout.nodeSpacing,
|
||||||
|
ranksep: data4Layout.rankSpacing,
|
||||||
|
marginx: 8,
|
||||||
|
marginy: 8,
|
||||||
|
})
|
||||||
|
.setDefaultEdgeLabel(function () {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Org
|
||||||
|
|
||||||
|
insertMarkers(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);
|
||||||
|
clearNodes();
|
||||||
|
clearEdges();
|
||||||
|
clearClusters();
|
||||||
|
clearGraphlib();
|
||||||
|
|
||||||
|
// Add the nodes and edges to the graph
|
||||||
|
data4Layout.nodes.forEach((node) => {
|
||||||
|
graph.setNode(node.id, { ...node });
|
||||||
|
});
|
||||||
|
|
||||||
|
log.warn('Graph at first:', JSON.stringify(graphlibJson.write(graph)));
|
||||||
|
adjustClustersAndEdges(graph);
|
||||||
|
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
|
||||||
|
const siteConfig = getConfig();
|
||||||
|
await recursiveRender(
|
||||||
|
element,
|
||||||
|
graph,
|
||||||
|
data4Layout.type,
|
||||||
|
data4Layout.diagramId,
|
||||||
|
undefined,
|
||||||
|
siteConfig
|
||||||
|
);
|
||||||
|
};
|
@ -545,12 +545,26 @@ const dataFetcher = (parentId, doc, nodes, edges) => {
|
|||||||
doc.forEach((item) => {
|
doc.forEach((item) => {
|
||||||
switch (item.stmt) {
|
switch (item.stmt) {
|
||||||
case STMT_STATE:
|
case STMT_STATE:
|
||||||
if(parentId) {
|
if (parentId) {
|
||||||
nodes.push({...item, labelText: item.id, labelType:'text', parentId});
|
nodes.push({ ...item, labelText: item.id, labelType: 'text', parentId, shape: 'rect' });
|
||||||
} else {
|
} else {
|
||||||
nodes.push({...item, labelText: item.id, labelType:'text'});
|
nodes.push({
|
||||||
|
...item,
|
||||||
|
labelText: item.id,
|
||||||
|
// description: item.id,
|
||||||
|
labelType: 'text',
|
||||||
|
labelStyle: '',
|
||||||
|
shape: 'rect',
|
||||||
|
domId: 'state-bla-bla-bla',
|
||||||
|
x: 100,
|
||||||
|
y: 100,
|
||||||
|
height: 100,
|
||||||
|
width: 100,
|
||||||
|
padding: 15,
|
||||||
|
classes: ' statediagram-state',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if(item.doc) {
|
if (item.doc) {
|
||||||
dataFetcher(item.id, item.doc, nodes, edges);
|
dataFetcher(item.id, item.doc, nodes, edges);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -559,7 +573,7 @@ const dataFetcher = (parentId, doc, nodes, edges) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
export const getData = () => {
|
export const getData = () => {
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
const edges = [];
|
const edges = [];
|
||||||
@ -571,9 +585,8 @@ export const getData = () => {
|
|||||||
// }
|
// }
|
||||||
dataFetcher(undefined, rootDoc, nodes, edges);
|
dataFetcher(undefined, rootDoc, nodes, edges);
|
||||||
|
|
||||||
|
return { nodes, edges, other: {} };
|
||||||
return {nodes, edges, other: {}};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getConfig: () => getConfig().state,
|
getConfig: () => getConfig().state,
|
||||||
|
@ -3,8 +3,8 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
|||||||
import parser from './parser/stateDiagram.jison';
|
import parser from './parser/stateDiagram.jison';
|
||||||
import db from './stateDb.js';
|
import db from './stateDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
// import renderer from './stateRenderer-v2.js';
|
import renderer from './stateRenderer-v2.js';
|
||||||
import renderer from './stateRenderer-v3-unified.js';
|
// import renderer from './stateRenderer-v3-unified.js';
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
export const diagram: DiagramDefinition = {
|
||||||
parser,
|
parser,
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
import { log } from '../../logger.js';
|
||||||
|
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
|
import type { LayoutData, LayoutMethod } from '../../rendering-util/types.js';
|
||||||
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
|
import doLayout from '../../rendering-util/doLayout.js';
|
||||||
|
import performRender from '../../rendering-util/performRender.js';
|
||||||
|
import insertElementsForSize, {
|
||||||
|
getDiagramElements,
|
||||||
|
} from '../../rendering-util/inserElementsForSize.js';
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const conf: Record<string, any> = {};
|
||||||
|
|
||||||
|
export const setConf = function (cnf: Record<string, any>) {
|
||||||
|
const keys = Object.keys(cnf);
|
||||||
|
for (const key of keys) {
|
||||||
|
conf[key] = cnf[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getClasses = function (
|
||||||
|
text: string,
|
||||||
|
diagramObj: any
|
||||||
|
): Record<string, DiagramStyleClassDef> {
|
||||||
|
diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
||||||
|
return diagramObj.db.getClasses();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||||
|
log.info('Drawing state diagram (v2)', id);
|
||||||
|
const { securityLevel, state: conf } = getConfig();
|
||||||
|
|
||||||
|
// Extracting the data from the parsed structure into a more usable form
|
||||||
|
// Not related to the refactoring, but this is the first step in the rendering process
|
||||||
|
diag.db.extract(diag.db.getRootDocV2());
|
||||||
|
|
||||||
|
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||||
|
// into the Layout data format
|
||||||
|
const data4Layout = diag.db.getData() as LayoutData;
|
||||||
|
// Create the root SVG
|
||||||
|
const { svg, element } = getDiagramElements(id, securityLevel);
|
||||||
|
// For some diagrams this call is not needed, but in the state diagram it is
|
||||||
|
await insertElementsForSize(element, data4Layout);
|
||||||
|
|
||||||
|
console.log('data4Layout:', data4Layout);
|
||||||
|
|
||||||
|
// Now we have layout data with real sizes, we can perform the layout
|
||||||
|
const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
||||||
|
|
||||||
|
// The performRender method provided in all supported diagrams is used to render the data
|
||||||
|
performRender(data4Rendering);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setConf,
|
||||||
|
getClasses,
|
||||||
|
draw,
|
||||||
|
};
|
@ -1,12 +1,21 @@
|
|||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
import type { LayoutData, LayoutMethod } from '../../rendering-util/types';
|
import type { LayoutData, LayoutMethod } from '../../rendering-util/types.js';
|
||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import doLayout from '../../rendering-util/doLayout';
|
import doLayout from '../../rendering-util/doLayout.js';
|
||||||
import performRender from '../../rendering-util/performRender';
|
import performRender from '../../rendering-util/performRender.js';
|
||||||
import insertElementsForSize, { getDiagramElements} from '../../rendering-util/inserElementsForSize.js';
|
import { render } from '../../rendering-util/render.js';
|
||||||
|
import insertElementsForSize, {
|
||||||
|
getDiagramElements,
|
||||||
|
} from '../../rendering-util/inserElementsForSize.js';
|
||||||
|
import {
|
||||||
|
DEFAULT_DIAGRAM_DIRECTION,
|
||||||
|
DEFAULT_NESTED_DOC_DIR,
|
||||||
|
STMT_STATE,
|
||||||
|
STMT_RELATION,
|
||||||
|
DEFAULT_STATE_TYPE,
|
||||||
|
DIVIDER_TYPE,
|
||||||
|
} from './stateCommon.js';
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
const conf: Record<string, any> = {};
|
const conf: Record<string, any> = {};
|
||||||
@ -18,6 +27,27 @@ export const setConf = function (cnf: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the direction from the statement items.
|
||||||
|
* Look through all of the documents (docs) in the parsedItems
|
||||||
|
* Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction.
|
||||||
|
* @param {object[]} parsedItem - the parsed statement item to look through
|
||||||
|
* @param [defaultDir] - the direction to use if none is found
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
||||||
|
let dir = defaultDir;
|
||||||
|
if (parsedItem.doc) {
|
||||||
|
for (let i = 0; i < parsedItem.doc.length; i++) {
|
||||||
|
const parsedItemDoc = parsedItem.doc[i];
|
||||||
|
if (parsedItemDoc.stmt === 'dir') {
|
||||||
|
dir = parsedItemDoc.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
};
|
||||||
|
|
||||||
export const getClasses = function (
|
export const getClasses = function (
|
||||||
text: string,
|
text: string,
|
||||||
diagramObj: any
|
diagramObj: any
|
||||||
@ -27,23 +57,43 @@ export const getClasses = function (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||||
|
log.info('REF0:');
|
||||||
log.info('Drawing state diagram (v2)', id);
|
log.info('Drawing state diagram (v2)', id);
|
||||||
const { securityLevel, state: conf } = getConfig();
|
const { securityLevel, state: conf } = getConfig();
|
||||||
|
|
||||||
// Extracting the data from the parsed structure into a more usable form
|
// Extracting the data from the parsed structure into a more usable form
|
||||||
// Not related to the refactoring, but this is the first step in the rendering process
|
// Not related to the refactoring, but this is the first step in the rendering process
|
||||||
diag.db.extract(diag.db.getRootDocV2());
|
diag.db.extract(diag.db.getRootDocV2());
|
||||||
|
|
||||||
|
const DIR = getDir(diag.db.getRootDocV2());
|
||||||
|
|
||||||
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||||
// into the Layout data format
|
// into the Layout data format
|
||||||
const data4Layout = diag.db.getData() as LayoutData;
|
const data4Layout = diag.db.getData() as LayoutData;
|
||||||
const { svg, element } = getDiagramElements(id, securityLevel);
|
// Create the root SVG - the element is the div containing the SVG element
|
||||||
// For some diagrams this call is not needed, but in the state diagram it is
|
const { element, svg } = getDiagramElements(id, securityLevel);
|
||||||
await insertElementsForSize(element, data4Layout);
|
|
||||||
const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
|
||||||
|
|
||||||
// The performRender method provided in all supported diagrams is used to render the data
|
// // For some diagrams this call is not needed, but in the state diagram it is
|
||||||
performRender(data4Rendering);
|
// await insertElementsForSize(element, data4Layout);
|
||||||
|
|
||||||
|
// console.log('data4Layout:', data4Layout);
|
||||||
|
|
||||||
|
// // Now we have layout data with real sizes, we can perform the layout
|
||||||
|
// const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
||||||
|
|
||||||
|
// // The performRender method provided in all supported diagrams is used to render the data
|
||||||
|
// performRender(data4Rendering);
|
||||||
|
|
||||||
|
console.log('REF1:', data4Layout);
|
||||||
|
data4Layout.type = diag.type;
|
||||||
|
data4Layout.layoutAlgorithm = 'dagre-wrapper';
|
||||||
|
data4Layout.skin = 'roughjs';
|
||||||
|
data4Layout.direction = DIR;
|
||||||
|
data4Layout.nodeSpacing = conf.nodeSpacing || 50;
|
||||||
|
data4Layout.rankSpacing = conf.rankSpacing || 50;
|
||||||
|
data4Layout.markers = ['barb'];
|
||||||
|
data4Layout.diagramId = id;
|
||||||
|
|
||||||
|
render(data4Layout, svg, element);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
7
packages/mermaid/src/rendering-util/render.js
Normal file
7
packages/mermaid/src/rendering-util/render.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const render = async (data4Layout, svg, element) => {
|
||||||
|
if (data4Layout.layoutAlgorithm === 'dagre-wrapper') {
|
||||||
|
const layoutRenderer = await import('../dagre-wrapper/index-refactored.js');
|
||||||
|
|
||||||
|
return layoutRenderer.render(data4Layout, svg, element);
|
||||||
|
}
|
||||||
|
};
|
168
packages/mermaid/src/rendering-util/types.d.ts
vendored
168
packages/mermaid/src/rendering-util/types.d.ts
vendored
@ -9,82 +9,81 @@ export type CheckFitFunction = (text: MarkdownLine) => boolean;
|
|||||||
|
|
||||||
// Common properties for any node in the system
|
// Common properties for any node in the system
|
||||||
interface Node {
|
interface Node {
|
||||||
id: string;
|
id: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
position?: string;
|
position?: string;
|
||||||
styles?: string;
|
styles?: string;
|
||||||
classes?: string;
|
classes?: string;
|
||||||
// Flowchart specific properties
|
// Flowchart specific properties
|
||||||
labelType?: string;
|
labelType?: string;
|
||||||
domId: string;
|
domId: string;
|
||||||
// Rendering specific properties for both Flowchart and State Diagram nodes
|
// Rendering specific properties for both Flowchart and State Diagram nodes
|
||||||
dir?: string;
|
dir?: string;
|
||||||
haveCallback?: boolean;
|
haveCallback?: boolean;
|
||||||
labelStyle?: string;
|
labelStyle?: string;
|
||||||
labelText?: string;
|
labelText?: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
linkTarget?: string;
|
linkTarget?: string;
|
||||||
padding?: number;
|
padding?: number;
|
||||||
props?: Record<string, unknown>;
|
props?: Record<string, unknown>;
|
||||||
rx?: number;
|
rx?: number;
|
||||||
ry?: number;
|
ry?: number;
|
||||||
shape?: string;
|
shape?: string;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
type: string;
|
type: string;
|
||||||
width?: number;
|
width?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common properties for any edge in the system
|
// Common properties for any edge in the system
|
||||||
interface Edge {
|
interface Edge {
|
||||||
id: string;
|
id: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
classes?: string;
|
classes?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
// Properties common to both Flowchart and State Diagram edges
|
// Properties common to both Flowchart and State Diagram edges
|
||||||
arrowhead?: string;
|
arrowhead?: string;
|
||||||
arrowheadStyle?: string;
|
arrowheadStyle?: string;
|
||||||
arrowTypeEnd?: string;
|
arrowTypeEnd?: string;
|
||||||
arrowTypeStart?: string;
|
arrowTypeStart?: string;
|
||||||
// Flowchart specific properties
|
// Flowchart specific properties
|
||||||
defaultInterpolate?: string;
|
defaultInterpolate?: string;
|
||||||
end?: string;
|
end?: string;
|
||||||
interpolate?: string;
|
interpolate?: string;
|
||||||
labelType?: string;
|
labelType?: string;
|
||||||
length?: number;
|
length?: number;
|
||||||
start?: string;
|
start?: string;
|
||||||
stroke?: string;
|
stroke?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
type: string;
|
type: string;
|
||||||
// Rendering specific properties
|
// Rendering specific properties
|
||||||
curve?: string;
|
curve?: string;
|
||||||
labelpos?: string;
|
labelpos?: string;
|
||||||
labelStyle?: string;
|
labelStyle?: string;
|
||||||
minlen?: number;
|
minlen?: number;
|
||||||
pattern?: string;
|
pattern?: string;
|
||||||
thickness?: number;
|
thickness?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extending the Node interface for specific types if needed
|
// Extending the Node interface for specific types if needed
|
||||||
interface ClassDiagramNode extends Node {
|
interface ClassDiagramNode extends Node {
|
||||||
memberData: any; // Specific property for class diagram nodes
|
memberData: any; // Specific property for class diagram nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific interfaces for layout and render data
|
// Specific interfaces for layout and render data
|
||||||
export interface LayoutData {
|
export interface LayoutData {
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
other: any; // Additional properties not yet defined
|
other: any; // Additional properties not yet defined
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderData {
|
export interface RenderData {
|
||||||
items: (Node | Edge)[];
|
items: (Node | Edge)[];
|
||||||
otherDetails: any; // Placeholder for additional, undefined properties
|
otherDetails: any; // Placeholder for additional, undefined properties
|
||||||
}
|
}
|
||||||
|
|
||||||
// This refactored approach ensures that common properties are included in the base `Node` and `Edge` interfaces, with specific types extending these bases with additional properties as needed. This maintains flexibility while ensuring type safety and reducing redundancy.
|
// This refactored approach ensures that common properties are included in the base `Node` and `Edge` interfaces, with specific types extending these bases with additional properties as needed. This maintains flexibility while ensuring type safety and reducing redundancy.
|
||||||
|
|
||||||
|
|
||||||
export type LayoutMethod =
|
export type LayoutMethod =
|
||||||
| 'dagre'
|
| 'dagre'
|
||||||
| 'dagre-wrapper'
|
| 'dagre-wrapper'
|
||||||
@ -96,39 +95,38 @@ export type LayoutMethod =
|
|||||||
| 'osage'
|
| 'osage'
|
||||||
| 'grid';
|
| 'grid';
|
||||||
|
|
||||||
|
|
||||||
export function createDomElement(node: Node): Node {
|
export function createDomElement(node: Node): Node {
|
||||||
// Create a new DOM element. Assuming we're creating a div as an example
|
// Create a new DOM element. Assuming we're creating a div as an example
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
|
|
||||||
// Check if node.domId is set, if not generate a unique identifier for it
|
// Check if node.domId is set, if not generate a unique identifier for it
|
||||||
if (!node.domId) {
|
if (!node.domId) {
|
||||||
// This is a simplistic approach to generate a unique ID
|
// This is a simplistic approach to generate a unique ID
|
||||||
// In a real application, you might want to use a more robust method
|
// In a real application, you might want to use a more robust method
|
||||||
node.domId = `node-${Math.random().toString(36).substr(2, 9)}`;
|
node.domId = `node-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the ID of the DOM element
|
// Set the ID of the DOM element
|
||||||
element.id = node.domId;
|
element.id = node.domId;
|
||||||
|
|
||||||
// Optional: Apply styles and classes to the element
|
// Optional: Apply styles and classes to the element
|
||||||
if (node.styles) {
|
if (node.styles) {
|
||||||
element.style.cssText = node.styles;
|
element.style.cssText = node.styles;
|
||||||
}
|
}
|
||||||
if (node.classes) {
|
if (node.classes) {
|
||||||
element.className = node.classes;
|
element.className = node.classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Add content or additional attributes to the element
|
// Optional: Add content or additional attributes to the element
|
||||||
// This can be based on other properties of the node
|
// This can be based on other properties of the node
|
||||||
if (node.label) {
|
if (node.label) {
|
||||||
element.textContent = node.label;
|
element.textContent = node.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the newly created element to the document body or a specific container
|
// Append the newly created element to the document body or a specific container
|
||||||
// This is just an example; in a real application, you might append it somewhere specific
|
// This is just an example; in a real application, you might append it somewhere specific
|
||||||
document.body.appendChild(element);
|
document.body.appendChild(element);
|
||||||
|
|
||||||
// Return the updated node with its domId set
|
// Return the updated node with its domId set
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
634
pnpm-lock.yaml
generated
634
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user