mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
#5237 Removed style, class, labelText and props from node
This commit is contained in:
parent
4463e9d7a3
commit
b6ef7367c2
@ -76,7 +76,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"layout": "stress"} }%%
|
||||
%%{init: {"layout": "elk"} }%%
|
||||
stateDiagram
|
||||
[*] --> T1
|
||||
T1 --> T2
|
||||
@ -531,7 +531,7 @@ mindmap
|
||||
mermaid.initialize({
|
||||
// theme: 'dark',
|
||||
handdrawnSeed: 12,
|
||||
look: 'handdrawn',
|
||||
// look: 'handdrawn',
|
||||
// layout: 'dagre',
|
||||
layout: 'elk',
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
|
392
packages/mermaid/src/diagrams/state/dataFetcher.js
Normal file
392
packages/mermaid/src/diagrams/state/dataFetcher.js
Normal file
@ -0,0 +1,392 @@
|
||||
import { log } from '../../logger.js';
|
||||
import common from '../common/common.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
|
||||
import {
|
||||
DEFAULT_DIAGRAM_DIRECTION,
|
||||
STMT_STATE,
|
||||
STMT_RELATION,
|
||||
STMT_CLASSDEF,
|
||||
STMT_APPLYCLASS,
|
||||
DEFAULT_STATE_TYPE,
|
||||
DIVIDER_TYPE,
|
||||
G_EDGE_STYLE,
|
||||
G_EDGE_ARROWHEADSTYLE,
|
||||
G_EDGE_LABELPOS,
|
||||
G_EDGE_LABELTYPE,
|
||||
G_EDGE_THICKNESS,
|
||||
CSS_EDGE,
|
||||
DEFAULT_NESTED_DOC_DIR,
|
||||
SHAPE_DIVIDER,
|
||||
SHAPE_GROUP,
|
||||
CSS_DIAGRAM_CLUSTER,
|
||||
CSS_DIAGRAM_CLUSTER_ALT,
|
||||
CSS_DIAGRAM_STATE,
|
||||
SHAPE_STATE_WITH_DESC,
|
||||
SHAPE_STATE,
|
||||
SHAPE_START,
|
||||
SHAPE_END,
|
||||
SHAPE_NOTE,
|
||||
SHAPE_NOTEGROUP,
|
||||
CSS_DIAGRAM_NOTE,
|
||||
DOMID_TYPE_SPACER,
|
||||
DOMID_STATE,
|
||||
NOTE_ID,
|
||||
PARENT_ID,
|
||||
NOTE,
|
||||
PARENT,
|
||||
CSS_EDGE_NOTE_EDGE,
|
||||
} from './stateCommon.js';
|
||||
|
||||
// List of nodes created from the parsed diagram statement items
|
||||
let nodeDb = {};
|
||||
|
||||
let graphItemCount = 0; // used to construct ids, etc.
|
||||
|
||||
/**
|
||||
* Create a standard string for the dom ID of an item.
|
||||
* If a type is given, insert that before the counter, preceded by the type spacer
|
||||
*
|
||||
* @param itemId
|
||||
* @param counter
|
||||
* @param {string | null} type
|
||||
* @param typeSpacer
|
||||
* @returns {string}
|
||||
*/
|
||||
export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOMID_TYPE_SPACER) {
|
||||
const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : '';
|
||||
return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`;
|
||||
}
|
||||
|
||||
const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, useRough) => {
|
||||
// graphItemCount = 0;
|
||||
log.trace('items', doc);
|
||||
doc.forEach((item) => {
|
||||
switch (item.stmt) {
|
||||
case STMT_STATE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, useRough);
|
||||
break;
|
||||
case DEFAULT_STATE_TYPE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, useRough);
|
||||
break;
|
||||
case STMT_RELATION:
|
||||
{
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item.state1,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
useRough
|
||||
);
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item.state2,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
useRough
|
||||
);
|
||||
const edgeData = {
|
||||
id: 'edge' + graphItemCount,
|
||||
start: item.state1.id,
|
||||
end: item.state2.id,
|
||||
arrowhead: 'normal',
|
||||
arrowTypeEnd: 'arrow_barb',
|
||||
style: G_EDGE_STYLE,
|
||||
labelStyle: '',
|
||||
label: common.sanitizeText(item.description, getConfig()),
|
||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
||||
labelpos: G_EDGE_LABELPOS,
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
classes: CSS_EDGE,
|
||||
useRough,
|
||||
};
|
||||
edges.push(edgeData);
|
||||
//g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount);
|
||||
graphItemCount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 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, 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new list of classes.
|
||||
* In the future, this can be replaced with a class common to all diagrams.
|
||||
* ClassDef information = { id: id, styles: [], textStyles: [] }
|
||||
*
|
||||
* @returns {{}}
|
||||
*/
|
||||
function newClassesList() {
|
||||
return {};
|
||||
}
|
||||
|
||||
// let direction = DEFAULT_DIAGRAM_DIRECTION;
|
||||
// let rootDoc = [];
|
||||
let cssClasses = newClassesList(); // style classes defined by a classDef
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodes
|
||||
* @param nodeData
|
||||
*/
|
||||
function insertOrUpdateNode(nodes, nodeData) {
|
||||
if (!nodeData.id || nodeData.id === '</join></fork>' || nodeData.id === '</choice>') {
|
||||
return;
|
||||
}
|
||||
|
||||
//Populate node style attributes if nodeData has classes defined
|
||||
if (nodeData.cssClasses) {
|
||||
nodeData.cssClasses.split(' ').forEach((cssClass) => {
|
||||
if (cssClasses[cssClass]) {
|
||||
cssClasses[cssClass].styles.forEach((style) => {
|
||||
// Populate nodeData with style attributes specifically to be used by rough.js
|
||||
if (style && style.startsWith('fill:')) {
|
||||
nodeData.backgroundColor = style.replace('fill:', '');
|
||||
}
|
||||
if (style && style.startsWith('stroke:')) {
|
||||
nodeData.borderColor = style.replace('stroke:', '');
|
||||
}
|
||||
if (style && style.startsWith('stroke-width:')) {
|
||||
nodeData.borderWidth = style.replace('stroke-width:', '');
|
||||
}
|
||||
|
||||
nodeData.cssStyles += style + ';';
|
||||
});
|
||||
cssClasses[cssClass].textStyles.forEach((style) => {
|
||||
nodeData.labelStyle += style + ';';
|
||||
if (style && style.startsWith('fill:')) {
|
||||
nodeData.labelTextColor = style.replace('fill:', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const existingNodeData = nodes.find((node) => node.id === nodeData.id);
|
||||
if (existingNodeData) {
|
||||
//update the existing nodeData
|
||||
Object.assign(existingNodeData, nodeData);
|
||||
} else {
|
||||
nodes.push(nodeData);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get classes from the db for the info item.
|
||||
* If there aren't any or if dbInfoItem isn't defined, return an empty string.
|
||||
* Else create 1 string from the list of classes found
|
||||
*
|
||||
* @param {undefined | null | object} dbInfoItem
|
||||
* @returns {string}
|
||||
*/
|
||||
function getClassesFromDbInfo(dbInfoItem) {
|
||||
if (dbInfoItem === undefined || dbInfoItem === null) {
|
||||
return '';
|
||||
} else {
|
||||
if (dbInfoItem.cssClasses) {
|
||||
return dbInfoItem.cssClasses.join(' ');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, altFlag, useRough) => {
|
||||
const itemId = parsedItem.id;
|
||||
const classStr = getClassesFromDbInfo(diagramStates[itemId]);
|
||||
|
||||
if (itemId !== 'root') {
|
||||
let shape = SHAPE_STATE;
|
||||
if (parsedItem.start === true) {
|
||||
shape = SHAPE_START;
|
||||
}
|
||||
if (parsedItem.start === false) {
|
||||
shape = SHAPE_END;
|
||||
}
|
||||
if (parsedItem.type !== DEFAULT_STATE_TYPE) {
|
||||
shape = parsedItem.type;
|
||||
}
|
||||
|
||||
// Add the node to our list (nodeDb)
|
||||
if (!nodeDb[itemId]) {
|
||||
nodeDb[itemId] = {
|
||||
id: itemId,
|
||||
shape,
|
||||
description: common.sanitizeText(itemId, getConfig()),
|
||||
cssClasses: `${classStr} ${CSS_DIAGRAM_STATE}`,
|
||||
};
|
||||
}
|
||||
|
||||
const newNode = nodeDb[itemId];
|
||||
console.log('New Node:', newNode);
|
||||
|
||||
// Save data for description and group so that for instance a statement without description overwrites
|
||||
// one with description @todo TODO What does this mean? If important, add a test for it
|
||||
|
||||
// Build of the array of description strings
|
||||
if (parsedItem.description) {
|
||||
if (Array.isArray(newNode.description)) {
|
||||
// There already is an array of strings,add to it
|
||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
||||
newNode.description.push(parsedItem.description);
|
||||
} else {
|
||||
if (newNode.description?.length > 0) {
|
||||
// if there is a description already transform it to an array
|
||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
||||
if (newNode.description === itemId) {
|
||||
// If the previous description was this, remove it
|
||||
newNode.description = [parsedItem.description];
|
||||
} else {
|
||||
newNode.description = [newNode.description, parsedItem.description];
|
||||
}
|
||||
} else {
|
||||
newNode.shape = SHAPE_STATE;
|
||||
newNode.description = parsedItem.description;
|
||||
}
|
||||
}
|
||||
newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig());
|
||||
}
|
||||
|
||||
// If there's only 1 description entry, just use a regular state shape
|
||||
if (newNode.description?.length === 1 && newNode.shape === SHAPE_STATE_WITH_DESC) {
|
||||
newNode.shape = SHAPE_STATE;
|
||||
}
|
||||
|
||||
// group
|
||||
if (!newNode.type && parsedItem.doc) {
|
||||
log.info('Setting cluster for ', itemId, getDir(parsedItem));
|
||||
newNode.type = 'group';
|
||||
newNode.dir = getDir(parsedItem);
|
||||
newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
||||
newNode.cssClasses =
|
||||
newNode.cssClasses +
|
||||
' ' +
|
||||
CSS_DIAGRAM_CLUSTER +
|
||||
' ' +
|
||||
(altFlag ? CSS_DIAGRAM_CLUSTER_ALT : '');
|
||||
}
|
||||
|
||||
// This is what will be added to the graph
|
||||
const nodeData = {
|
||||
labelStyle: '',
|
||||
shape: newNode.shape,
|
||||
label: newNode.description,
|
||||
cssClasses: newNode.cssClasses,
|
||||
cssStyles: '',
|
||||
id: itemId,
|
||||
dir: newNode.dir,
|
||||
domId: stateDomId(itemId, graphItemCount),
|
||||
type: newNode.type,
|
||||
padding: 15,
|
||||
rx: 10,
|
||||
ry: 10,
|
||||
useRough,
|
||||
};
|
||||
|
||||
if (parent && parent.id !== 'root') {
|
||||
log.trace('Setting node ', itemId, ' to be child of its parent ', parent.id);
|
||||
nodeData.parentId = parent.id;
|
||||
}
|
||||
|
||||
nodeData.centerLabel = true;
|
||||
|
||||
if (parsedItem.note) {
|
||||
// Todo: set random id
|
||||
const noteData = {
|
||||
labelStyle: '',
|
||||
shape: SHAPE_NOTE,
|
||||
label: parsedItem.note.text,
|
||||
cssClasses: CSS_DIAGRAM_NOTE,
|
||||
// useHtmlLabels: false,
|
||||
cssStyles: '', // styles.style,
|
||||
id: itemId + NOTE_ID + '-' + graphItemCount,
|
||||
domId: stateDomId(itemId, graphItemCount, NOTE),
|
||||
type: newNode.type,
|
||||
padding: 15, //getConfig().flowchart.padding
|
||||
useRough,
|
||||
};
|
||||
const groupData = {
|
||||
labelStyle: '',
|
||||
shape: SHAPE_NOTEGROUP,
|
||||
label: parsedItem.note.text,
|
||||
cssClasses: newNode.cssClasses,
|
||||
cssStyles: '', // styles.style,
|
||||
id: itemId + PARENT_ID,
|
||||
domId: stateDomId(itemId, graphItemCount, PARENT),
|
||||
type: 'group',
|
||||
padding: 0, //getConfig().flowchart.padding
|
||||
useRough,
|
||||
};
|
||||
graphItemCount++;
|
||||
|
||||
const parentNodeId = itemId + PARENT_ID;
|
||||
|
||||
//add parent id to groupData
|
||||
groupData.id = parentNodeId;
|
||||
//add parent id to noteData
|
||||
noteData.parentId = parentNodeId;
|
||||
|
||||
//insert groupData
|
||||
insertOrUpdateNode(nodes, groupData);
|
||||
//insert noteData
|
||||
insertOrUpdateNode(nodes, noteData);
|
||||
//insert nodeData
|
||||
insertOrUpdateNode(nodes, nodeData);
|
||||
|
||||
let from = itemId;
|
||||
let to = noteData.id;
|
||||
|
||||
if (parsedItem.note.position === 'left of') {
|
||||
from = noteData.id;
|
||||
to = itemId;
|
||||
}
|
||||
|
||||
edges.push({
|
||||
id: from + '-' + to,
|
||||
start: from,
|
||||
end: to,
|
||||
arrowhead: 'none',
|
||||
arrowTypeEnd: '',
|
||||
style: G_EDGE_STYLE,
|
||||
labelStyle: '',
|
||||
classes: CSS_EDGE_NOTE_EDGE,
|
||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
||||
labelpos: G_EDGE_LABELPOS,
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
useRough,
|
||||
});
|
||||
} else {
|
||||
insertOrUpdateNode(nodes, nodeData);
|
||||
}
|
||||
|
||||
console.log('Nodes:', nodes);
|
||||
}
|
||||
if (parsedItem.doc) {
|
||||
log.trace('Adding nodes children ');
|
||||
setupDoc(parsedItem, parsedItem.doc, diagramStates, nodes, edges, !altFlag, useRough);
|
||||
}
|
||||
};
|
@ -11,6 +11,7 @@ import {
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import { dataFetcher } from './dataFetcher.js';
|
||||
|
||||
import {
|
||||
DEFAULT_DIAGRAM_DIRECTION,
|
||||
@ -75,10 +76,6 @@ let rootDoc = [];
|
||||
let classes = newClassesList(); // style classes defined by a classDef
|
||||
|
||||
// --------------------------------------
|
||||
// List of nodes created from the parsed diagram statement items
|
||||
let nodeDb = {};
|
||||
|
||||
let graphItemCount = 0; // used to construct ids, etc.
|
||||
|
||||
const newDoc = () => {
|
||||
return {
|
||||
@ -574,300 +571,6 @@ const setDirection = (dir) => {
|
||||
|
||||
const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim());
|
||||
|
||||
const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, altFlag, useRough) => {
|
||||
const itemId = parsedItem.id;
|
||||
const classStr = getClassesFromDbInfo(diagramStates[itemId]);
|
||||
|
||||
if (itemId !== 'root') {
|
||||
let shape = SHAPE_STATE;
|
||||
if (parsedItem.start === true) {
|
||||
shape = SHAPE_START;
|
||||
}
|
||||
if (parsedItem.start === false) {
|
||||
shape = SHAPE_END;
|
||||
}
|
||||
if (parsedItem.type !== DEFAULT_STATE_TYPE) {
|
||||
shape = parsedItem.type;
|
||||
}
|
||||
|
||||
// Add the node to our list (nodeDb)
|
||||
if (!nodeDb[itemId]) {
|
||||
nodeDb[itemId] = {
|
||||
id: itemId,
|
||||
shape,
|
||||
description: common.sanitizeText(itemId, getConfig()),
|
||||
classes: `${classStr} ${CSS_DIAGRAM_STATE}`,
|
||||
};
|
||||
}
|
||||
|
||||
const newNode = nodeDb[itemId];
|
||||
console.log('New Node:', newNode);
|
||||
|
||||
// Save data for description and group so that for instance a statement without description overwrites
|
||||
// one with description @todo TODO What does this mean? If important, add a test for it
|
||||
|
||||
// Build of the array of description strings
|
||||
if (parsedItem.description) {
|
||||
if (Array.isArray(newNode.description)) {
|
||||
// There already is an array of strings,add to it
|
||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
||||
newNode.description.push(parsedItem.description);
|
||||
} else {
|
||||
if (newNode.description?.length > 0) {
|
||||
// if there is a description already transform it to an array
|
||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
||||
if (newNode.description === itemId) {
|
||||
// If the previous description was this, remove it
|
||||
newNode.description = [parsedItem.description];
|
||||
} else {
|
||||
newNode.description = [newNode.description, parsedItem.description];
|
||||
}
|
||||
} else {
|
||||
newNode.shape = SHAPE_STATE;
|
||||
newNode.description = parsedItem.description;
|
||||
}
|
||||
}
|
||||
newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig());
|
||||
}
|
||||
|
||||
// If there's only 1 description entry, just use a regular state shape
|
||||
if (newNode.description?.length === 1 && newNode.shape === SHAPE_STATE_WITH_DESC) {
|
||||
newNode.shape = SHAPE_STATE;
|
||||
}
|
||||
|
||||
// group
|
||||
if (!newNode.type && parsedItem.doc) {
|
||||
log.info('Setting cluster for ', itemId, getDir(parsedItem));
|
||||
newNode.type = 'group';
|
||||
newNode.dir = getDir(parsedItem);
|
||||
newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
||||
newNode.classes =
|
||||
newNode.classes +
|
||||
' ' +
|
||||
CSS_DIAGRAM_CLUSTER +
|
||||
' ' +
|
||||
(altFlag ? CSS_DIAGRAM_CLUSTER_ALT : '');
|
||||
}
|
||||
|
||||
// This is what will be added to the graph
|
||||
const nodeData = {
|
||||
labelStyle: '',
|
||||
shape: newNode.shape,
|
||||
labelText: newNode.description,
|
||||
classes: newNode.classes,
|
||||
style: '',
|
||||
id: itemId,
|
||||
dir: newNode.dir,
|
||||
domId: stateDomId(itemId, graphItemCount),
|
||||
type: newNode.type,
|
||||
padding: 15,
|
||||
rx: 10,
|
||||
ry: 10,
|
||||
useRough,
|
||||
};
|
||||
|
||||
if (parent && parent.id !== 'root') {
|
||||
log.trace('Setting node ', itemId, ' to be child of its parent ', parent.id);
|
||||
nodeData.parentId = parent.id;
|
||||
}
|
||||
|
||||
nodeData.centerLabel = true;
|
||||
|
||||
if (parsedItem.note) {
|
||||
// Todo: set random id
|
||||
const noteData = {
|
||||
labelStyle: '',
|
||||
shape: SHAPE_NOTE,
|
||||
labelText: parsedItem.note.text,
|
||||
classes: CSS_DIAGRAM_NOTE,
|
||||
// useHtmlLabels: false,
|
||||
style: '', // styles.style,
|
||||
id: itemId + NOTE_ID + '-' + graphItemCount,
|
||||
domId: stateDomId(itemId, graphItemCount, NOTE),
|
||||
type: newNode.type,
|
||||
padding: 15, //getConfig().flowchart.padding
|
||||
useRough,
|
||||
};
|
||||
const groupData = {
|
||||
labelStyle: '',
|
||||
shape: SHAPE_NOTEGROUP,
|
||||
labelText: parsedItem.note.text,
|
||||
classes: newNode.classes,
|
||||
style: '', // styles.style,
|
||||
id: itemId + PARENT_ID,
|
||||
domId: stateDomId(itemId, graphItemCount, PARENT),
|
||||
type: 'group',
|
||||
padding: 0, //getConfig().flowchart.padding
|
||||
useRough,
|
||||
};
|
||||
graphItemCount++;
|
||||
|
||||
const parentNodeId = itemId + PARENT_ID;
|
||||
|
||||
//add parent id to groupData
|
||||
groupData.id = parentNodeId;
|
||||
//add parent id to noteData
|
||||
noteData.parentId = parentNodeId;
|
||||
|
||||
//insert groupData
|
||||
insertOrUpdateNode(nodes, groupData);
|
||||
//insert noteData
|
||||
insertOrUpdateNode(nodes, noteData);
|
||||
//insert nodeData
|
||||
insertOrUpdateNode(nodes, nodeData);
|
||||
|
||||
let from = itemId;
|
||||
let to = noteData.id;
|
||||
|
||||
if (parsedItem.note.position === 'left of') {
|
||||
from = noteData.id;
|
||||
to = itemId;
|
||||
}
|
||||
|
||||
edges.push({
|
||||
id: from + '-' + to,
|
||||
start: from,
|
||||
end: to,
|
||||
arrowhead: 'none',
|
||||
arrowTypeEnd: '',
|
||||
style: G_EDGE_STYLE,
|
||||
labelStyle: '',
|
||||
classes: CSS_EDGE_NOTE_EDGE,
|
||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
||||
labelpos: G_EDGE_LABELPOS,
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
useRough,
|
||||
});
|
||||
} else {
|
||||
insertOrUpdateNode(nodes, nodeData);
|
||||
}
|
||||
|
||||
console.log('Nodes:', nodes);
|
||||
}
|
||||
if (parsedItem.doc) {
|
||||
log.trace('Adding nodes children ');
|
||||
setupDoc(parsedItem, parsedItem.doc, diagramStates, nodes, edges, !altFlag, useRough);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodes
|
||||
* @param nodeData
|
||||
*/
|
||||
function insertOrUpdateNode(nodes, nodeData) {
|
||||
if (!nodeData.id || nodeData.id === '</join></fork>' || nodeData.id === '</choice>') {
|
||||
return;
|
||||
}
|
||||
|
||||
//Populate node style attributes if nodeData has classes defined
|
||||
if (nodeData.classes) {
|
||||
nodeData.classes.split(' ').forEach((cssClass) => {
|
||||
if (classes[cssClass]) {
|
||||
classes[cssClass].styles.forEach((style) => {
|
||||
// Populate nodeData with style attributes specifically to be used by rough.js
|
||||
if (style && style.startsWith('fill:')) {
|
||||
nodeData.backgroundColor = style.replace('fill:', '');
|
||||
}
|
||||
if (style && style.startsWith('stroke:')) {
|
||||
nodeData.borderColor = style.replace('stroke:', '');
|
||||
}
|
||||
if (style && style.startsWith('stroke-width:')) {
|
||||
nodeData.borderWidth = style.replace('stroke-width:', '');
|
||||
}
|
||||
|
||||
nodeData.style += style + ';';
|
||||
});
|
||||
classes[cssClass].textStyles.forEach((style) => {
|
||||
nodeData.labelStyle += style + ';';
|
||||
if (style && style.startsWith('fill:')) {
|
||||
nodeData.labelTextColor = style.replace('fill:', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const existingNodeData = nodes.find((node) => node.id === nodeData.id);
|
||||
if (existingNodeData) {
|
||||
//update the existing nodeData
|
||||
Object.assign(existingNodeData, nodeData);
|
||||
} else {
|
||||
nodes.push(nodeData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a standard string for the dom ID of an item.
|
||||
* If a type is given, insert that before the counter, preceded by the type spacer
|
||||
*
|
||||
* @param itemId
|
||||
* @param counter
|
||||
* @param {string | null} type
|
||||
* @param typeSpacer
|
||||
* @returns {string}
|
||||
*/
|
||||
export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOMID_TYPE_SPACER) {
|
||||
const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : '';
|
||||
return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`;
|
||||
}
|
||||
|
||||
const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, useRough) => {
|
||||
// graphItemCount = 0;
|
||||
log.trace('items', doc);
|
||||
doc.forEach((item) => {
|
||||
switch (item.stmt) {
|
||||
case STMT_STATE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, useRough);
|
||||
break;
|
||||
case DEFAULT_STATE_TYPE:
|
||||
dataFetcher(parentParsedItem, item, diagramStates, nodes, edges, altFlag, useRough);
|
||||
break;
|
||||
case STMT_RELATION:
|
||||
{
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item.state1,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
useRough
|
||||
);
|
||||
dataFetcher(
|
||||
parentParsedItem,
|
||||
item.state2,
|
||||
diagramStates,
|
||||
nodes,
|
||||
edges,
|
||||
altFlag,
|
||||
useRough
|
||||
);
|
||||
const edgeData = {
|
||||
id: 'edge' + graphItemCount,
|
||||
start: item.state1.id,
|
||||
end: item.state2.id,
|
||||
arrowhead: 'normal',
|
||||
arrowTypeEnd: 'arrow_barb',
|
||||
style: G_EDGE_STYLE,
|
||||
labelStyle: '',
|
||||
label: common.sanitizeText(item.description, getConfig()),
|
||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
||||
labelpos: G_EDGE_LABELPOS,
|
||||
labelType: G_EDGE_LABELTYPE,
|
||||
thickness: G_EDGE_THICKNESS,
|
||||
classes: CSS_EDGE,
|
||||
useRough,
|
||||
};
|
||||
edges.push(edgeData);
|
||||
//g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount);
|
||||
graphItemCount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const getData = () => {
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
@ -886,47 +589,6 @@ export const getData = () => {
|
||||
return { nodes, edges, other: {} };
|
||||
};
|
||||
|
||||
/**
|
||||
* 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, 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get classes from the db for the info item.
|
||||
* If there aren't any or if dbInfoItem isn't defined, return an empty string.
|
||||
* Else create 1 string from the list of classes found
|
||||
*
|
||||
* @param {undefined | null | object} dbInfoItem
|
||||
* @returns {string}
|
||||
*/
|
||||
function getClassesFromDbInfo(dbInfoItem) {
|
||||
if (dbInfoItem === undefined || dbInfoItem === null) {
|
||||
return '';
|
||||
} else {
|
||||
if (dbInfoItem.classes) {
|
||||
return dbInfoItem.classes.join(' ');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getConfig: () => getConfig().state,
|
||||
getData,
|
||||
|
@ -288,7 +288,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
||||
domId: specialId,
|
||||
id: specialId,
|
||||
labelStyle: '',
|
||||
labelText: edge.label,
|
||||
label: edge.label,
|
||||
padding: 0,
|
||||
shape: 'labelRect',
|
||||
style: '',
|
||||
@ -416,7 +416,7 @@ export const extractor = (graph, depth) => {
|
||||
clusterNode: true,
|
||||
id: node,
|
||||
clusterData: clusterDb[node].clusterData,
|
||||
labelText: clusterDb[node].labelText,
|
||||
label: clusterDb[node].label,
|
||||
graph: clusterGraph,
|
||||
});
|
||||
log.warn('New graph after copy node: (', node, ')', graphlibJson.write(clusterGraph));
|
||||
|
@ -386,7 +386,7 @@ flowchart TB
|
||||
*/
|
||||
|
||||
const exportedGraph = JSON.parse(
|
||||
'{"options":{"directed":true,"multigraph":true,"compound":true},"nodes":[{"v":"A","value":{"labelStyle":"","shape":"rect","labelText":"A","rx":0,"ry":0,"class":"default","style":"","id":"A","width":500,"type":"group","padding":15}},{"v":"B","value":{"labelStyle":"","shape":"rect","labelText":"B","rx":0,"ry":0,"class":"default","style":"","id":"B","width":500,"type":"group","padding":15},"parent":"A"},{"v":"b","value":{"labelStyle":"","shape":"rect","labelText":"b","rx":0,"ry":0,"class":"default","style":"","id":"b","padding":15},"parent":"A"},{"v":"c","value":{"labelStyle":"","shape":"rect","labelText":"c","rx":0,"ry":0,"class":"default","style":"","id":"c","padding":15},"parent":"B"},{"v":"a","value":{"labelStyle":"","shape":"rect","labelText":"a","rx":0,"ry":0,"class":"default","style":"","id":"a","padding":15},"parent":"A"}],"edges":[{"v":"b","w":"B","name":"1","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-b-B","classes":"flowchart-link LS-b LE-B"}},{"v":"a","w":"c","name":"2","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-a-c","classes":"flowchart-link LS-a LE-c"}}],"value":{"rankdir":"TB","nodesep":50,"ranksep":50,"marginx":8,"marginy":8}}'
|
||||
'{"options":{"directed":true,"multigraph":true,"compound":true},"nodes":[{"v":"A","value":{"labelStyle":"","shape":"rect","labelText":"A","rx":0,"ry":0,"cssClass":"default","style":"","id":"A","width":500,"type":"group","padding":15}},{"v":"B","value":{"labelStyle":"","shape":"rect","labelText":"B","rx":0,"ry":0,"class":"default","style":"","id":"B","width":500,"type":"group","padding":15},"parent":"A"},{"v":"b","value":{"labelStyle":"","shape":"rect","labelText":"b","rx":0,"ry":0,"class":"default","style":"","id":"b","padding":15},"parent":"A"},{"v":"c","value":{"labelStyle":"","shape":"rect","labelText":"c","rx":0,"ry":0,"class":"default","style":"","id":"c","padding":15},"parent":"B"},{"v":"a","value":{"labelStyle":"","shape":"rect","labelText":"a","rx":0,"ry":0,"class":"default","style":"","id":"a","padding":15},"parent":"A"}],"edges":[{"v":"b","w":"B","name":"1","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-b-B","cssClasses":"flowchart-link LS-b LE-B"}},{"v":"a","w":"c","name":"2","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-a-c","cssClasses":"flowchart-link LS-a LE-c"}}],"value":{"rankdir":"TB","nodesep":50,"ranksep":50,"marginx":8,"marginy":8}}'
|
||||
);
|
||||
const gr = graphlibJson.read(exportedGraph);
|
||||
|
||||
|
@ -14,10 +14,7 @@ const rect = (parent, node) => {
|
||||
const siteConfig = getConfig();
|
||||
|
||||
// Add outer g element
|
||||
const shapeSvg = parent
|
||||
.insert('g')
|
||||
.attr('class', 'cluster' + (node.class ? ' ' + node.class : ''))
|
||||
.attr('id', node.id);
|
||||
const shapeSvg = parent.insert('g').attr('class', 'cluster').attr('id', node.id);
|
||||
|
||||
// add the rect
|
||||
const rect = shapeSvg.insert('rect', ':first-child');
|
||||
@ -25,15 +22,15 @@ const rect = (parent, node) => {
|
||||
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
|
||||
const labelEl = shapeSvg.insert('g').attr('class', 'cluster-label');
|
||||
|
||||
// const text = label
|
||||
// .node()
|
||||
// .appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
||||
// .appendChild(createLabel(node.label, node.labelStyle, undefined, true));
|
||||
const text =
|
||||
node.labelType === 'markdown'
|
||||
? createText(label, node.labelText, { style: node.labelStyle, useHtmlLabels })
|
||||
: label.node().appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
||||
? createText(labelEl, node.label, { style: node.labelStyle, useHtmlLabels })
|
||||
: labelEl.node().appendChild(createLabel(node.label, node.labelStyle, undefined, true));
|
||||
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
@ -59,7 +56,7 @@ const rect = (parent, node) => {
|
||||
log.trace('Data ', node, JSON.stringify(node));
|
||||
// center the rect around its coordinate
|
||||
rect
|
||||
.attr('style', node.style)
|
||||
.attr('style', node.cssStyles)
|
||||
.attr('rx', node.rx)
|
||||
.attr('ry', node.ry)
|
||||
.attr('x', node.x - width / 2)
|
||||
@ -69,13 +66,13 @@ const rect = (parent, node) => {
|
||||
|
||||
const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
|
||||
if (useHtmlLabels) {
|
||||
label.attr(
|
||||
labelEl.attr(
|
||||
'transform',
|
||||
// This puts the label on top of the box instead of inside it
|
||||
`translate(${node.x - bbox.width / 2}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
|
||||
);
|
||||
} else {
|
||||
label.attr(
|
||||
labelEl.attr(
|
||||
'transform',
|
||||
// This puts the label on top of the box instead of inside it
|
||||
`translate(${node.x}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
|
||||
@ -154,7 +151,7 @@ const roundedWithTitle = (parent, node) => {
|
||||
themeVariables;
|
||||
|
||||
// Add outer g element
|
||||
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
|
||||
const shapeSvg = parent.insert('g').attr('class', node.cssClasses).attr('id', node.id);
|
||||
|
||||
// add the rect
|
||||
const outerRectG = shapeSvg.insert('g', ':first-child');
|
||||
@ -163,9 +160,7 @@ const roundedWithTitle = (parent, node) => {
|
||||
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
|
||||
let innerRect = shapeSvg.append('rect');
|
||||
|
||||
const text = label
|
||||
.node()
|
||||
.appendChild(createLabel(node.labelText, node.labelStyle, undefined, true));
|
||||
const text = label.node().appendChild(createLabel(node.label, node.labelStyle, undefined, true));
|
||||
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
@ -197,7 +192,7 @@ const roundedWithTitle = (parent, node) => {
|
||||
// add the rect
|
||||
let rect;
|
||||
if (node.useRough) {
|
||||
const isAlt = node.classes.includes('statediagram-cluster-alt');
|
||||
const isAlt = node.cssClasses.includes('statediagram-cluster-alt');
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const roughOuterNode =
|
||||
node.rx || node.ry
|
||||
@ -263,7 +258,7 @@ const roundedWithTitle = (parent, node) => {
|
||||
const divider = (parent, node) => {
|
||||
const { handdrawnSeed } = getConfig();
|
||||
// Add outer g element
|
||||
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
|
||||
const shapeSvg = parent.insert('g').attr('class', node.cssClasses).attr('id', node.id);
|
||||
|
||||
// add the rect
|
||||
let rect;
|
||||
@ -318,7 +313,7 @@ export const insertCluster = (elem, node) => {
|
||||
return cluster;
|
||||
};
|
||||
export const getClusterTitleWidth = (elem, node) => {
|
||||
const label = createLabel(node.labelText, node.labelStyle, undefined, true);
|
||||
const label = createLabel(node.label, node.labelStyle, undefined, true);
|
||||
elem.node().appendChild(label);
|
||||
const width = label.getBBox().width;
|
||||
elem.node().removeChild(label);
|
||||
|
@ -48,9 +48,9 @@ export const insertNode = async (elem, node, dir) => {
|
||||
if (node.tooltip) {
|
||||
el.attr('title', node.tooltip);
|
||||
}
|
||||
if (node.class) {
|
||||
el.attr('class', 'node default ' + node.class);
|
||||
}
|
||||
// if (node.class) {
|
||||
// el.attr('class', 'node default ' + node.class);
|
||||
// }
|
||||
|
||||
nodeElems[node.id] = newEl;
|
||||
|
||||
|
@ -16,12 +16,12 @@ export const note = async (parent: SVGAElement, node: Node) => {
|
||||
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||
parent,
|
||||
node,
|
||||
'node ' + node.classes,
|
||||
'node ' + node.cssClasses,
|
||||
true
|
||||
);
|
||||
|
||||
log.info('Classes = ', node.classes);
|
||||
const { style, useRough } = node;
|
||||
log.info('Classes = ', node.cssClasses);
|
||||
const { cssStyles, useRough } = node;
|
||||
let rect;
|
||||
const totalWidth = bbox.width + node.padding;
|
||||
const totalHeight = bbox.height + node.padding;
|
||||
@ -41,7 +41,7 @@ export const note = async (parent: SVGAElement, node: Node) => {
|
||||
});
|
||||
|
||||
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||
rect.attr('class', 'basic label-container').attr('style', style);
|
||||
rect.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||
} else {
|
||||
rect = shapeSvg.insert('rect', ':first-child');
|
||||
rect
|
||||
|
@ -65,7 +65,7 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
||||
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||
parent,
|
||||
node,
|
||||
'node ' + node.classes + ' ' + node.class,
|
||||
'node ' + node.cssClasses, // + ' ' + node.class,
|
||||
true
|
||||
);
|
||||
|
||||
@ -75,7 +75,7 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
||||
const y = -bbox.height / 2 - halfPadding;
|
||||
|
||||
let rect;
|
||||
const { rx, ry, style, useRough } = node;
|
||||
const { rx, ry, style: cssStyles, useRough } = node;
|
||||
if (useRough) {
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {
|
||||
@ -93,13 +93,13 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
||||
: rc.rectangle(x, y, totalWidth, totalHeight, options);
|
||||
|
||||
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||
rect.attr('class', 'basic label-container').attr('style', style);
|
||||
rect.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||
} else {
|
||||
rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
rect
|
||||
.attr('class', 'basic label-container')
|
||||
.attr('style', style)
|
||||
.attr('style', cssStyles)
|
||||
.attr('rx', rx)
|
||||
.attr('ry', ry)
|
||||
.attr('x', x)
|
||||
@ -108,16 +108,16 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
||||
.attr('height', totalHeight);
|
||||
}
|
||||
|
||||
if (node.props) {
|
||||
const propKeys = new Set(Object.keys(node.props));
|
||||
if (node.props.borders) {
|
||||
applyNodePropertyBorders(rect, node.props.borders + '', totalWidth, totalHeight);
|
||||
propKeys.delete('borders');
|
||||
}
|
||||
propKeys.forEach((propKey) => {
|
||||
log.warn(`Unknown node property ${propKey}`);
|
||||
});
|
||||
}
|
||||
// if (node.props) {
|
||||
// const propKeys = new Set(Object.keys(node.props));
|
||||
// if (node.props.borders) {
|
||||
// applyNodePropertyBorders(rect, node.props.borders + '', totalWidth, totalHeight);
|
||||
// propKeys.delete('borders');
|
||||
// }
|
||||
// propKeys.forEach((propKey) => {
|
||||
// log.warn(`Unknown node property ${propKey}`);
|
||||
// });
|
||||
// }
|
||||
|
||||
updateNodeBounds(node, rect);
|
||||
|
||||
@ -131,7 +131,7 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
||||
export const labelRect = async (parent: SVGElement, node: Node) => {
|
||||
const { shapeSvg } = await labelHelper(parent, node, 'label', true);
|
||||
|
||||
log.trace('Classes = ', node.class);
|
||||
// log.trace('Classes = ', node.class);
|
||||
// add the rect
|
||||
const rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
@ -141,16 +141,16 @@ export const labelRect = async (parent: SVGElement, node: Node) => {
|
||||
rect.attr('width', totalWidth).attr('height', totalHeight);
|
||||
shapeSvg.attr('class', 'label edgeLabel');
|
||||
|
||||
if (node.props) {
|
||||
const propKeys = new Set(Object.keys(node.props));
|
||||
if (node.props.borders) {
|
||||
applyNodePropertyBorders(rect, node.borders, totalWidth, totalHeight);
|
||||
propKeys.delete('borders');
|
||||
}
|
||||
propKeys.forEach((propKey) => {
|
||||
log.warn(`Unknown node property ${propKey}`);
|
||||
});
|
||||
}
|
||||
// if (node.props) {
|
||||
// const propKeys = new Set(Object.keys(node.props));
|
||||
// if (node.props.borders) {
|
||||
// applyNodePropertyBorders(rect, node.borders, totalWidth, totalHeight);
|
||||
// propKeys.delete('borders');
|
||||
// }
|
||||
// propKeys.forEach((propKey) => {
|
||||
// log.warn(`Unknown node property ${propKey}`);
|
||||
// });
|
||||
// }
|
||||
|
||||
updateNodeBounds(node, rect);
|
||||
|
||||
|
@ -6,48 +6,43 @@ import { evaluate, sanitizeText } from '$root/diagrams/common/common.js';
|
||||
import { decodeEntities } from '$root/utils.js';
|
||||
|
||||
export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
let classes;
|
||||
let cssClasses;
|
||||
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig().flowchart.htmlLabels);
|
||||
if (!_classes) {
|
||||
classes = 'node default';
|
||||
cssClasses = 'node default';
|
||||
} else {
|
||||
classes = _classes;
|
||||
cssClasses = _classes;
|
||||
}
|
||||
|
||||
// Add outer g element
|
||||
const shapeSvg = parent
|
||||
.insert('g')
|
||||
.attr('class', classes)
|
||||
.attr('class', cssClasses)
|
||||
.attr('id', node.domId || node.id);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const label = shapeSvg.insert('g').attr('class', 'label').attr('style', node.labelStyle);
|
||||
const labelEl = shapeSvg.insert('g').attr('class', 'label').attr('style', node.labelStyle);
|
||||
|
||||
// Replace labelText with default value if undefined
|
||||
let labelText;
|
||||
if (node.labelText === undefined) {
|
||||
labelText = '';
|
||||
// Replace label with default value if undefined
|
||||
let label;
|
||||
if (node.label === undefined) {
|
||||
label = '';
|
||||
} else {
|
||||
labelText = typeof node.labelText === 'string' ? node.labelText : node.labelText[0];
|
||||
label = typeof node.label === 'string' ? node.label : node.label[0];
|
||||
}
|
||||
|
||||
const textNode = label.node();
|
||||
const textNode = labelEl.node();
|
||||
let text;
|
||||
if (node.labelType === 'markdown') {
|
||||
// text = textNode;
|
||||
text = createText(label, sanitizeText(decodeEntities(labelText), getConfig()), {
|
||||
text = createText(labelEl, sanitizeText(decodeEntities(label), getConfig()), {
|
||||
useHtmlLabels,
|
||||
width: node.width || getConfig().flowchart.wrappingWidth,
|
||||
classes: 'markdown-node-label',
|
||||
cssClasses: 'markdown-node-label',
|
||||
});
|
||||
} else {
|
||||
text = textNode.appendChild(
|
||||
createLabel(
|
||||
sanitizeText(decodeEntities(labelText), getConfig()),
|
||||
node.labelStyle,
|
||||
false,
|
||||
isNode
|
||||
)
|
||||
createLabel(sanitizeText(decodeEntities(label), getConfig()), node.labelStyle, false, isNode)
|
||||
);
|
||||
}
|
||||
// Get the size of the label
|
||||
@ -61,7 +56,7 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
// if there are images, need to wait for them to load before getting the bounding box
|
||||
const images = div.getElementsByTagName('img');
|
||||
if (images) {
|
||||
const noImgText = labelText.replace(/<img[^>]*>/g, '').trim() === '';
|
||||
const noImgText = label.replace(/<img[^>]*>/g, '').trim() === '';
|
||||
|
||||
await Promise.all(
|
||||
[...images].map(
|
||||
@ -107,15 +102,15 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
|
||||
// Center the label
|
||||
if (useHtmlLabels) {
|
||||
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||
labelEl.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||
} else {
|
||||
label.attr('transform', 'translate(' + 0 + ', ' + -bbox.height / 2 + ')');
|
||||
labelEl.attr('transform', 'translate(' + 0 + ', ' + -bbox.height / 2 + ')');
|
||||
}
|
||||
if (node.centerLabel) {
|
||||
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||
labelEl.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||
}
|
||||
label.insert('rect', ':first-child');
|
||||
return { shapeSvg, bbox, halfPadding, label };
|
||||
labelEl.insert('rect', ':first-child');
|
||||
return { shapeSvg, bbox, halfPadding, label: labelEl };
|
||||
};
|
||||
|
||||
export const updateNodeBounds = (node, element) => {
|
||||
|
19
packages/mermaid/src/rendering-util/types.d.ts
vendored
19
packages/mermaid/src/rendering-util/types.d.ts
vendored
@ -14,25 +14,24 @@ interface Node {
|
||||
id: string;
|
||||
label?: string;
|
||||
parentId?: string;
|
||||
position?: string; //REMOVE
|
||||
position?: string; // Keep, this is for notes 'left of', 'right of', etc.
|
||||
cssStyles?: string; // Renamed from `styles` to `cssStyles`
|
||||
style?: string; //REMOVE
|
||||
cssClasses?: string; // Renamed from `classes` to `cssClasses`
|
||||
classes?: string; //REMOVE
|
||||
class?: string; //REMOVE
|
||||
// style?: string; //REMOVE
|
||||
// class?: string; //REMOVE
|
||||
// labelText?: string; //REMOVE, use `label` instead
|
||||
// props?: Record<string, unknown>; //REMOVE
|
||||
labelStyle?: string;
|
||||
labelText?: string; //REMOVE, use `label` instead
|
||||
|
||||
// Flowchart specific properties
|
||||
labelType?: string; // REMOVE? Always use markdown string, need to check for KaTeX
|
||||
labelType?: string; // REMOVE? Always use markdown string, need to check for KaTeX - wait with this one
|
||||
domId: string;
|
||||
// Rendering specific properties for both Flowchart and State Diagram nodes
|
||||
dir?: string; // Only relevant for isGroup true, i.e. a sub-graph or composite state.
|
||||
haveCallback?: boolean;
|
||||
link?: string;
|
||||
linkTarget?: string;
|
||||
padding?: number; //REMOVE, use from LayoutData.config
|
||||
props?: Record<string, unknown>; //REMOVE
|
||||
padding?: number; //REMOVE?, use from LayoutData.config - Keep, this could be shape specific
|
||||
shape?: string;
|
||||
tooltip?: string;
|
||||
type: string; // REMOVE, replace with isGroup: boolean, default false
|
||||
@ -137,8 +136,8 @@ export function createDomElement(node: Node): Node {
|
||||
element.id = node.domId;
|
||||
|
||||
// Optional: Apply styles and classes to the element
|
||||
if (node.styles) {
|
||||
element.style.cssText = node.styles;
|
||||
if (node.cssStyles) {
|
||||
element.style.cssText = node.cssStyles;
|
||||
}
|
||||
if (node.classes) {
|
||||
element.className = node.classes;
|
||||
|
945
pnpm-lock.yaml
generated
945
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user