mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Convert svgDraw.ts
This commit is contained in:
parent
75ec719257
commit
b51d8ff7ba
@ -1,12 +1,12 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import type { D3Element } from '../../mermaidAPI.js';
|
||||
import { sanitizeText } from '../../diagrams/common/common.js';
|
||||
import { log } from '../../logger.js';
|
||||
import type { D3Element } from '../../mermaidAPI.js';
|
||||
import type { MindMapNode } from './mindmapTypes.js';
|
||||
import type { MindmapNode } from './mindmapTypes.js';
|
||||
|
||||
let nodes: MindMapNode[] = [];
|
||||
let nodes: MindmapNode[] = [];
|
||||
let cnt = 0;
|
||||
let elements: Record<string, D3Element> = {};
|
||||
let elements: Record<number, D3Element> = {};
|
||||
|
||||
const clear = () => {
|
||||
nodes = [];
|
||||
@ -14,7 +14,7 @@ const clear = () => {
|
||||
elements = {};
|
||||
};
|
||||
|
||||
const getParent = function (level: number) {
|
||||
const getParent = function(level: number) {
|
||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||
if (nodes[i].level < level) {
|
||||
return nodes[i];
|
||||
@ -48,7 +48,7 @@ const addNode = (level: number, id: string, descr: string, type: number) => {
|
||||
children: [],
|
||||
width: conf.mindmap?.maxNodeWidth ?? 200,
|
||||
padding,
|
||||
} satisfies MindMapNode;
|
||||
} satisfies MindmapNode;
|
||||
|
||||
const parent = getParent(level);
|
||||
if (parent) {
|
||||
@ -100,7 +100,7 @@ const getType = (startStr: string, endStr: string): number => {
|
||||
}
|
||||
};
|
||||
|
||||
const setElementForId = (id: string, element: D3Element) => {
|
||||
const setElementForId = (id: number, element: D3Element) => {
|
||||
elements[id] = element;
|
||||
};
|
||||
|
||||
@ -141,7 +141,7 @@ const type2Str = (type: number) => {
|
||||
|
||||
// Expose logger to grammar
|
||||
const getLogger = () => log;
|
||||
const getElementById = (id: string) => elements[id];
|
||||
const getElementById = (id: number) => elements[id];
|
||||
|
||||
const db = {
|
||||
clear,
|
||||
|
@ -6,7 +6,7 @@ import { drawNode, positionNode } from './svgDraw.js';
|
||||
import cytoscape from 'cytoscape';
|
||||
// @ts-expect-error No types available
|
||||
import coseBilkent from 'cytoscape-cose-bilkent';
|
||||
import type { MindMapNode, MindmapDB } from './mindmapTypes.js';
|
||||
import type { MindmapNode, MindmapDB, FilledMindMapNode } from './mindmapTypes.js';
|
||||
import type { MermaidConfig } from '../../config.type.js';
|
||||
import type { Diagram } from '../../Diagram.js';
|
||||
import type { D3Element } from '../../mermaidAPI.js';
|
||||
@ -18,9 +18,9 @@ cytoscape.use(coseBilkent);
|
||||
function drawNodes(
|
||||
db: MindmapDB,
|
||||
svg: D3Element,
|
||||
mindmap: MindMapNode,
|
||||
mindmap: FilledMindMapNode,
|
||||
section: number,
|
||||
conf: MermaidConfig
|
||||
conf: MermaidConfigWithDefaults
|
||||
) {
|
||||
drawNode(db, svg, mindmap, section, conf);
|
||||
if (mindmap.children) {
|
||||
@ -63,7 +63,7 @@ function drawEdges(edgesEl: D3Element, cy: cytoscape.Core) {
|
||||
});
|
||||
}
|
||||
|
||||
function addNodes(mindmap: MindMapNode, cy: cytoscape.Core, conf: MermaidConfig, level: number) {
|
||||
function addNodes(mindmap: MindmapNode, cy: cytoscape.Core, conf: MermaidConfig, level: number) {
|
||||
cy.add({
|
||||
group: 'nodes',
|
||||
data: {
|
||||
@ -99,7 +99,7 @@ function addNodes(mindmap: MindMapNode, cy: cytoscape.Core, conf: MermaidConfig,
|
||||
}
|
||||
|
||||
function layoutMindmap(
|
||||
node: MindMapNode,
|
||||
node: MindmapNode,
|
||||
conf: MermaidConfigWithDefaults
|
||||
): Promise<cytoscape.Core> {
|
||||
return new Promise((resolve) => {
|
||||
@ -193,7 +193,7 @@ export const draw = async (text: string, id: string, version: string, diagObj: D
|
||||
edgesElem.attr('class', 'mindmap-edges');
|
||||
const nodesElem = svg.append('g');
|
||||
nodesElem.attr('class', 'mindmap-nodes');
|
||||
drawNodes(db, nodesElem, mm, -1, conf);
|
||||
drawNodes(db, nodesElem, mm as FilledMindMapNode, -1, conf);
|
||||
|
||||
// Next step is to layout the mindmap, giving each node a position
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { RequiredDeep } from 'type-fest';
|
||||
import type mindmapDb from './mindmapDb.js';
|
||||
|
||||
export interface MindMapNode {
|
||||
export interface MindmapNode {
|
||||
id: number;
|
||||
nodeId: string;
|
||||
level: number;
|
||||
descr: string;
|
||||
type: number;
|
||||
children: MindMapNode[];
|
||||
children: MindmapNode[];
|
||||
width: number;
|
||||
padding: number;
|
||||
section?: number;
|
||||
@ -17,4 +18,5 @@ export interface MindMapNode {
|
||||
y?: number;
|
||||
}
|
||||
|
||||
export type FilledMindMapNode = RequiredDeep<MindmapNode>;
|
||||
export type MindmapDB = typeof mindmapDb;
|
||||
|
@ -1,7 +1,13 @@
|
||||
import type { D3Element } from '../../mermaidAPI.js';
|
||||
import { createText } from '../../rendering-util/createText.js';
|
||||
import type { FilledMindMapNode, MindmapDB } from './mindmapTypes.js';
|
||||
import { MermaidConfigWithDefaults } from '../../config.js';
|
||||
import { Point } from '../../types.js';
|
||||
const MAX_SECTIONS = 12;
|
||||
|
||||
const defaultBkg = function (db, elem, node, section) {
|
||||
type ShapeFunction = (db: MindmapDB, elem: D3Element, node: FilledMindMapNode, section?: number) => void;
|
||||
|
||||
const defaultBkg: ShapeFunction = function(db, elem, node, section) {
|
||||
const rd = 5;
|
||||
elem
|
||||
.append('path')
|
||||
@ -9,8 +15,7 @@ const defaultBkg = function (db, elem, node, section) {
|
||||
.attr('class', 'node-bkg node-' + db.type2Str(node.type))
|
||||
.attr(
|
||||
'd',
|
||||
`M0 ${node.height - rd} v${-node.height + 2 * rd} q0,-5 5,-5 h${
|
||||
node.width - 2 * rd
|
||||
`M0 ${node.height - rd} v${-node.height + 2 * rd} q0,-5 5,-5 h${node.width - 2 * rd
|
||||
} q5,0 5,5 v${node.height - rd} H0 Z`
|
||||
);
|
||||
|
||||
@ -23,7 +28,7 @@ const defaultBkg = function (db, elem, node, section) {
|
||||
.attr('y2', node.height);
|
||||
};
|
||||
|
||||
const rectBkg = function (db, elem, node) {
|
||||
const rectBkg: ShapeFunction = function(db, elem, node) {
|
||||
elem
|
||||
.append('rect')
|
||||
.attr('id', 'node-' + node.id)
|
||||
@ -32,7 +37,7 @@ const rectBkg = function (db, elem, node) {
|
||||
.attr('width', node.width);
|
||||
};
|
||||
|
||||
const cloudBkg = function (db, elem, node) {
|
||||
const cloudBkg: ShapeFunction = function(db, elem, node) {
|
||||
const w = node.width;
|
||||
const h = node.height;
|
||||
const r1 = 0.15 * w;
|
||||
@ -63,7 +68,7 @@ const cloudBkg = function (db, elem, node) {
|
||||
);
|
||||
};
|
||||
|
||||
const bangBkg = function (db, elem, node) {
|
||||
const bangBkg: ShapeFunction = function(db, elem, node) {
|
||||
const w = node.width;
|
||||
const h = node.height;
|
||||
const r = 0.15 * w;
|
||||
@ -95,7 +100,7 @@ const bangBkg = function (db, elem, node) {
|
||||
);
|
||||
};
|
||||
|
||||
const circleBkg = function (db, elem, node) {
|
||||
const circleBkg: ShapeFunction = function(db, elem, node) {
|
||||
elem
|
||||
.append('circle')
|
||||
.attr('id', 'node-' + node.id)
|
||||
@ -111,13 +116,13 @@ const circleBkg = function (db, elem, node) {
|
||||
* @param points
|
||||
* @param node
|
||||
*/
|
||||
function insertPolygonShape(parent, w, h, points, node) {
|
||||
function insertPolygonShape(parent: D3Element, w: number, h: number, points: Point[], node: FilledMindMapNode) {
|
||||
return parent
|
||||
.insert('polygon', ':first-child')
|
||||
.attr(
|
||||
'points',
|
||||
points
|
||||
.map(function (d) {
|
||||
.map(function(d) {
|
||||
return d.x + ',' + d.y;
|
||||
})
|
||||
.join(' ')
|
||||
@ -125,12 +130,12 @@ function insertPolygonShape(parent, w, h, points, node) {
|
||||
.attr('transform', 'translate(' + (node.width - w) / 2 + ', ' + h + ')');
|
||||
}
|
||||
|
||||
const hexagonBkg = function (db, elem, node) {
|
||||
const hexagonBkg: ShapeFunction = function(_db: MindmapDB, elem: D3Element, node: FilledMindMapNode) {
|
||||
const h = node.height;
|
||||
const f = 4;
|
||||
const m = h / f;
|
||||
const w = node.width - node.padding + 2 * m;
|
||||
const points = [
|
||||
const points: Point[] = [
|
||||
{ x: m, y: 0 },
|
||||
{ x: w - m, y: 0 },
|
||||
{ x: w, y: -h / 2 },
|
||||
@ -138,10 +143,10 @@ const hexagonBkg = function (db, elem, node) {
|
||||
{ x: m, y: -h },
|
||||
{ x: 0, y: -h / 2 },
|
||||
];
|
||||
const shapeSvg = insertPolygonShape(elem, w, h, points, node);
|
||||
insertPolygonShape(elem, w, h, points, node);
|
||||
};
|
||||
|
||||
const roundedRectBkg = function (db, elem, node) {
|
||||
const roundedRectBkg: ShapeFunction = function(db, elem, node) {
|
||||
elem
|
||||
.append('rect')
|
||||
.attr('id', 'node-' + node.id)
|
||||
@ -153,14 +158,14 @@ const roundedRectBkg = function (db, elem, node) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('./mindmapTypes.js').MindmapDB} db The database
|
||||
* @param {object} elem The D3 dom element in which the node is to be added
|
||||
* @param {object} node The node to be added
|
||||
* @param db The database
|
||||
* @param elem The D3 dom element in which the node is to be added
|
||||
* @param node The node to be added
|
||||
* @param fullSection
|
||||
* @param {object} conf The configuration object
|
||||
* @returns {number} The height nodes dom element
|
||||
* @param conf The configuration object
|
||||
* @returns The height nodes dom element
|
||||
*/
|
||||
export const drawNode = function (db, elem, node, fullSection, conf) {
|
||||
export const drawNode = function(db: MindmapDB, elem: D3Element, node: FilledMindMapNode, fullSection: number, conf: MermaidConfigWithDefaults): number {
|
||||
const htmlLabels = conf.htmlLabels;
|
||||
const section = fullSection % (MAX_SECTIONS - 1);
|
||||
const nodeElem = elem.append('g');
|
||||
@ -190,6 +195,7 @@ export const drawNode = function (db, elem, node, fullSection, conf) {
|
||||
}
|
||||
// .call(wrap, node.width);
|
||||
const bbox = textElem.node().getBBox();
|
||||
// @ts-expect-error TODO: Check if fontSize can be string?
|
||||
const fontSize = conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
|
||||
node.height = bbox.height + fontSize * 1.1 * 0.5 + node.padding;
|
||||
node.width = bbox.width + 2 * node.padding;
|
||||
@ -247,26 +253,26 @@ export const drawNode = function (db, elem, node, fullSection, conf) {
|
||||
|
||||
switch (node.type) {
|
||||
case db.nodeType.DEFAULT:
|
||||
defaultBkg(db, bkgElem, node, section, conf);
|
||||
defaultBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.ROUNDED_RECT:
|
||||
roundedRectBkg(db, bkgElem, node, section, conf);
|
||||
roundedRectBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.RECT:
|
||||
rectBkg(db, bkgElem, node, section, conf);
|
||||
rectBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.CIRCLE:
|
||||
bkgElem.attr('transform', 'translate(' + node.width / 2 + ', ' + +node.height / 2 + ')');
|
||||
circleBkg(db, bkgElem, node, section, conf);
|
||||
circleBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.CLOUD:
|
||||
cloudBkg(db, bkgElem, node, section, conf);
|
||||
cloudBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.BANG:
|
||||
bangBkg(db, bkgElem, node, section, conf);
|
||||
bangBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
case db.nodeType.HEXAGON:
|
||||
hexagonBkg(db, bkgElem, node, section, conf);
|
||||
hexagonBkg(db, bkgElem, node, section);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -274,7 +280,7 @@ export const drawNode = function (db, elem, node, fullSection, conf) {
|
||||
return node.height;
|
||||
};
|
||||
|
||||
export const positionNode = function (db, node) {
|
||||
export const positionNode = function(db: MindmapDB, node: FilledMindMapNode) {
|
||||
const nodeElem = db.getElementById(node.id);
|
||||
|
||||
const x = node.x || 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user