From 6d5791a63a31a6a2975766724b1c6ff4fc6ddb0f Mon Sep 17 00:00:00 2001 From: NicolasNewman Date: Thu, 4 Apr 2024 13:47:01 -0500 Subject: [PATCH] feat(arch): arrows now rendered on diagram --- .../architecture/architectureRenderer.ts | 2 + .../architecture/architectureStyles.ts | 3 ++ .../architecture/architectureTypes.ts | 15 ++++++ .../architecture/parser/architecture.jison | 4 +- .../src/diagrams/architecture/svgDraw.ts | 54 ++++++++++++++++--- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts b/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts index 0ebd6abeb..e38af6927 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts @@ -88,8 +88,10 @@ function addEdges(lines: ArchitectureLine[], cy: cytoscape.Core) { id: `${line.lhs_id}-${line.rhs_id}`, source: line.lhs_id, sourceDir: line.lhs_dir, + sourceArrow: line.lhs_into, target: line.rhs_id, targetDir: line.rhs_dir, + targetArrow: line.rhs_into, }, }); }); diff --git a/packages/mermaid/src/diagrams/architecture/architectureStyles.ts b/packages/mermaid/src/diagrams/architecture/architectureStyles.ts index 7cdcbf4ae..3a02a1fa6 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureStyles.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureStyles.ts @@ -58,6 +58,9 @@ const getStyles: DiagramStylesProvider = (options: ArchitectureStyleOptions) => stroke-width: 3; stroke: #777; } + .arrow { + fill: #777; + } .section-root rect, .section-root path, .section-root circle, .section-root polygon { fill: #333; } diff --git a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts index 38bb31775..fb07d9e37 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts @@ -5,6 +5,7 @@ import type { D3Element } from '../../mermaidAPI.js'; export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B'; export type ArchitectureDirectionX = Extract; export type ArchitectureDirectionY = Extract; + export const ArchitectureDirectionName = { L: 'left', R: 'right', @@ -12,6 +13,20 @@ export const ArchitectureDirectionName = { B: 'bottom', } as const; +export const ArchitectureDirectionArrow = { + L: (scale: number) => `${scale},${scale / 2} 0,${scale} 0,0`, + R: (scale: number) => `0,${scale / 2} ${scale},0 ${scale},${scale}`, + T: (scale: number) => `0,0 ${scale},0 ${scale / 2},${scale}`, + B: (scale: number) => `${scale / 2},0 ${scale},${scale} 0,${scale}`, +} as const; + +export const ArchitectureDirectionArrowShift = { + L: (orig: number, iconSize: number, arrowSize: number) => orig - iconSize / 2 - arrowSize + 2, + R: (orig: number, iconSize: number, arrowSize: number) => orig + iconSize / 2 - 2, + T: (orig: number, iconSize: number, arrowSize: number) => orig - iconSize / 2 - arrowSize + 2, + B: (orig: number, iconSize: number, arrowSize: number) => orig + iconSize / 2 - 2, +} as const; + export const getOppositeArchitectureDirection = function ( x: ArchitectureDirection ): ArchitectureDirection { diff --git a/packages/mermaid/src/diagrams/architecture/parser/architecture.jison b/packages/mermaid/src/diagrams/architecture/parser/architecture.jison index d92a1d1db..8f96cc383 100644 --- a/packages/mermaid/src/diagrams/architecture/parser/architecture.jison +++ b/packages/mermaid/src/diagrams/architecture/parser/architecture.jison @@ -18,9 +18,9 @@ \([\w]*\) return 'icon'; \[[\w ]*\] return 'title'; [\w]+ { this.begin('LINE'); return 'id'; } -\<[L|R|T|B]"-" return 'ARROW_LEFT_INTO'; +\([L|R|T|B]"-" return 'ARROW_LEFT_INTO'; [L|R|T|B]"-" return 'ARROW_LEFT'; -"-"[L|R|T|B]\> return 'ARROW_RIGHT_INTO'; +"-"[L|R|T|B]\) return 'ARROW_RIGHT_INTO'; "-"[L|R|T|B] return 'ARROW_RIGHT'; [\w]+ return 'id'; \[[\w ]*\] return 'title'; diff --git a/packages/mermaid/src/diagrams/architecture/svgDraw.ts b/packages/mermaid/src/diagrams/architecture/svgDraw.ts index c643a51da..8c27550f1 100644 --- a/packages/mermaid/src/diagrams/architecture/svgDraw.ts +++ b/packages/mermaid/src/diagrams/architecture/svgDraw.ts @@ -1,9 +1,13 @@ import type { D3Element } from '../../mermaidAPI.js'; import { createText } from '../../rendering-util/createText.js'; -import type { - ArchitectureDB, - ArchitectureDirection, - ArchitectureService, +import { + ArchitectureDirectionArrow, + type ArchitectureDB, + type ArchitectureDirection, + type ArchitectureService, + ArchitectureDirectionArrowShift, + isArchitectureDirectionX, + isArchitectureDirectionY, } from './architectureTypes.js'; import type { MermaidConfig } from '../../config.type.js'; import type cytoscape from 'cytoscape'; @@ -16,8 +20,10 @@ declare module 'cytoscape' { id: string; source: string; sourceDir: ArchitectureDirection; + sourceArrow?: boolean; target: string; targetDir: ArchitectureDirection; + targetArrow?: boolean; [key: string]: any; }; interface EdgeSingular { @@ -70,19 +76,51 @@ declare module 'cytoscape' { } export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) { + const iconSize = getConfigField('iconSize'); + const halfIconSize = iconSize / 2; + const arrowSize = iconSize / 6; + const halfArrowSize = arrowSize / 2; cy.edges().map((edge, id) => { - const data = edge.data(); + const { source, sourceDir, sourceArrow, target, targetDir, targetArrow } = edge.data(); if (edge[0]._private.bodyBounds) { const bounds = edge[0]._private.rscratch; - log.trace('Edge: ', id, data); - edgesEl - .insert('path') + const g = edgesEl.insert('g'); + + g.insert('path') .attr( 'd', `M ${bounds.startX},${bounds.startY} L ${bounds.midX},${bounds.midY} L${bounds.endX},${bounds.endY} ` ) .attr('class', 'edge'); + + if (sourceArrow) { + console.log(`New source arrow: ${sourceDir} for ${source}`); + const xShift = isArchitectureDirectionX(sourceDir) + ? ArchitectureDirectionArrowShift[sourceDir](bounds.startX, iconSize, arrowSize) + : bounds.startX - halfArrowSize; + const yShift = isArchitectureDirectionY(sourceDir) + ? ArchitectureDirectionArrowShift[sourceDir](bounds.startY, iconSize, arrowSize) + : bounds.startY - halfArrowSize; + + g.insert('polygon') + .attr('points', ArchitectureDirectionArrow[sourceDir](arrowSize)) + .attr('transform', `translate(${xShift},${yShift})`) + .attr('class', 'arrow'); + } + if (targetArrow) { + console.log(`New target arrow: ${targetDir} for ${target}`); + const xShift = isArchitectureDirectionX(targetDir) + ? ArchitectureDirectionArrowShift[targetDir](bounds.endX, iconSize, arrowSize) + : bounds.endX - halfArrowSize; + const yShift = isArchitectureDirectionY(targetDir) + ? ArchitectureDirectionArrowShift[targetDir](bounds.endY, iconSize, arrowSize) + : bounds.endY - halfArrowSize; + g.insert('polygon') + .attr('points', ArchitectureDirectionArrow[targetDir](arrowSize)) + .attr('transform', `translate(${xShift},${yShift})`) + .attr('class', 'arrow'); + } } }); };