feat(arch): arrows now rendered on diagram

This commit is contained in:
NicolasNewman
2024-04-04 13:47:01 -05:00
parent 2709c2d2e1
commit 6d5791a63a
5 changed files with 68 additions and 10 deletions

View File

@@ -88,8 +88,10 @@ function addEdges(lines: ArchitectureLine[], cy: cytoscape.Core) {
id: `${line.lhs_id}-${line.rhs_id}`, id: `${line.lhs_id}-${line.rhs_id}`,
source: line.lhs_id, source: line.lhs_id,
sourceDir: line.lhs_dir, sourceDir: line.lhs_dir,
sourceArrow: line.lhs_into,
target: line.rhs_id, target: line.rhs_id,
targetDir: line.rhs_dir, targetDir: line.rhs_dir,
targetArrow: line.rhs_into,
}, },
}); });
}); });

View File

@@ -58,6 +58,9 @@ const getStyles: DiagramStylesProvider = (options: ArchitectureStyleOptions) =>
stroke-width: 3; stroke-width: 3;
stroke: #777; stroke: #777;
} }
.arrow {
fill: #777;
}
.section-root rect, .section-root path, .section-root circle, .section-root polygon { .section-root rect, .section-root path, .section-root circle, .section-root polygon {
fill: #333; fill: #333;
} }

View File

@@ -5,6 +5,7 @@ import type { D3Element } from '../../mermaidAPI.js';
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B'; export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>; export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>; export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
export const ArchitectureDirectionName = { export const ArchitectureDirectionName = {
L: 'left', L: 'left',
R: 'right', R: 'right',
@@ -12,6 +13,20 @@ export const ArchitectureDirectionName = {
B: 'bottom', B: 'bottom',
} as const; } 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 ( export const getOppositeArchitectureDirection = function (
x: ArchitectureDirection x: ArchitectureDirection
): ArchitectureDirection { ): ArchitectureDirection {

View File

@@ -18,9 +18,9 @@
<GROUP,SERVICE>\([\w]*\) return 'icon'; <GROUP,SERVICE>\([\w]*\) return 'icon';
<GROUP,SERVICE>\[[\w ]*\] return 'title'; <GROUP,SERVICE>\[[\w ]*\] return 'title';
[\w]+ { this.begin('LINE'); return 'id'; } [\w]+ { this.begin('LINE'); return 'id'; }
<LINE>\<[L|R|T|B]"-" return 'ARROW_LEFT_INTO'; <LINE>\([L|R|T|B]"-" return 'ARROW_LEFT_INTO';
<LINE>[L|R|T|B]"-" return 'ARROW_LEFT'; <LINE>[L|R|T|B]"-" return 'ARROW_LEFT';
<LINE>"-"[L|R|T|B]\> return 'ARROW_RIGHT_INTO'; <LINE>"-"[L|R|T|B]\) return 'ARROW_RIGHT_INTO';
<LINE>"-"[L|R|T|B] return 'ARROW_RIGHT'; <LINE>"-"[L|R|T|B] return 'ARROW_RIGHT';
<LINE>[\w]+ return 'id'; <LINE>[\w]+ return 'id';
<LINE>\[[\w ]*\] return 'title'; <LINE>\[[\w ]*\] return 'title';

View File

@@ -1,9 +1,13 @@
import type { D3Element } from '../../mermaidAPI.js'; import type { D3Element } from '../../mermaidAPI.js';
import { createText } from '../../rendering-util/createText.js'; import { createText } from '../../rendering-util/createText.js';
import type { import {
ArchitectureDB, ArchitectureDirectionArrow,
ArchitectureDirection, type ArchitectureDB,
ArchitectureService, type ArchitectureDirection,
type ArchitectureService,
ArchitectureDirectionArrowShift,
isArchitectureDirectionX,
isArchitectureDirectionY,
} from './architectureTypes.js'; } from './architectureTypes.js';
import type { MermaidConfig } from '../../config.type.js'; import type { MermaidConfig } from '../../config.type.js';
import type cytoscape from 'cytoscape'; import type cytoscape from 'cytoscape';
@@ -16,8 +20,10 @@ declare module 'cytoscape' {
id: string; id: string;
source: string; source: string;
sourceDir: ArchitectureDirection; sourceDir: ArchitectureDirection;
sourceArrow?: boolean;
target: string; target: string;
targetDir: ArchitectureDirection; targetDir: ArchitectureDirection;
targetArrow?: boolean;
[key: string]: any; [key: string]: any;
}; };
interface EdgeSingular { interface EdgeSingular {
@@ -70,19 +76,51 @@ declare module 'cytoscape' {
} }
export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) { 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) => { cy.edges().map((edge, id) => {
const data = edge.data(); const { source, sourceDir, sourceArrow, target, targetDir, targetArrow } = edge.data();
if (edge[0]._private.bodyBounds) { if (edge[0]._private.bodyBounds) {
const bounds = edge[0]._private.rscratch; const bounds = edge[0]._private.rscratch;
log.trace('Edge: ', id, data); const g = edgesEl.insert('g');
edgesEl
.insert('path') g.insert('path')
.attr( .attr(
'd', 'd',
`M ${bounds.startX},${bounds.startY} L ${bounds.midX},${bounds.midY} L${bounds.endX},${bounds.endY} ` `M ${bounds.startX},${bounds.startY} L ${bounds.midX},${bounds.midY} L${bounds.endX},${bounds.endY} `
) )
.attr('class', 'edge'); .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');
}
} }
}); });
}; };