mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
#5237 WIP, testing common layoutAndRender
This commit is contained in:
parent
6b7e1225dd
commit
8205e3619a
@ -58,10 +58,17 @@
|
||||
</head>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
stateDiagram-v2
|
||||
Second
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
stateDiagram-v2
|
||||
state First {
|
||||
Second
|
||||
} </pre>
|
||||
}
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart TB
|
||||
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) => {
|
||||
switch (item.stmt) {
|
||||
case STMT_STATE:
|
||||
if(parentId) {
|
||||
nodes.push({...item, labelText: item.id, labelType:'text', parentId});
|
||||
if (parentId) {
|
||||
nodes.push({ ...item, labelText: item.id, labelType: 'text', parentId, shape: 'rect' });
|
||||
} 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);
|
||||
}
|
||||
break;
|
||||
@ -559,7 +573,7 @@ const dataFetcher = (parentId, doc, nodes, edges) => {
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
export const getData = () => {
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
@ -571,9 +585,8 @@ export const getData = () => {
|
||||
// }
|
||||
dataFetcher(undefined, rootDoc, nodes, edges);
|
||||
|
||||
|
||||
return {nodes, edges, other: {}};
|
||||
}
|
||||
return { nodes, edges, other: {} };
|
||||
};
|
||||
|
||||
export default {
|
||||
getConfig: () => getConfig().state,
|
||||
|
@ -3,8 +3,8 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import parser from './parser/stateDiagram.jison';
|
||||
import db from './stateDb.js';
|
||||
import styles from './styles.js';
|
||||
// import renderer from './stateRenderer-v2.js';
|
||||
import renderer from './stateRenderer-v3-unified.js';
|
||||
import renderer from './stateRenderer-v2.js';
|
||||
// import renderer from './stateRenderer-v3-unified.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
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 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 doLayout from '../../rendering-util/doLayout';
|
||||
import performRender from '../../rendering-util/performRender';
|
||||
import insertElementsForSize, { getDiagramElements} from '../../rendering-util/inserElementsForSize.js';
|
||||
|
||||
|
||||
import doLayout from '../../rendering-util/doLayout.js';
|
||||
import performRender from '../../rendering-util/performRender.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
|
||||
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 (
|
||||
text: string,
|
||||
diagramObj: any
|
||||
@ -27,23 +57,43 @@ export const getClasses = function (
|
||||
};
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
log.info('REF0:');
|
||||
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());
|
||||
|
||||
const DIR = getDir(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;
|
||||
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);
|
||||
const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
||||
// Create the root SVG - the element is the div containing the SVG element
|
||||
const { element, svg } = getDiagramElements(id, securityLevel);
|
||||
|
||||
// The performRender method provided in all supported diagrams is used to render the data
|
||||
performRender(data4Rendering);
|
||||
// // 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);
|
||||
|
||||
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 {
|
||||
|
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
|
||||
interface Node {
|
||||
id: string;
|
||||
label?: string;
|
||||
parentId?: string;
|
||||
position?: string;
|
||||
styles?: string;
|
||||
classes?: string;
|
||||
// Flowchart specific properties
|
||||
labelType?: string;
|
||||
domId: string;
|
||||
// Rendering specific properties for both Flowchart and State Diagram nodes
|
||||
dir?: string;
|
||||
haveCallback?: boolean;
|
||||
labelStyle?: string;
|
||||
labelText?: string;
|
||||
link?: string;
|
||||
linkTarget?: string;
|
||||
padding?: number;
|
||||
props?: Record<string, unknown>;
|
||||
rx?: number;
|
||||
ry?: number;
|
||||
shape?: string;
|
||||
tooltip?: string;
|
||||
type: string;
|
||||
width?: number;
|
||||
id: string;
|
||||
label?: string;
|
||||
parentId?: string;
|
||||
position?: string;
|
||||
styles?: string;
|
||||
classes?: string;
|
||||
// Flowchart specific properties
|
||||
labelType?: string;
|
||||
domId: string;
|
||||
// Rendering specific properties for both Flowchart and State Diagram nodes
|
||||
dir?: string;
|
||||
haveCallback?: boolean;
|
||||
labelStyle?: string;
|
||||
labelText?: string;
|
||||
link?: string;
|
||||
linkTarget?: string;
|
||||
padding?: number;
|
||||
props?: Record<string, unknown>;
|
||||
rx?: number;
|
||||
ry?: number;
|
||||
shape?: string;
|
||||
tooltip?: string;
|
||||
type: string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
// Common properties for any edge in the system
|
||||
interface Edge {
|
||||
id: string;
|
||||
label?: string;
|
||||
classes?: string;
|
||||
style?: string;
|
||||
// Properties common to both Flowchart and State Diagram edges
|
||||
arrowhead?: string;
|
||||
arrowheadStyle?: string;
|
||||
arrowTypeEnd?: string;
|
||||
arrowTypeStart?: string;
|
||||
// Flowchart specific properties
|
||||
defaultInterpolate?: string;
|
||||
end?: string;
|
||||
interpolate?: string;
|
||||
labelType?: string;
|
||||
length?: number;
|
||||
start?: string;
|
||||
stroke?: string;
|
||||
text?: string;
|
||||
type: string;
|
||||
// Rendering specific properties
|
||||
curve?: string;
|
||||
labelpos?: string;
|
||||
labelStyle?: string;
|
||||
minlen?: number;
|
||||
pattern?: string;
|
||||
thickness?: number;
|
||||
id: string;
|
||||
label?: string;
|
||||
classes?: string;
|
||||
style?: string;
|
||||
// Properties common to both Flowchart and State Diagram edges
|
||||
arrowhead?: string;
|
||||
arrowheadStyle?: string;
|
||||
arrowTypeEnd?: string;
|
||||
arrowTypeStart?: string;
|
||||
// Flowchart specific properties
|
||||
defaultInterpolate?: string;
|
||||
end?: string;
|
||||
interpolate?: string;
|
||||
labelType?: string;
|
||||
length?: number;
|
||||
start?: string;
|
||||
stroke?: string;
|
||||
text?: string;
|
||||
type: string;
|
||||
// Rendering specific properties
|
||||
curve?: string;
|
||||
labelpos?: string;
|
||||
labelStyle?: string;
|
||||
minlen?: number;
|
||||
pattern?: string;
|
||||
thickness?: number;
|
||||
}
|
||||
|
||||
// Extending the Node interface for specific types if needed
|
||||
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
|
||||
export interface LayoutData {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
other: any; // Additional properties not yet defined
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
other: any; // Additional properties not yet defined
|
||||
}
|
||||
|
||||
export interface RenderData {
|
||||
items: (Node | Edge)[];
|
||||
otherDetails: any; // Placeholder for additional, undefined properties
|
||||
items: (Node | Edge)[];
|
||||
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.
|
||||
|
||||
|
||||
export type LayoutMethod =
|
||||
| 'dagre'
|
||||
| 'dagre-wrapper'
|
||||
@ -96,39 +95,38 @@ export type LayoutMethod =
|
||||
| 'osage'
|
||||
| 'grid';
|
||||
|
||||
|
||||
export function createDomElement(node: Node): Node {
|
||||
// Create a new DOM element. Assuming we're creating a div as an example
|
||||
const element = document.createElement('div');
|
||||
// Create a new DOM element. Assuming we're creating a div as an example
|
||||
const element = document.createElement('div');
|
||||
|
||||
// Check if node.domId is set, if not generate a unique identifier for it
|
||||
if (!node.domId) {
|
||||
// This is a simplistic approach to generate a unique ID
|
||||
// In a real application, you might want to use a more robust method
|
||||
node.domId = `node-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
// Check if node.domId is set, if not generate a unique identifier for it
|
||||
if (!node.domId) {
|
||||
// This is a simplistic approach to generate a unique ID
|
||||
// In a real application, you might want to use a more robust method
|
||||
node.domId = `node-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
// Set the ID of the DOM element
|
||||
element.id = node.domId;
|
||||
// Set the ID of the DOM element
|
||||
element.id = node.domId;
|
||||
|
||||
// Optional: Apply styles and classes to the element
|
||||
if (node.styles) {
|
||||
element.style.cssText = node.styles;
|
||||
}
|
||||
if (node.classes) {
|
||||
element.className = node.classes;
|
||||
}
|
||||
// Optional: Apply styles and classes to the element
|
||||
if (node.styles) {
|
||||
element.style.cssText = node.styles;
|
||||
}
|
||||
if (node.classes) {
|
||||
element.className = node.classes;
|
||||
}
|
||||
|
||||
// Optional: Add content or additional attributes to the element
|
||||
// This can be based on other properties of the node
|
||||
if (node.label) {
|
||||
element.textContent = node.label;
|
||||
}
|
||||
// Optional: Add content or additional attributes to the element
|
||||
// This can be based on other properties of the node
|
||||
if (node.label) {
|
||||
element.textContent = node.label;
|
||||
}
|
||||
|
||||
// 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
|
||||
document.body.appendChild(element);
|
||||
// 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
|
||||
document.body.appendChild(element);
|
||||
|
||||
// Return the updated node with its domId set
|
||||
return node;
|
||||
// Return the updated node with its domId set
|
||||
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