mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-29 12:19:41 +02:00
#5237 Adding basic flow, WIP
This commit is contained in:
@@ -372,10 +372,13 @@ const rect = async (parent, node) => {
|
||||
// add the rect
|
||||
const rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
|
||||
// console.log('Rect node:', node, 'bbox:', bbox, 'halfPadding:', halfPadding, 'node.padding:', node.padding);
|
||||
// const totalWidth = bbox.width + node.padding * 2;
|
||||
// const totalHeight = bbox.height + node.padding * 2;
|
||||
const totalWidth = bbox.width + node.padding;
|
||||
const totalHeight = bbox.height + node.padding;
|
||||
console.log('Rect node:', node, rect.node(), 'bbox:', bbox, 'halfPadding:', halfPadding, 'node.padding:', node.padding, 'totalWidth:', totalWidth, 'totalHeight:', totalHeight);
|
||||
rect
|
||||
.attr('class', 'basic label-container')
|
||||
.attr('style', node.style)
|
||||
@@ -1062,6 +1065,8 @@ export const insertNode = async (elem, node, dir) => {
|
||||
let newEl;
|
||||
let el;
|
||||
|
||||
console.log('insertNode element', elem, elem.node());
|
||||
// debugger;
|
||||
// Add link when appropriate
|
||||
if (node.link) {
|
||||
let target;
|
||||
|
@@ -14,6 +14,8 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
classes = _classes;
|
||||
}
|
||||
|
||||
console.log('parentY', parent.node());
|
||||
|
||||
// Add outer g element
|
||||
const shapeSvg = parent
|
||||
.insert('g')
|
||||
@@ -31,7 +33,9 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
labelText = typeof node.labelText === 'string' ? node.labelText : node.labelText[0];
|
||||
}
|
||||
|
||||
|
||||
const textNode = label.node();
|
||||
console.log('parentX', parent, 'node',node,'labelText',labelText, textNode, node.labelType, 'label', label.node());
|
||||
let text;
|
||||
if (node.labelType === 'markdown') {
|
||||
// text = textNode;
|
||||
|
@@ -29,6 +29,9 @@ export const setConf = function (cnf) {
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
|
||||
const svg = root.select(`[id="${svgId}"]`);
|
||||
console.log('SVG:', svg, svg.node(), 'root:', root, root.node());
|
||||
|
||||
|
||||
const keys = Object.keys(vert);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
|
@@ -541,8 +541,43 @@ const setDirection = (dir) => {
|
||||
|
||||
const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim());
|
||||
|
||||
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});
|
||||
} else {
|
||||
nodes.push({...item, labelText: item.id, labelType:'text'});
|
||||
}
|
||||
if(item.doc) {
|
||||
dataFetcher(item.id, item.doc, nodes, edges);
|
||||
}
|
||||
break;
|
||||
case STMT_RELATION:
|
||||
edges.push(item);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
export const getData = () => {
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
|
||||
// for (const key in currentDocument.states) {
|
||||
// if (currentDocument.states.hasOwnProperty(key)) {
|
||||
// nodes.push({...currentDocument.states[key]});
|
||||
// }
|
||||
// }
|
||||
dataFetcher(undefined, rootDoc, nodes, edges);
|
||||
|
||||
|
||||
return {nodes, edges, other: {}};
|
||||
}
|
||||
|
||||
export default {
|
||||
getConfig: () => getConfig().state,
|
||||
getData,
|
||||
addState,
|
||||
clear,
|
||||
getState,
|
||||
|
@@ -3,7 +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-v2.js';
|
||||
import renderer from './stateRenderer-v3-unified.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
|
@@ -1,28 +1,12 @@
|
||||
import { log } from '../../logger.js';
|
||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||
import type { LayoutData, LayoutMethod } from '../../rendering-util/types';
|
||||
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';
|
||||
|
||||
interface LayoutData {}
|
||||
interface RenderData {}
|
||||
type LayoutMethod =
|
||||
| 'dagre'
|
||||
| 'dagre-wrapper'
|
||||
| 'elk'
|
||||
| 'neato'
|
||||
| 'dot'
|
||||
| 'circo'
|
||||
| 'fdp'
|
||||
| 'osage'
|
||||
| 'grid';
|
||||
|
||||
const performLayout = (
|
||||
layoutData: LayoutData,
|
||||
id: string,
|
||||
_version: string,
|
||||
layoutMethod: LayoutMethod
|
||||
): RenderData => {
|
||||
return {};
|
||||
};
|
||||
const performRender = (data: RenderData) => {};
|
||||
|
||||
// Configuration
|
||||
const conf: Record<string, any> = {};
|
||||
@@ -44,6 +28,7 @@ export const getClasses = function (
|
||||
|
||||
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
|
||||
@@ -51,10 +36,11 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
// 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();
|
||||
|
||||
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
|
||||
const data4Rendering = performLayout(data4Layout, id, _version, 'dagre-wrapper');
|
||||
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
|
||||
performRender(data4Rendering);
|
||||
|
14
packages/mermaid/src/rendering-util/doLayout.ts
Normal file
14
packages/mermaid/src/rendering-util/doLayout.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { LayoutData, LayoutMethod, RenderData } from './types';
|
||||
|
||||
const layoutAlgorithms = {} as Record<string, any>;
|
||||
|
||||
const performLayout = (
|
||||
layoutData: LayoutData,
|
||||
id: string,
|
||||
_version: string,
|
||||
layoutMethod: LayoutMethod
|
||||
): RenderData => {
|
||||
console.log('Performing layout', layoutData, id, _version, layoutMethod);
|
||||
return { items: [], otherDetails:{} };
|
||||
};
|
||||
export default performLayout;
|
53
packages/mermaid/src/rendering-util/inserElementsForSize.js
Normal file
53
packages/mermaid/src/rendering-util/inserElementsForSize.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// import type { LayoutData } from './types';
|
||||
import { select } from 'd3';
|
||||
import { insertNode } from '../dagre-wrapper/nodes.js'
|
||||
|
||||
// export const getDiagramElements = (id: string, securityLevel: any) => {
|
||||
export const getDiagramElements = (id, securityLevel) => {
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
console.log('SVG:', svg, svg.node(), 'id:',id,'root:', root, root.node());
|
||||
|
||||
// console.log('SVG:', svg, svg.node(), 'root:', root, 'sandboxElement:', sandboxElement, 'id:', id, 'securityLevel:', securityLevel);
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
|
||||
// @ts-ignore todo: fix this
|
||||
const element = root.select('#' + id + ' g');
|
||||
return { svg, element };
|
||||
}
|
||||
|
||||
// export function insertElementsForSize(el: SVGElement, data: LayoutData): void {
|
||||
export function insertElementsForSize(el, data) {
|
||||
const nodesElem = el.insert('g').attr('class', 'nodes');
|
||||
const edgesElem = el.insert('g').attr('class', 'edges');
|
||||
console.log('Inserting elements for size:', data);
|
||||
data.nodes.forEach(async item => {
|
||||
item.shape = 'rect';
|
||||
console.log('Inserting node id:', item.id, 'shape:', item.shape);
|
||||
const e = await insertNode(nodesElem, {...item, class: 'default flowchart-label', labelStyle: '', x:0, y:0, width: 100,rx:0,ry:0, height: 100, shape: 'rect', padding:8});
|
||||
console.log('Inserted node:', e, e.node());
|
||||
// Create a new DOM element
|
||||
// const element = document.createElement('div');
|
||||
|
||||
// // Set the content of the element to the name of the item
|
||||
// element.textContent = item.name;
|
||||
|
||||
// // Set the size of the element to the size of the item
|
||||
// element.style.width = `${item.size}px`;
|
||||
// element.style.height = `${item.size}px`;
|
||||
|
||||
// Append the element to the body of the document
|
||||
// document.body.appendChild(element);
|
||||
});
|
||||
console.log('Element', el, 'data:', data);
|
||||
}
|
||||
|
||||
export default insertElementsForSize;
|
187
packages/mermaid/src/rendering-util/layout-algorithms/dagre.js
Normal file
187
packages/mermaid/src/rendering-util/layout-algorithms/dagre.js
Normal file
@@ -0,0 +1,187 @@
|
||||
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 { 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';
|
||||
|
||||
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 (elem, graph, markers, diagramtype, id) => {
|
||||
insertMarkers(elem, markers, diagramtype, id);
|
||||
clearNodes();
|
||||
clearEdges();
|
||||
clearClusters();
|
||||
clearGraphlib();
|
||||
|
||||
log.warn('Graph at first:', JSON.stringify(graphlibJson.write(graph)));
|
||||
adjustClustersAndEdges(graph);
|
||||
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
|
||||
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
|
||||
const siteConfig = getConfig();
|
||||
await recursiveRender(elem, graph, diagramtype, id, undefined, siteConfig);
|
||||
};
|
||||
|
||||
// const shapeDefinitions = {};
|
||||
// export const addShape = ({ shapeType: fun }) => {
|
||||
// shapeDefinitions[shapeType] = fun;
|
||||
// };
|
||||
|
||||
// const arrowDefinitions = {};
|
||||
// export const addArrow = ({ arrowType: fun }) => {
|
||||
// arrowDefinitions[arrowType] = fun;
|
||||
// };
|
3
packages/mermaid/src/rendering-util/performRender.ts
Normal file
3
packages/mermaid/src/rendering-util/performRender.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { RenderData } from './types';
|
||||
const performRender = (data: RenderData) => { };
|
||||
export default performRender;
|
126
packages/mermaid/src/rendering-util/types.d.ts
vendored
126
packages/mermaid/src/rendering-util/types.d.ts
vendored
@@ -6,3 +6,129 @@ export interface MarkdownWord {
|
||||
export type MarkdownLine = MarkdownWord[];
|
||||
/** Returns `true` if the line fits a constraint (e.g. it's under 𝑛 chars) */
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Extending the Node interface for specific types if needed
|
||||
interface ClassDiagramNode extends Node {
|
||||
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
|
||||
}
|
||||
|
||||
export interface RenderData {
|
||||
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'
|
||||
| 'elk'
|
||||
| 'neato'
|
||||
| 'dot'
|
||||
| 'circo'
|
||||
| 'fdp'
|
||||
| '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');
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user