From 69b3a9d3a26934dd69a3fe68a521acd20390b8cf Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 13:27:23 +0530 Subject: [PATCH 1/9] feat: Support fallback layouts in renderer --- packages/mermaid/src/rendering-util/render.ts | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/mermaid/src/rendering-util/render.ts b/packages/mermaid/src/rendering-util/render.ts index 442780c753..4c08b5d27e 100644 --- a/packages/mermaid/src/rendering-util/render.ts +++ b/packages/mermaid/src/rendering-util/render.ts @@ -1,3 +1,5 @@ +import { log } from '$root/logger.js'; + export interface LayoutAlgorithm { render(data4Layout: any, svg: any, element: any, algorithm?: string): any; } @@ -24,10 +26,6 @@ const registerDefaultLayoutLoaders = () => { name: 'dagre', loader: async () => await import('./layout-algorithms/dagre/index.js'), }, - // { - // name: 'elk', - // loader: async () => await import('../../../mermaid-layout-elk/src/render.js'), - // }, ]); }; @@ -42,3 +40,17 @@ export const render = async (data4Layout: any, svg: any, element: any) => { const layoutRenderer = await layoutDefinition.loader(); return layoutRenderer.render(data4Layout, svg, element, layoutDefinition.algorithm); }; + +/** + * Get the registered layout algorithm. If the algorithm is not registered, use the fallback algorithm. + */ +export const getRegisteredLayoutAlgorithm = (algorithm = '', { fallback = 'dagre' } = {}) => { + if (algorithm in layoutAlgorithms) { + return algorithm; + } + if (fallback in layoutAlgorithms) { + log.warn(`Layout algorithm ${algorithm} is not registered. Using ${fallback} as fallback.`); + return fallback; + } + throw new Error(`Both layout algorithms ${algorithm} and ${fallback} are not registered.`); +}; From 754fa241046cadb8f15cc4d84f026f8147fec3af Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 13:28:11 +0530 Subject: [PATCH 2/9] chore: Remove redundant flowDiagram-v2 --- .../src/diagrams/flowchart/flowDetector-v2.ts | 9 +++++--- .../src/diagrams/flowchart/flowDiagram-v2.ts | 23 ------------------- 2 files changed, 6 insertions(+), 26 deletions(-) delete mode 100644 packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts diff --git a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts index dda5a67f0d..b66afe4bf7 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts @@ -1,5 +1,8 @@ -import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js'; -import type { ExternalDiagramDefinition } from '../../diagram-api/types.js'; +import type { + DiagramDetector, + DiagramLoader, + ExternalDiagramDefinition, +} from '../../diagram-api/types.js'; const id = 'flowchart-v2'; @@ -19,7 +22,7 @@ const detector: DiagramDetector = (txt, config) => { }; const loader: DiagramLoader = async () => { - const { diagram } = await import('./flowDiagram-v2.js'); + const { diagram } = await import('./flowDiagram.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts b/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts deleted file mode 100644 index 5b8012edea..0000000000 --- a/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts +++ /dev/null @@ -1,23 +0,0 @@ -// @ts-ignore: JISON doesn't support types -import flowParser from './parser/flow.jison'; -import flowDb from './flowDb.js'; -import renderer from './flowRenderer-v3-unified.js'; -import flowStyles from './styles.js'; -import type { MermaidConfig } from '../../config.type.js'; -import { setConfig } from '../../diagram-api/diagramAPI.js'; - -export const diagram = { - parser: flowParser, - db: flowDb, - renderer, - styles: flowStyles, - init: (cnf: MermaidConfig) => { - if (!cnf.flowchart) { - cnf.flowchart = {}; - } - cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } }); - flowDb.clear(); - flowDb.setGen('gen-2'); - }, -}; From bc3fe33428b550b3a41ab5e7de0714c17bde5576 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 13:29:09 +0530 Subject: [PATCH 3/9] feat: Set config.layout=elk when using flowchart-elk --- .../src/diagrams/flowchart/elk/detector.ts | 16 ++++------------ .../src/diagrams/flowchart/flowDiagram.ts | 11 +++++++---- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts index b476ff11ba..6688ffd8c0 100644 --- a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts +++ b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts @@ -1,34 +1,26 @@ import type { - ExternalDiagramDefinition, DiagramDetector, DiagramLoader, + ExternalDiagramDefinition, } from '../../../diagram-api/types.js'; -import { log } from '../../../logger.js'; const id = 'flowchart-elk'; -const detector: DiagramDetector = (txt, config): boolean => { +const detector: DiagramDetector = (txt, config = {}): boolean => { if ( // If diagram explicitly states flowchart-elk /^\s*flowchart-elk/.test(txt) || // If a flowchart/graph diagram has their default renderer set to elk (/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk') ) { - // This will log at the end, hopefully. - setTimeout( - () => - log.warn( - 'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](link) for more details. This diagram will be rendered using `dagre` layout as a fallback.' - ), - 500 - ); + config.layout = 'elk'; return true; } return false; }; const loader: DiagramLoader = async () => { - const { diagram } = await import('../flowDiagram-v2.js'); + const { diagram } = await import('../flowDiagram.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts b/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts index 5b8012edea..67cdf918fe 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts @@ -1,10 +1,10 @@ -// @ts-ignore: JISON doesn't support types -import flowParser from './parser/flow.jison'; +import type { MermaidConfig } from '../../config.type.js'; +import { setConfig } from '../../diagram-api/diagramAPI.js'; import flowDb from './flowDb.js'; import renderer from './flowRenderer-v3-unified.js'; +// @ts-ignore: JISON doesn't support types +import flowParser from './parser/flow.jison'; import flowStyles from './styles.js'; -import type { MermaidConfig } from '../../config.type.js'; -import { setConfig } from '../../diagram-api/diagramAPI.js'; export const diagram = { parser: flowParser, @@ -15,6 +15,9 @@ export const diagram = { if (!cnf.flowchart) { cnf.flowchart = {}; } + if (cnf.layout) { + setConfig({ layout: cnf.layout }); + } cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } }); flowDb.clear(); From 77118ad40c814545fbf4194a878b8cb4d94360c6 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 13:30:02 +0530 Subject: [PATCH 4/9] feat: Use dagre as fallback if elk layout is not present Warn users that we are using the fallback --- .../src/diagrams/flowchart/flowRenderer-v3-unified.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts index 102662ee68..5d52b64e8b 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v3-unified.ts @@ -3,7 +3,7 @@ import { getConfig } from '../../diagram-api/diagramAPI.js'; import type { DiagramStyleClassDef } from '../../diagram-api/types.js'; import { log } from '../../logger.js'; import { getDiagramElements } 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 type { LayoutData } from '../../rendering-util/types.js'; import utils from '../../utils.js'; @@ -40,7 +40,12 @@ export const draw = async function (text: string, id: string, _version: string, const direction = getDirection(); data4Layout.type = diag.type; - data4Layout.layoutAlgorithm = layout; + data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout); + if (data4Layout.layoutAlgorithm === 'dagre' && layout === 'elk') { + log.warn( + 'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](https://github.com/mermaid-js/mermaid/releases/tag/v11.0.0) for more details. This diagram will be rendered using `dagre` layout as a fallback.' + ); + } data4Layout.direction = direction; data4Layout.nodeSpacing = conf?.nodeSpacing || 50; data4Layout.rankSpacing = conf?.rankSpacing || 50; From 44875691db7713c8e3427fefde0d2373f2b91943 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 13:37:58 +0530 Subject: [PATCH 5/9] chore: Remove `mermaid-flowchart-elk` --- packages/mermaid-flowchart-elk/package.json | 45 - .../src/detector.spec.ts | 75 -- .../mermaid-flowchart-elk/src/detector.ts | 32 - .../src/diagram-definition.ts | 12 - .../src/flowRenderer-elk.js | 888 ------------------ .../src/render-utils.spec.ts | 41 - .../mermaid-flowchart-elk/src/render-utils.ts | 25 - packages/mermaid-flowchart-elk/src/styles.ts | 143 --- packages/mermaid-flowchart-elk/tsconfig.json | 10 - 9 files changed, 1271 deletions(-) delete mode 100644 packages/mermaid-flowchart-elk/package.json delete mode 100644 packages/mermaid-flowchart-elk/src/detector.spec.ts delete mode 100644 packages/mermaid-flowchart-elk/src/detector.ts delete mode 100644 packages/mermaid-flowchart-elk/src/diagram-definition.ts delete mode 100644 packages/mermaid-flowchart-elk/src/flowRenderer-elk.js delete mode 100644 packages/mermaid-flowchart-elk/src/render-utils.spec.ts delete mode 100644 packages/mermaid-flowchart-elk/src/render-utils.ts delete mode 100644 packages/mermaid-flowchart-elk/src/styles.ts delete mode 100644 packages/mermaid-flowchart-elk/tsconfig.json diff --git a/packages/mermaid-flowchart-elk/package.json b/packages/mermaid-flowchart-elk/package.json deleted file mode 100644 index dc3af195ca..0000000000 --- a/packages/mermaid-flowchart-elk/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@mermaid-js/flowchart-elk", - "version": "1.0.0-rc.1", - "description": "Flowchart plugin for mermaid with ELK layout", - "module": "dist/mermaid-flowchart-elk.core.mjs", - "types": "dist/packages/mermaid-flowchart-elk/src/detector.d.ts", - "type": "module", - "exports": { - ".": { - "import": "./dist/mermaid-flowchart-elk.core.mjs", - "types": "./dist/packages/mermaid-flowchart-elk/src/detector.d.ts" - }, - "./*": "./*" - }, - "keywords": [ - "diagram", - "markdown", - "flowchart", - "elk", - "mermaid" - ], - "scripts": { - "prepublishOnly": "pnpm -w run build" - }, - "repository": { - "type": "git", - "url": "https://github.com/mermaid-js/mermaid" - }, - "author": "Knut Sveidqvist", - "license": "MIT", - "dependencies": { - "d3": "^7.9.0", - "dagre-d3-es": "7.0.10", - "elkjs": "^0.9.2", - "khroma": "^2.1.0" - }, - "devDependencies": { - "concurrently": "^8.2.2", - "mermaid": "workspace:^", - "rimraf": "^5.0.5" - }, - "files": [ - "dist" - ] -} diff --git a/packages/mermaid-flowchart-elk/src/detector.spec.ts b/packages/mermaid-flowchart-elk/src/detector.spec.ts deleted file mode 100644 index 94ac22d260..0000000000 --- a/packages/mermaid-flowchart-elk/src/detector.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import plugin from './detector.js'; -import { describe, it } from 'vitest'; - -const { detector } = plugin; - -describe('flowchart-elk detector', () => { - it('should fail for dagre-d3', () => { - expect( - detector('flowchart', { - flowchart: { - defaultRenderer: 'dagre-d3', - }, - }) - ).toBe(false); - }); - it('should fail for dagre-wrapper', () => { - expect( - detector('flowchart', { - flowchart: { - defaultRenderer: 'dagre-wrapper', - }, - }) - ).toBe(false); - }); - it('should succeed for elk', () => { - expect( - detector('flowchart', { - flowchart: { - defaultRenderer: 'elk', - }, - }) - ).toBe(true); - expect( - detector('graph', { - flowchart: { - defaultRenderer: 'elk', - }, - }) - ).toBe(true); - }); - - // The error from the issue was reproduced with mindmap, so this is just an example - // what matters is the keyword somewhere inside graph definition - it('should check only the beginning of the line in search of keywords', () => { - expect( - detector('mindmap ["Descendant node in flowchart"]', { - flowchart: { - defaultRenderer: 'elk', - }, - }) - ).toBe(false); - - expect( - detector('mindmap ["Descendant node in graph"]', { - flowchart: { - defaultRenderer: 'elk', - }, - }) - ).toBe(false); - }); - - it('should detect flowchart-elk', () => { - expect(detector('flowchart-elk')).toBe(true); - }); - - it('should not detect class with defaultRenderer set to elk', () => { - expect( - detector('class', { - flowchart: { - defaultRenderer: 'elk', - }, - }) - ).toBe(false); - }); -}); diff --git a/packages/mermaid-flowchart-elk/src/detector.ts b/packages/mermaid-flowchart-elk/src/detector.ts deleted file mode 100644 index 3b168bd616..0000000000 --- a/packages/mermaid-flowchart-elk/src/detector.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { - ExternalDiagramDefinition, - DiagramDetector, - DiagramLoader, -} from '../../mermaid/src/diagram-api/types.js'; - -const id = 'flowchart-elk'; - -const detector: DiagramDetector = (txt, config): boolean => { - if ( - // If diagram explicitly states flowchart-elk - /^\s*flowchart-elk/.test(txt) || - // If a flowchart/graph diagram has their default renderer set to elk - (/^\s*(flowchart|graph)/.test(txt) && config?.flowchart?.defaultRenderer === 'elk') - ) { - return true; - } - return false; -}; - -const loader: DiagramLoader = async () => { - const { diagram } = await import('./diagram-definition.js'); - return { id, diagram }; -}; - -const plugin: ExternalDiagramDefinition = { - id, - detector, - loader, -}; - -export default plugin; diff --git a/packages/mermaid-flowchart-elk/src/diagram-definition.ts b/packages/mermaid-flowchart-elk/src/diagram-definition.ts deleted file mode 100644 index 4a6b5b0766..0000000000 --- a/packages/mermaid-flowchart-elk/src/diagram-definition.ts +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-ignore: JISON typing missing -import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison'; -import db from '../../mermaid/src/diagrams/flowchart/flowDb.js'; -import styles from '../../mermaid/src/diagrams/flowchart/styles.js'; -import renderer from './flowRenderer-elk.js'; - -export const diagram = { - db, - renderer, - parser, - styles, -}; diff --git a/packages/mermaid-flowchart-elk/src/flowRenderer-elk.js b/packages/mermaid-flowchart-elk/src/flowRenderer-elk.js deleted file mode 100644 index fc540073a4..0000000000 --- a/packages/mermaid-flowchart-elk/src/flowRenderer-elk.js +++ /dev/null @@ -1,888 +0,0 @@ -import { select, line, curveLinear } from 'd3'; -import { insertNode } from '../../mermaid/src/dagre-wrapper/nodes.js'; -import insertMarkers from '../../mermaid/src/dagre-wrapper/markers.js'; -import { insertEdgeLabel } from '../../mermaid/src/dagre-wrapper/edges.js'; -import { findCommonAncestor } from './render-utils.js'; -import { labelHelper } from '../../mermaid/src/dagre-wrapper/shapes/util.js'; -import { getConfig } from '../../mermaid/src/config.js'; -import { log } from '../../mermaid/src/logger.js'; -import utils from '../../mermaid/src/utils.js'; -import { setupGraphViewbox } from '../../mermaid/src/setupGraphViewbox.js'; -import common from '../../mermaid/src/diagrams/common/common.js'; -import { interpolateToCurve, getStylesFromArray } from '../../mermaid/src/utils.js'; -import ELK from 'elkjs/lib/elk.bundled.js'; -import { getLineFunctionsWithOffset } from '../../mermaid/src/utils/lineWithOffset.js'; -import { addEdgeMarkers } from '../../mermaid/src/dagre-wrapper/edgeMarker.js'; - -const elk = new ELK(); - -let portPos = {}; - -const conf = {}; -export const setConf = function (cnf) { - const keys = Object.keys(cnf); - for (const key of keys) { - conf[key] = cnf[key]; - } -}; - -let nodeDb = {}; - -// /** -// * Function that adds the vertices found during parsing to the graph to be rendered. -// * -// * @param vert Object containing the vertices. -// * @param g The graph that is to be drawn. -// * @param svgId -// * @param root -// * @param doc -// * @param diagObj -// */ -export const addVertices = async function (vert, svgId, root, doc, diagObj, parentLookupDb, graph) { - const svg = root.select(`[id="${svgId}"]`); - const nodes = svg.insert('g').attr('class', 'nodes'); - const keys = [...vert.keys()]; - - // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition - await Promise.all( - keys.map(async function (id) { - const vertex = vert.get(id); - - /** - * Variable for storing the classes for the vertex - * - * @type {string} - */ - let classStr = 'default'; - if (vertex.classes.length > 0) { - classStr = vertex.classes.join(' '); - } - classStr = classStr + ' flowchart-label'; - const styles = getStylesFromArray(vertex.styles); - - // Use vertex id as text in the box if no text is provided by the graph definition - let vertexText = vertex.text !== undefined ? vertex.text : vertex.id; - - // We create a SVG label, either by delegating to addHtmlLabel or manually - const labelData = { width: 0, height: 0 }; - - const ports = [ - { - id: vertex.id + '-west', - layoutOptions: { - 'port.side': 'WEST', - }, - }, - { - id: vertex.id + '-east', - layoutOptions: { - 'port.side': 'EAST', - }, - }, - { - id: vertex.id + '-south', - layoutOptions: { - 'port.side': 'SOUTH', - }, - }, - { - id: vertex.id + '-north', - layoutOptions: { - 'port.side': 'NORTH', - }, - }, - ]; - - let radius = 0; - let _shape = ''; - let layoutOptions = {}; - // Set the shape based parameters - switch (vertex.type) { - case 'round': - radius = 5; - _shape = 'rect'; - break; - case 'square': - _shape = 'rect'; - break; - case 'diamond': - _shape = 'question'; - layoutOptions = { - portConstraints: 'FIXED_SIDE', - }; - break; - case 'hexagon': - _shape = 'hexagon'; - break; - case 'odd': - _shape = 'rect_left_inv_arrow'; - break; - case 'lean_right': - _shape = 'lean_right'; - break; - case 'lean_left': - _shape = 'lean_left'; - break; - case 'trapezoid': - _shape = 'trapezoid'; - break; - case 'inv_trapezoid': - _shape = 'inv_trapezoid'; - break; - case 'odd_right': - _shape = 'rect_left_inv_arrow'; - break; - case 'circle': - _shape = 'circle'; - break; - case 'ellipse': - _shape = 'ellipse'; - break; - case 'stadium': - _shape = 'stadium'; - break; - case 'subroutine': - _shape = 'subroutine'; - break; - case 'cylinder': - _shape = 'cylinder'; - break; - case 'group': - _shape = 'rect'; - break; - case 'doublecircle': - _shape = 'doublecircle'; - break; - default: - _shape = 'rect'; - } - - // Add the node - const node = { - labelStyle: styles.labelStyle, - shape: _shape, - labelText: vertexText, - labelType: vertex.labelType, - rx: radius, - ry: radius, - class: classStr, - style: styles.style, - id: vertex.id, - link: vertex.link, - linkTarget: vertex.linkTarget, - tooltip: diagObj.db.getTooltip(vertex.id) || '', - domId: diagObj.db.lookUpDomId(vertex.id), - haveCallback: vertex.haveCallback, - width: vertex.type === 'group' ? 500 : undefined, - dir: vertex.dir, - type: vertex.type, - props: vertex.props, - padding: getConfig().flowchart.padding, - }; - let boundingBox; - let nodeEl; - - // Add the element to the DOM - if (node.type !== 'group') { - nodeEl = await insertNode(nodes, node, vertex.dir); - boundingBox = nodeEl.node().getBBox(); - } else { - const { shapeSvg, bbox } = await labelHelper(nodes, node, undefined, true); - labelData.width = bbox.width; - labelData.wrappingWidth = getConfig().flowchart.wrappingWidth; - labelData.height = bbox.height; - labelData.labelNode = shapeSvg.node(); - node.labelData = labelData; - } - // const { shapeSvg, bbox } = await labelHelper(svg, node, undefined, true); - - const data = { - id: vertex.id, - ports: vertex.type === 'diamond' ? ports : [], - // labelStyle: styles.labelStyle, - // shape: _shape, - layoutOptions, - labelText: vertexText, - labelData, - // labels: [{ text: vertexText }], - // rx: radius, - // ry: radius, - // class: classStr, - // style: styles.style, - // link: vertex.link, - // linkTarget: vertex.linkTarget, - // tooltip: diagObj.db.getTooltip(vertex.id) || '', - domId: diagObj.db.lookUpDomId(vertex.id), - // haveCallback: vertex.haveCallback, - width: boundingBox?.width, - height: boundingBox?.height, - // dir: vertex.dir, - type: vertex.type, - // props: vertex.props, - // padding: getConfig().flowchart.padding, - // boundingBox, - el: nodeEl, - parent: parentLookupDb.parentById[vertex.id], - }; - // if (!Object.keys(parentLookupDb.childrenById).includes(vertex.id)) { - // graph.children.push({ - // ...data, - // }); - // } - nodeDb[node.id] = data; - // log.trace('setNode', { - // labelStyle: styles.labelStyle, - // shape: _shape, - // labelText: vertexText, - // rx: radius, - // ry: radius, - // class: classStr, - // style: styles.style, - // id: vertex.id, - // domId: diagObj.db.lookUpDomId(vertex.id), - // width: vertex.type === 'group' ? 500 : undefined, - // type: vertex.type, - // dir: vertex.dir, - // props: vertex.props, - // padding: getConfig().flowchart.padding, - // parent: parentLookupDb.parentById[vertex.id], - // }); - }) - ); - return graph; -}; - -const getNextPosition = (position, edgeDirection, graphDirection) => { - const portPos = { - TB: { - in: { - north: 'north', - }, - out: { - south: 'west', - west: 'east', - east: 'south', - }, - }, - LR: { - in: { - west: 'west', - }, - out: { - east: 'south', - south: 'north', - north: 'east', - }, - }, - RL: { - in: { - east: 'east', - }, - out: { - west: 'north', - north: 'south', - south: 'west', - }, - }, - BT: { - in: { - south: 'south', - }, - out: { - north: 'east', - east: 'west', - west: 'north', - }, - }, - }; - portPos.TD = portPos.TB; - return portPos[graphDirection][edgeDirection][position]; - // return 'south'; -}; - -const getNextPort = (node, edgeDirection, graphDirection) => { - log.info('getNextPort', { node, edgeDirection, graphDirection }); - if (!portPos[node]) { - switch (graphDirection) { - case 'TB': - case 'TD': - portPos[node] = { - inPosition: 'north', - outPosition: 'south', - }; - break; - case 'BT': - portPos[node] = { - inPosition: 'south', - outPosition: 'north', - }; - break; - case 'RL': - portPos[node] = { - inPosition: 'east', - outPosition: 'west', - }; - break; - case 'LR': - portPos[node] = { - inPosition: 'west', - outPosition: 'east', - }; - break; - } - } - const result = edgeDirection === 'in' ? portPos[node].inPosition : portPos[node].outPosition; - - if (edgeDirection === 'in') { - portPos[node].inPosition = getNextPosition( - portPos[node].inPosition, - edgeDirection, - graphDirection - ); - } else { - portPos[node].outPosition = getNextPosition( - portPos[node].outPosition, - edgeDirection, - graphDirection - ); - } - return result; -}; - -const getEdgeStartEndPoint = (edge, dir) => { - let source = edge.start; - let target = edge.end; - - // Save the original source and target - const sourceId = source; - const targetId = target; - - const startNode = nodeDb[source]; - const endNode = nodeDb[target]; - - if (!startNode || !endNode) { - return { source, target }; - } - - if (startNode.type === 'diamond') { - source = `${source}-${getNextPort(source, 'out', dir)}`; - } - - if (endNode.type === 'diamond') { - target = `${target}-${getNextPort(target, 'in', dir)}`; - } - - // Add the edge to the graph - return { source, target, sourceId, targetId }; -}; - -/** - * Add edges to graph based on parsed graph definition - * - * @param {object} edges The edges to add to the graph - * @param {object} g The graph object - * @param cy - * @param diagObj - * @param graph - * @param svg - */ -export const addEdges = function (edges, diagObj, graph, svg) { - log.info('abc78 edges = ', edges); - const labelsEl = svg.insert('g').attr('class', 'edgeLabels'); - let linkIdCnt = {}; - let dir = diagObj.db.getDirection(); - let defaultStyle; - let defaultLabelStyle; - - if (edges.defaultStyle !== undefined) { - const defaultStyles = getStylesFromArray(edges.defaultStyle); - defaultStyle = defaultStyles.style; - defaultLabelStyle = defaultStyles.labelStyle; - } - - edges.forEach(function (edge) { - // Identify Link - const linkIdBase = 'L-' + edge.start + '-' + edge.end; - // count the links from+to the same node to give unique id - if (linkIdCnt[linkIdBase] === undefined) { - linkIdCnt[linkIdBase] = 0; - log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]); - } else { - linkIdCnt[linkIdBase]++; - log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]); - } - let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase]; - log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]); - const linkNameStart = 'LS-' + edge.start; - const linkNameEnd = 'LE-' + edge.end; - - const edgeData = { style: '', labelStyle: '' }; - edgeData.minlen = edge.length || 1; - //edgeData.id = 'id' + cnt; - - // Set link type for rendering - if (edge.type === 'arrow_open') { - edgeData.arrowhead = 'none'; - } else { - edgeData.arrowhead = 'normal'; - } - - // Check of arrow types, placed here in order not to break old rendering - edgeData.arrowTypeStart = 'arrow_open'; - edgeData.arrowTypeEnd = 'arrow_open'; - - /* eslint-disable no-fallthrough */ - switch (edge.type) { - case 'double_arrow_cross': - edgeData.arrowTypeStart = 'arrow_cross'; - case 'arrow_cross': - edgeData.arrowTypeEnd = 'arrow_cross'; - break; - case 'double_arrow_point': - edgeData.arrowTypeStart = 'arrow_point'; - case 'arrow_point': - edgeData.arrowTypeEnd = 'arrow_point'; - break; - case 'double_arrow_circle': - edgeData.arrowTypeStart = 'arrow_circle'; - case 'arrow_circle': - edgeData.arrowTypeEnd = 'arrow_circle'; - break; - } - - let style = ''; - let labelStyle = ''; - - switch (edge.stroke) { - case 'normal': - style = 'fill:none;'; - if (defaultStyle !== undefined) { - style = defaultStyle; - } - if (defaultLabelStyle !== undefined) { - labelStyle = defaultLabelStyle; - } - edgeData.thickness = 'normal'; - edgeData.pattern = 'solid'; - break; - case 'dotted': - edgeData.thickness = 'normal'; - edgeData.pattern = 'dotted'; - edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;'; - break; - case 'thick': - edgeData.thickness = 'thick'; - edgeData.pattern = 'solid'; - edgeData.style = 'stroke-width: 3.5px;fill:none;'; - break; - } - if (edge.style !== undefined) { - const styles = getStylesFromArray(edge.style); - style = styles.style; - labelStyle = styles.labelStyle; - } - - edgeData.style = edgeData.style += style; - edgeData.labelStyle = edgeData.labelStyle += labelStyle; - - if (edge.interpolate !== undefined) { - edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear); - } else if (edges.defaultInterpolate !== undefined) { - edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear); - } else { - edgeData.curve = interpolateToCurve(conf.curve, curveLinear); - } - - if (edge.text === undefined) { - if (edge.style !== undefined) { - edgeData.arrowheadStyle = 'fill: #333'; - } - } else { - edgeData.arrowheadStyle = 'fill: #333'; - edgeData.labelpos = 'c'; - } - - edgeData.labelType = edge.labelType; - edgeData.label = edge.text.replace(common.lineBreakRegex, '\n'); - - if (edge.style === undefined) { - edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;'; - } - - edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:'); - - edgeData.id = linkId; - edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd; - - const labelEl = insertEdgeLabel(labelsEl, edgeData); - - // calculate start and end points of the edge, note that the source and target - // can be modified for shapes that have ports - const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir); - log.debug('abc78 source and target', source, target); - // Add the edge to the graph - graph.edges.push({ - id: 'e' + edge.start + edge.end, - sources: [source], - targets: [target], - sourceId, - targetId, - labelEl: labelEl, - labels: [ - { - width: edgeData.width, - height: edgeData.height, - orgWidth: edgeData.width, - orgHeight: edgeData.height, - text: edgeData.label, - layoutOptions: { - 'edgeLabels.inline': 'true', - 'edgeLabels.placement': 'CENTER', - }, - }, - ], - edgeData, - }); - }); - return graph; -}; - -// TODO: break out and share with dagre wrapper. The current code in dagre wrapper also adds -// adds the line to the graph, but we don't need that here. This is why we can't use the dagre -// wrapper directly for this -/** - * Add the markers to the edge depending on the type of arrow is - * @param svgPath - * @param edgeData - * @param diagramType - * @param arrowMarkerAbsolute - * @param id - */ -const addMarkersToEdge = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute, id) { - let url = ''; - // Check configuration for absolute path - if (arrowMarkerAbsolute) { - url = - window.location.protocol + - '//' + - window.location.host + - window.location.pathname + - window.location.search; - url = url.replace(/\(/g, '\\('); - url = url.replace(/\)/g, '\\)'); - } - - // look in edge data and decide which marker to use - addEdgeMarkers(svgPath, edgeData, url, id, diagramType); -}; - -/** - * Returns the all the styles from classDef statements in the graph definition. - * - * @param text - * @param diagObj - * @returns {Map} ClassDef styles - */ -export const getClasses = function (text, diagObj) { - log.info('Extracting classes'); - return diagObj.db.getClasses(); -}; - -const addSubGraphs = function (db) { - const parentLookupDb = { parentById: {}, childrenById: {} }; - const subgraphs = db.getSubGraphs(); - log.info('Subgraphs - ', subgraphs); - subgraphs.forEach(function (subgraph) { - subgraph.nodes.forEach(function (node) { - parentLookupDb.parentById[node] = subgraph.id; - if (parentLookupDb.childrenById[subgraph.id] === undefined) { - parentLookupDb.childrenById[subgraph.id] = []; - } - parentLookupDb.childrenById[subgraph.id].push(node); - }); - }); - - subgraphs.forEach(function (subgraph) { - const data = { id: subgraph.id }; - if (parentLookupDb.parentById[subgraph.id] !== undefined) { - data.parent = parentLookupDb.parentById[subgraph.id]; - } - }); - return parentLookupDb; -}; - -const calcOffset = function (src, dest, parentLookupDb) { - const ancestor = findCommonAncestor(src, dest, parentLookupDb); - if (ancestor === undefined || ancestor === 'root') { - return { x: 0, y: 0 }; - } - - const ancestorOffset = nodeDb[ancestor].offset; - return { x: ancestorOffset.posX, y: ancestorOffset.posY }; -}; - -const insertEdge = function (edgesEl, edge, edgeData, diagObj, parentLookupDb, id) { - const offset = calcOffset(edge.sourceId, edge.targetId, parentLookupDb); - - const src = edge.sections[0].startPoint; - const dest = edge.sections[0].endPoint; - const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : []; - - const segPoints = segments.map((segment) => [segment.x + offset.x, segment.y + offset.y]); - const points = [ - [src.x + offset.x, src.y + offset.y], - ...segPoints, - [dest.x + offset.x, dest.y + offset.y], - ]; - - const { x, y } = getLineFunctionsWithOffset(edge.edgeData); - const curve = line().x(x).y(y).curve(curveLinear); - const edgePath = edgesEl - .insert('path') - .attr('d', curve(points)) - .attr('class', 'path ' + edgeData.classes) - .attr('fill', 'none'); - Object.entries(edgeData).forEach(([key, value]) => { - if (key !== 'classes') { - edgePath.attr(key, value); - } - }); - const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel'); - const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl)); - const box = edgeWithLabel.node().firstChild.getBoundingClientRect(); - edgeWithLabel.attr('width', box.width); - edgeWithLabel.attr('height', box.height); - - edgeG.attr( - 'transform', - `translate(${edge.labels[0].x + offset.x}, ${edge.labels[0].y + offset.y})` - ); - addMarkersToEdge(edgePath, edgeData, diagObj.type, diagObj.arrowMarkerAbsolute, id); -}; - -/** - * Recursive function that iterates over an array of nodes and inserts the children of each node. - * It also recursively populates the inserts the children of the children and so on. - * @param nodeArray - * @param parentLookupDb - */ -const insertChildren = (nodeArray, parentLookupDb) => { - nodeArray.forEach((node) => { - // Check if we have reached the end of the tree - if (!node.children) { - node.children = []; - } - // Check if the node has children - const childIds = parentLookupDb.childrenById[node.id]; - // If the node has children, add them to the node - if (childIds) { - childIds.forEach((childId) => { - node.children.push(nodeDb[childId]); - }); - } - // Recursive call - insertChildren(node.children, parentLookupDb); - }); -}; - -/** - * Draws a flowchart in the tag with id: id based on the graph definition in text. - * - * @param text - * @param id - */ - -export const draw = async function (text, id, _version, diagObj) { - const { securityLevel, flowchart: conf } = getConfig(); - nodeDb = {}; - portPos = {}; - const renderEl = select('body').append('div').attr('style', 'height:400px').attr('id', 'cy'); - let graph = { - id: 'root', - layoutOptions: { - 'elk.hierarchyHandling': 'INCLUDE_CHILDREN', - 'elk.layered.spacing.edgeNodeBetweenLayers': conf?.nodeSpacing ? `${conf.nodeSpacing}` : '30', - // 'elk.layered.mergeEdges': 'true', - 'elk.direction': 'DOWN', - // 'elk.ports.sameLayerEdges': true, - // 'nodePlacement.strategy': 'SIMPLE', - }, - children: [], - edges: [], - }; - log.info('Drawing flowchart using v3 renderer', elk); - - // Set the direction, - // Fetch the default direction, use TD if none was found - let dir = diagObj.db.getDirection(); - switch (dir) { - case 'BT': - graph.layoutOptions['elk.direction'] = 'UP'; - break; - case 'TB': - graph.layoutOptions['elk.direction'] = 'DOWN'; - break; - case 'LR': - graph.layoutOptions['elk.direction'] = 'RIGHT'; - break; - case 'RL': - graph.layoutOptions['elk.direction'] = 'LEFT'; - break; - } - - // Find the root dom node to ne used in rendering - // Handle root and document for when rendering in sandbox mode - let sandboxElement; - if (securityLevel === 'sandbox') { - sandboxElement = select('#i' + id); - } - const root = - securityLevel === 'sandbox' - ? select(sandboxElement.nodes()[0].contentDocument.body) - : select('body'); - const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document; - - const svg = root.select(`[id="${id}"]`); - // Define the supported markers for the diagram - const markers = ['point', 'circle', 'cross']; - - // Add the marker definitions to the svg as marker tags - insertMarkers(svg, markers, diagObj.type, id); - - // Fetch the vertices/nodes and edges/links from the parsed graph definition - const vert = diagObj.db.getVertices(); - - // Setup nodes from the subgraphs with type group, these will be used - // as nodes with children in the subgraph - let subG; - const subGraphs = diagObj.db.getSubGraphs(); - log.info('Subgraphs - ', subGraphs); - for (let i = subGraphs.length - 1; i >= 0; i--) { - subG = subGraphs[i]; - diagObj.db.addVertex( - subG.id, - { text: subG.title, type: subG.labelType }, - 'group', - undefined, - subG.classes, - subG.dir - ); - } - - // debugger; - // Add an element in the svg to be used to hold the subgraphs container - // elements - const subGraphsEl = svg.insert('g').attr('class', 'subgraphs'); - - // Create the lookup db for the subgraphs and their children to used when creating - // the tree structured graph - const parentLookupDb = addSubGraphs(diagObj.db); - - // Add the nodes to the graph, this will entail creating the actual nodes - // in order to get the size of the node. You can't get the size of a node - // that is not in the dom so we need to add it to the dom, get the size - // we will position the nodes when we get the layout from elkjs - graph = await addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph); - - // Time for the edges, we start with adding an element in the node to hold the edges - const edgesEl = svg.insert('g').attr('class', 'edges edgePath'); - // Fetch the edges form the parsed graph definition - const edges = diagObj.db.getEdges(); - - // Add the edges to the graph, this will entail creating the actual edges - graph = addEdges(edges, diagObj, graph, svg); - - // Iterate through all nodes and add the top level nodes to the graph - const nodes = Object.keys(nodeDb); - nodes.forEach((nodeId) => { - const node = nodeDb[nodeId]; - if (!node.parent) { - graph.children.push(node); - } - // Subgraph - if (parentLookupDb.childrenById[nodeId] !== undefined) { - node.labels = [ - { - text: node.labelText, - layoutOptions: { - 'nodeLabels.placement': '[H_CENTER, V_TOP, INSIDE]', - }, - width: node.labelData.width, - height: node.labelData.height, - // width: 100, - // height: 100, - }, - ]; - delete node.x; - delete node.y; - delete node.width; - delete node.height; - } - }); - - insertChildren(graph.children, parentLookupDb); - log.info('after layout', JSON.stringify(graph, null, 2)); - const g = await elk.layout(graph); - drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0); - utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle()); - log.info('after layout', g); - g.edges?.map((edge) => { - insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb, id); - }); - setupGraphViewbox({}, svg, conf.diagramPadding, conf.useMaxWidth); - // Remove element after layout - renderEl.remove(); -}; - -const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj, depth) => { - nodeArray.forEach(function (node) { - if (node) { - nodeDb[node.id].offset = { - posX: node.x + relX, - posY: node.y + relY, - x: relX, - y: relY, - depth, - width: node.width, - height: node.height, - }; - if (node.type === 'group') { - const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph'); - subgraphEl - .insert('rect') - .attr('class', 'subgraph subgraph-lvl-' + (depth % 5) + ' node') - .attr('x', node.x + relX) - .attr('y', node.y + relY) - .attr('width', node.width) - .attr('height', node.height); - const label = subgraphEl.insert('g').attr('class', 'label'); - const labelCentering = getConfig().flowchart.htmlLabels ? node.labelData.width / 2 : 0; - label.attr( - 'transform', - `translate(${node.labels[0].x + relX + node.x + labelCentering}, ${ - node.labels[0].y + relY + node.y + 3 - })` - ); - label.node().appendChild(node.labelData.labelNode); - - log.info('Id (UGH)= ', node.type, node.labels); - } else { - log.info('Id (UGH)= ', node.id); - node.el.attr( - 'transform', - `translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})` - ); - } - } - }); - nodeArray.forEach(function (node) { - if (node && node.type === 'group') { - drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1); - } - }); -}; - -export default { - getClasses, - draw, -}; diff --git a/packages/mermaid-flowchart-elk/src/render-utils.spec.ts b/packages/mermaid-flowchart-elk/src/render-utils.spec.ts deleted file mode 100644 index 046ed43c1b..0000000000 --- a/packages/mermaid-flowchart-elk/src/render-utils.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { TreeData } from './render-utils.js'; -import { findCommonAncestor } from './render-utils.js'; -describe('when rendering a flowchart using elk ', () => { - let lookupDb: TreeData; - beforeEach(() => { - lookupDb = { - parentById: { - B4: 'inner', - B5: 'inner', - C4: 'inner2', - C5: 'inner2', - B2: 'Ugge', - B3: 'Ugge', - inner: 'Ugge', - inner2: 'Ugge', - B6: 'outer', - }, - childrenById: { - inner: ['B4', 'B5'], - inner2: ['C4', 'C5'], - Ugge: ['B2', 'B3', 'inner', 'inner2'], - outer: ['B6'], - }, - }; - }); - it('to find parent of siblings in a subgraph', () => { - expect(findCommonAncestor('B4', 'B5', lookupDb)).toBe('inner'); - }); - it('to find an uncle', () => { - expect(findCommonAncestor('B4', 'B2', lookupDb)).toBe('Ugge'); - }); - it('to find a cousin', () => { - expect(findCommonAncestor('B4', 'C4', lookupDb)).toBe('Ugge'); - }); - it('to find a grandparent', () => { - expect(findCommonAncestor('B4', 'B6', lookupDb)).toBe('root'); - }); - it('to find ancestor of siblings in the root', () => { - expect(findCommonAncestor('B1', 'outer', lookupDb)).toBe('root'); - }); -}); diff --git a/packages/mermaid-flowchart-elk/src/render-utils.ts b/packages/mermaid-flowchart-elk/src/render-utils.ts deleted file mode 100644 index ebdc01cf76..0000000000 --- a/packages/mermaid-flowchart-elk/src/render-utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface TreeData { - parentById: Record; - childrenById: Record; -} - -export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData) => { - const { parentById } = treeData; - const visited = new Set(); - let currentId = id1; - while (currentId) { - visited.add(currentId); - if (currentId === id2) { - return currentId; - } - currentId = parentById[currentId]; - } - currentId = id2; - while (currentId) { - if (visited.has(currentId)) { - return currentId; - } - currentId = parentById[currentId]; - } - return 'root'; -}; diff --git a/packages/mermaid-flowchart-elk/src/styles.ts b/packages/mermaid-flowchart-elk/src/styles.ts deleted file mode 100644 index 60659df457..0000000000 --- a/packages/mermaid-flowchart-elk/src/styles.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** Returns the styles given options */ -export interface FlowChartStyleOptions { - arrowheadColor: string; - border2: string; - clusterBkg: string; - clusterBorder: string; - edgeLabelBackground: string; - fontFamily: string; - lineColor: string; - mainBkg: string; - nodeBorder: string; - nodeTextColor: string; - tertiaryColor: string; - textColor: string; - titleColor: string; - [key: string]: string; -} - -const genSections = (options: FlowChartStyleOptions) => { - let sections = ''; - - for (let i = 0; i < 5; i++) { - sections += ` - .subgraph-lvl-${i} { - fill: ${options[`surface${i}`]}; - stroke: ${options[`surfacePeer${i}`]}; - } - `; - } - return sections; -}; - -const getStyles = (options: FlowChartStyleOptions) => - `.label { - font-family: ${options.fontFamily}; - color: ${options.nodeTextColor || options.textColor}; - } - .cluster-label text { - fill: ${options.titleColor}; - } - .cluster-label span { - color: ${options.titleColor}; - } - - .label text,span { - fill: ${options.nodeTextColor || options.textColor}; - color: ${options.nodeTextColor || options.textColor}; - } - - .node rect, - .node circle, - .node ellipse, - .node polygon, - .node path { - fill: ${options.mainBkg}; - stroke: ${options.nodeBorder}; - stroke-width: 1px; - } - - .node .label { - text-align: center; - } - .node.clickable { - cursor: pointer; - } - - .arrowheadPath { - fill: ${options.arrowheadColor}; - } - - .edgePath .path { - stroke: ${options.lineColor}; - stroke-width: 2.0px; - } - - .flowchart-link { - stroke: ${options.lineColor}; - fill: none; - } - - .edgeLabel { - background-color: ${options.edgeLabelBackground}; - rect { - opacity: 0.85; - background-color: ${options.edgeLabelBackground}; - fill: ${options.edgeLabelBackground}; - } - text-align: center; - } - - .cluster rect { - fill: ${options.clusterBkg}; - stroke: ${options.clusterBorder}; - stroke-width: 1px; - } - - .cluster text { - fill: ${options.titleColor}; - } - - .cluster span { - color: ${options.titleColor}; - } - /* .cluster div { - color: ${options.titleColor}; - } */ - - div.mermaidTooltip { - position: absolute; - text-align: center; - max-width: 200px; - padding: 2px; - font-family: ${options.fontFamily}; - font-size: 12px; - background: ${options.tertiaryColor}; - border: 1px solid ${options.border2}; - border-radius: 2px; - pointer-events: none; - z-index: 100; - } - - .flowchartTitleText { - text-anchor: middle; - font-size: 18px; - fill: ${options.textColor}; - } - .subgraph { - stroke-width:2; - rx:3; - } - // .subgraph-lvl-1 { - // fill:#ccc; - // // stroke:black; - // } - - .flowchart-label text { - text-anchor: middle; - } - - ${genSections(options)} -`; - -export default getStyles; diff --git a/packages/mermaid-flowchart-elk/tsconfig.json b/packages/mermaid-flowchart-elk/tsconfig.json deleted file mode 100644 index 5a41d06030..0000000000 --- a/packages/mermaid-flowchart-elk/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "../..", - "outDir": "./dist", - "types": ["vitest/importMeta", "vitest/globals"] - }, - "include": ["./src/**/*.ts"], - "typeRoots": ["./src/types"] -} From 43ffb00996976af85042c505307d33995cf525ba Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:10:09 +0000 Subject: [PATCH 6/9] [autofix.ci] apply automated fixes --- .../setup/interfaces/mermaid.LayoutLoaderDefinition.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config/setup/interfaces/mermaid.LayoutLoaderDefinition.md b/docs/config/setup/interfaces/mermaid.LayoutLoaderDefinition.md index cb8e1a00b5..498aee75d1 100644 --- a/docs/config/setup/interfaces/mermaid.LayoutLoaderDefinition.md +++ b/docs/config/setup/interfaces/mermaid.LayoutLoaderDefinition.md @@ -16,7 +16,7 @@ #### Defined in -[packages/mermaid/src/rendering-util/render.ts:9](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L9) +[packages/mermaid/src/rendering-util/render.ts:11](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L11) --- @@ -26,7 +26,7 @@ #### Defined in -[packages/mermaid/src/rendering-util/render.ts:8](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L8) +[packages/mermaid/src/rendering-util/render.ts:10](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L10) --- @@ -36,4 +36,4 @@ #### Defined in -[packages/mermaid/src/rendering-util/render.ts:7](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L7) +[packages/mermaid/src/rendering-util/render.ts:9](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L9) From 50a535125ef5f1083c1dd33048d22b1f2f46948b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 15:29:08 +0530 Subject: [PATCH 7/9] chore: Use default export --- cypress/platform/flowchart-refactor.html | 2 +- cypress/platform/flowchart-sate.html | 2 +- cypress/platform/knsv2.html | 2 +- cypress/platform/state-refactor.html | 4 ++-- cypress/platform/viewer.js | 4 ++-- packages/mermaid-layout-elk/src/layouts.ts | 4 +++- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cypress/platform/flowchart-refactor.html b/cypress/platform/flowchart-refactor.html index 034e79a529..6d9ce423f7 100644 --- a/cypress/platform/flowchart-refactor.html +++ b/cypress/platform/flowchart-refactor.html @@ -822,7 +822,7 @@ - \ No newline at end of file + diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index 0b480b8bc3..77da253c27 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -1,7 +1,7 @@ -import mermaid from './mermaid.esm.mjs'; -import { layouts } from './mermaid-layout-elk.esm.mjs'; import externalExample from './mermaid-example-diagram.esm.mjs'; +import layouts from './mermaid-layout-elk.esm.mjs'; import zenUml from './mermaid-zenuml.esm.mjs'; +import mermaid from './mermaid.esm.mjs'; function b64ToUtf8(str) { return decodeURIComponent(escape(window.atob(str))); diff --git a/packages/mermaid-layout-elk/src/layouts.ts b/packages/mermaid-layout-elk/src/layouts.ts index a6075386b3..dc48ccbfae 100644 --- a/packages/mermaid-layout-elk/src/layouts.ts +++ b/packages/mermaid-layout-elk/src/layouts.ts @@ -3,7 +3,7 @@ import type { LayoutLoaderDefinition } from 'mermaid'; const loader = async () => await import(`./render.js`); const algos = ['elk.stress', 'elk.force', 'elk.mrtree', 'elk.sporeOverlap']; -export const layouts: LayoutLoaderDefinition[] = [ +const layouts: LayoutLoaderDefinition[] = [ { name: 'elk', loader, @@ -15,3 +15,5 @@ export const layouts: LayoutLoaderDefinition[] = [ algorithm: algo, })), ]; + +export default layouts; From db8a0028a69ceae63635d0e4911183d0fc64d270 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 16:22:10 +0530 Subject: [PATCH 8/9] docs: Add Readme --- packages/mermaid-layout-elk/README.md | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 packages/mermaid-layout-elk/README.md diff --git a/packages/mermaid-layout-elk/README.md b/packages/mermaid-layout-elk/README.md new file mode 100644 index 0000000000..65ad96c3d9 --- /dev/null +++ b/packages/mermaid-layout-elk/README.md @@ -0,0 +1,72 @@ +# @mermaid-js/layout-elk + +This package provides a layout engine for Mermaid based on the [ELK](https://www.eclipse.org/elk/) layout engine. + +> [!NOTE] +> The ELK Layout engine will not be available in all providers that support mermaid by default. +> The websites will have to install the `@mermaid-js/layout-elk` package to use the ELK layout engine. + +## Usage + +``` +flowchart-elk TD + A --> B + A --> C +``` + +``` +--- +config: + layout: elk +--- + +flowchart TD + A --> B + A --> C +``` + +``` +--- +config: + layout: elk.stress +--- + +flowchart TD + A --> B + A --> C +``` + +### With bundlers + +```sh +npm install @mermaid-js/layout-elk +``` + +```ts +import mermaid from 'mermaid'; +import elkLayouts from '@mermaid-js/layout-elk'; + +mermaid.registerLayoutLoaders(elkLayouts); +``` + +### With CDN + +```html + +``` + +## Supported layouts + +- `elk`: The default layout, which is `elk.layered`. +- `elk.layered`: Layered layout +- `elk.stress`: Stress layout +- `elk.force`: Force layout +- `elk.mrtree`: Multi-root tree layout +- `elk.sporeOverlap`: Spore overlap layout + + From 797877bcbfc48d3f29c6ab4ac445bd9e8ad63eb1 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 21 Aug 2024 16:23:56 +0530 Subject: [PATCH 9/9] chore: Use spaces --- packages/mermaid-layout-elk/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/mermaid-layout-elk/README.md b/packages/mermaid-layout-elk/README.md index 65ad96c3d9..c328032922 100644 --- a/packages/mermaid-layout-elk/README.md +++ b/packages/mermaid-layout-elk/README.md @@ -10,30 +10,30 @@ This package provides a layout engine for Mermaid based on the [ELK](https://www ``` flowchart-elk TD - A --> B - A --> C + A --> B + A --> C ``` ``` --- config: - layout: elk + layout: elk --- flowchart TD - A --> B - A --> C + A --> B + A --> C ``` ``` --- config: - layout: elk.stress + layout: elk.stress --- flowchart TD - A --> B - A --> C + A --> B + A --> C ``` ### With bundlers