mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-14 04:49:44 +02:00
Add support for new renderer
This commit is contained in:
@@ -1,9 +1,8 @@
|
|||||||
import type { Selection } from 'd3';
|
import { select, type Selection } from 'd3';
|
||||||
import { select } from 'd3';
|
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import common from '../common/common.js';
|
import common from '../common/common.js';
|
||||||
import utils from '../../utils.js';
|
import utils, { getEdgeId } from '../../utils.js';
|
||||||
import {
|
import {
|
||||||
setAccTitle,
|
setAccTitle,
|
||||||
getAccTitle,
|
getAccTitle,
|
||||||
@@ -21,12 +20,15 @@ import type {
|
|||||||
ClassMap,
|
ClassMap,
|
||||||
NamespaceMap,
|
NamespaceMap,
|
||||||
NamespaceNode,
|
NamespaceNode,
|
||||||
|
StyleClass,
|
||||||
} from './classTypes.js';
|
} from './classTypes.js';
|
||||||
|
import type { Node, Edge } from '../../rendering-util/types.js';
|
||||||
|
|
||||||
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
||||||
|
|
||||||
let relations: ClassRelation[] = [];
|
let relations: ClassRelation[] = [];
|
||||||
let classes = new Map<string, ClassNode>();
|
let classes = new Map<string, ClassNode>();
|
||||||
|
const styleClasses = new Map<string, StyleClass>();
|
||||||
let notes: ClassNote[] = [];
|
let notes: ClassNote[] = [];
|
||||||
let classCounter = 0;
|
let classCounter = 0;
|
||||||
let namespaces = new Map<string, NamespaceNode>();
|
let namespaces = new Map<string, NamespaceNode>();
|
||||||
@@ -59,7 +61,7 @@ export const setClassLabel = function (_id: string, label: string) {
|
|||||||
const { className } = splitClassNameAndType(id);
|
const { className } = splitClassNameAndType(id);
|
||||||
classes.get(className)!.label = label;
|
classes.get(className)!.label = label;
|
||||||
classes.get(className)!.text =
|
classes.get(className)!.text =
|
||||||
`<strong>${label}${classes.get(className)!.type ? `<${classes.get(className)!.type}>` : ''}</strong>`;
|
`${label}${classes.get(className)!.type ? `<${classes.get(className)!.type}>` : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +84,7 @@ export const addClass = function (_id: string) {
|
|||||||
id: name,
|
id: name,
|
||||||
type: type,
|
type: type,
|
||||||
label: name,
|
label: name,
|
||||||
text: `<strong>${name}${type ? `<${type}>` : ''}</strong>`,
|
text: `${name}${type ? `<${type}>` : ''}`,
|
||||||
shape: 'classBox',
|
shape: 'classBox',
|
||||||
cssClasses: [],
|
cssClasses: [],
|
||||||
methods: [],
|
methods: [],
|
||||||
@@ -238,6 +240,36 @@ export const setCssClass = function (ids: string, className: string) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defineClass = function (ids: string[], style: string[]) {
|
||||||
|
for (const id of ids) {
|
||||||
|
let styleClass = styleClasses.get(id);
|
||||||
|
if (styleClass === undefined) {
|
||||||
|
styleClass = { id, styles: [], textStyles: [] };
|
||||||
|
styleClasses.set(id, styleClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style !== undefined && style !== null) {
|
||||||
|
style.forEach(function (s) {
|
||||||
|
if (/color/.exec(s)) {
|
||||||
|
const newStyle = s.replace('fill', 'bgFill'); // .replace('color', 'fill');
|
||||||
|
styleClass.textStyles.push(newStyle);
|
||||||
|
}
|
||||||
|
styleClass.styles.push(s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [, value] of classes) {
|
||||||
|
if (value.cssClasses.includes(id)) {
|
||||||
|
for (const s of style) {
|
||||||
|
for (const k of s.split(',')) {
|
||||||
|
value.styles.push(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by parser when a tooltip is found, e.g. a clickable element.
|
* Called by parser when a tooltip is found, e.g. a clickable element.
|
||||||
*
|
*
|
||||||
@@ -476,9 +508,131 @@ export const setCssStyle = function (id: string, styles: string[]) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the arrow marker for a type index
|
||||||
|
*
|
||||||
|
* @param type - The type to look for
|
||||||
|
* @returns The arrow marker
|
||||||
|
*/
|
||||||
|
function getArrowMarker(type: number) {
|
||||||
|
let marker;
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
marker = 'aggregation';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
marker = 'extension';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
marker = 'composition';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
marker = 'dependency';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
marker = 'lollipop';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
marker = 'none';
|
||||||
|
}
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
export const getData = () => {
|
export const getData = () => {
|
||||||
|
const nodes: Node[] = [];
|
||||||
|
const edges: Edge[] = [];
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
return { nodes: classes, edges: relations, other: {}, config, direction: getDirection() };
|
|
||||||
|
for (const namespaceKey of namespaces.keys()) {
|
||||||
|
const namespace = namespaces.get(namespaceKey);
|
||||||
|
if (namespace) {
|
||||||
|
const node: Node = {
|
||||||
|
id: namespace.id,
|
||||||
|
label: namespace.id,
|
||||||
|
isGroup: false,
|
||||||
|
// parent node must be one of [rect, roundedWithTitle, noteGroup, divider]
|
||||||
|
shape: 'rect',
|
||||||
|
cssStyles: ['fill: none', 'stroke: black'],
|
||||||
|
look: config.look,
|
||||||
|
};
|
||||||
|
nodes.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const classKey of classes.keys()) {
|
||||||
|
const classNode = classes.get(classKey);
|
||||||
|
if (classNode) {
|
||||||
|
const node = classNode as unknown as Node;
|
||||||
|
node.parentId = classNode.parent;
|
||||||
|
nodes.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cnt = 0;
|
||||||
|
for (const note of notes) {
|
||||||
|
cnt++;
|
||||||
|
const noteNode: Node = {
|
||||||
|
id: note.id,
|
||||||
|
label: note.text.replaceAll('\\n', '<br>'), // 'rect' shape label sanitizes these newlines so must change to <br> manually
|
||||||
|
isGroup: false,
|
||||||
|
shape: 'rect',
|
||||||
|
padding: config.class!.padding ?? 6,
|
||||||
|
cssStyles: ['text-align: left'],
|
||||||
|
look: config.look,
|
||||||
|
};
|
||||||
|
nodes.push(noteNode);
|
||||||
|
|
||||||
|
const noteClassId = classes.get(note.class)?.id ?? '';
|
||||||
|
|
||||||
|
if (noteClassId) {
|
||||||
|
const edge: Edge = {
|
||||||
|
id: `edgeNote${cnt}`,
|
||||||
|
start: note.id,
|
||||||
|
end: noteClassId,
|
||||||
|
type: 'normal',
|
||||||
|
thickness: 'normal',
|
||||||
|
classes: 'relation',
|
||||||
|
arrowTypeStart: 'none',
|
||||||
|
arrowTypeEnd: 'none',
|
||||||
|
arrowheadStyle: '',
|
||||||
|
labelStyle: [''],
|
||||||
|
style: ['fill: none'],
|
||||||
|
pattern: 'dotted',
|
||||||
|
look: config.look,
|
||||||
|
};
|
||||||
|
edges.push(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
for (const relation of relations) {
|
||||||
|
cnt++;
|
||||||
|
const edge: Edge = {
|
||||||
|
id: getEdgeId(relation.id1, relation.id2, {
|
||||||
|
prefix: 'id',
|
||||||
|
counter: cnt,
|
||||||
|
}),
|
||||||
|
start: relation.id1,
|
||||||
|
end: relation.id2,
|
||||||
|
type: 'normal',
|
||||||
|
label: relation.title,
|
||||||
|
labelpos: 'c',
|
||||||
|
thickness: 'normal',
|
||||||
|
classes: 'relation',
|
||||||
|
arrowTypeStart: getArrowMarker(relation.relation.type1),
|
||||||
|
arrowTypeEnd: getArrowMarker(relation.relation.type2),
|
||||||
|
startLabelRight: relation.relationTitle1 === 'none' ? '' : relation.relationTitle1,
|
||||||
|
endLabelLeft: relation.relationTitle2 === 'none' ? '' : relation.relationTitle2,
|
||||||
|
arrowheadStyle: '',
|
||||||
|
labelStyle: ['display: inline-block'],
|
||||||
|
style: relation.style || '',
|
||||||
|
pattern: relation.relation.lineType == 1 ? 'dashed' : 'solid',
|
||||||
|
look: config.look,
|
||||||
|
};
|
||||||
|
edges.push(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { nodes, edges, other: {}, config, direction: getDirection() };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -506,6 +660,7 @@ export default {
|
|||||||
relationType,
|
relationType,
|
||||||
setClickEvent,
|
setClickEvent,
|
||||||
setCssClass,
|
setCssClass,
|
||||||
|
defineClass,
|
||||||
setLink,
|
setLink,
|
||||||
getTooltip,
|
getTooltip,
|
||||||
setTooltip,
|
setTooltip,
|
||||||
|
@@ -3,7 +3,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
|||||||
import parser from './parser/classDiagram.jison';
|
import parser from './parser/classDiagram.jison';
|
||||||
import db from './classDb.js';
|
import db from './classDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
import renderer from './classRenderer.js';
|
import renderer from './classRenderer-v3-unified.js';
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
export const diagram: DiagramDefinition = {
|
||||||
parser,
|
parser,
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
|
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
|
||||||
import { render } from '../../rendering-util/render.js';
|
import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js';
|
||||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
||||||
import type { LayoutData } from '../../rendering-util/types.js';
|
import type { LayoutData } from '../../rendering-util/types.js';
|
||||||
import utils from '../../utils.js';
|
import utils from '../../utils.js';
|
||||||
@@ -16,7 +16,7 @@ import utils from '../../utils.js';
|
|||||||
* @param defaultDir - the direction to use if none is found
|
* @param defaultDir - the direction to use if none is found
|
||||||
* @returns The direction to use
|
* @returns The direction to use
|
||||||
*/
|
*/
|
||||||
export const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
export const getDir = (parsedItem: any, defaultDir = 'TB') => {
|
||||||
if (!parsedItem.doc) {
|
if (!parsedItem.doc) {
|
||||||
return defaultDir;
|
return defaultDir;
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,6 @@ export const getClasses = function (
|
|||||||
text: string,
|
text: string,
|
||||||
diagramObj: any
|
diagramObj: any
|
||||||
): Map<string, DiagramStyleClassDef> {
|
): Map<string, DiagramStyleClassDef> {
|
||||||
// diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
|
||||||
return diagramObj.db.getClasses();
|
return diagramObj.db.getClasses();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,29 +47,25 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
// Not related to the refactoring, but this is the first step in the rendering process
|
// Not related to the refactoring, but this is the first step in the rendering process
|
||||||
// diag.db.extract(diag.db.getRootDocV2());
|
// diag.db.extract(diag.db.getRootDocV2());
|
||||||
|
|
||||||
//const DIR = getDir(diag.db.getRootDocV2());
|
|
||||||
|
|
||||||
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||||
// into the Layout data format
|
// into the Layout data format
|
||||||
const data4Layout = diag.db.getData() as LayoutData;
|
const data4Layout = diag.db.getData() as LayoutData;
|
||||||
|
|
||||||
// Create the root SVG - the element is the div containing the SVG element
|
// Create the root SVG - the element is the div containing the SVG element
|
||||||
const { element, svg } = getDiagramElements(id, securityLevel);
|
const svg = getDiagramElement(id, securityLevel);
|
||||||
|
|
||||||
data4Layout.type = diag.type;
|
data4Layout.type = diag.type;
|
||||||
data4Layout.layoutAlgorithm = layout;
|
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
|
||||||
|
|
||||||
// TODO: Should we move these two to baseConfig? These types are not there in StateConfig.
|
|
||||||
|
|
||||||
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||||
data4Layout.markers = ['barb'];
|
data4Layout.markers = ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'];
|
||||||
data4Layout.diagramId = id;
|
data4Layout.diagramId = id;
|
||||||
await render(data4Layout, svg, element);
|
await render(data4Layout, svg);
|
||||||
const padding = 8;
|
const padding = 8;
|
||||||
utils.insertTitle(
|
utils.insertTitle(
|
||||||
element,
|
svg,
|
||||||
'statediagramTitleText',
|
'classDiagramTitleText',
|
||||||
conf?.titleTopMargin ?? 25,
|
conf?.titleTopMargin ?? 25,
|
||||||
diag.db.getDiagramTitle()
|
diag.db.getDiagramTitle()
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user