feat(arch): extended parser to control how edges pass through groups

This commit is contained in:
NicolasNewman
2024-05-09 14:33:44 -05:00
parent 48e6901936
commit 5b6c95cea3
6 changed files with 211 additions and 143 deletions

View File

@@ -1,5 +1,6 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
@@ -120,6 +121,28 @@
</pre> </pre>
<hr /> <hr />
<h2>Group Edges</h2>
<pre class="mermaid">
architecture
group left_group(cloud)[Left]
group right_group(cloud)[Right]
group top_group(cloud)[Top]
group bottom_group(cloud)[Bottom]
group center_group(cloud)[Center]
service left_disk(disk)[Disk] in left_group
service right_disk(disk)[Disk] in right_group
service top_disk(disk)[Disk] in top_group
service bottom_disk(disk)[Disk] in bottom_group
service center_disk(disk)[Disk] in center_group
left_disk{group} (R--L) center_disk{group}
right_disk{group} (L--R) center_disk{group}
top_disk{group} (B--T) center_disk{group}
bottom_disk{group} (T--B) center_disk{group}
</pre>
<hr />
<h2>Edge Label Test</h2> <h2>Edge Label Test</h2>
<pre class="mermaid"> <pre class="mermaid">
architecture architecture
@@ -228,4 +251,5 @@
}; };
</script> </script>
</body> </body>
</html> </html>

View File

@@ -128,6 +128,8 @@ const addEdge = function ({
rhsDir, rhsDir,
lhsInto, lhsInto,
rhsInto, rhsInto,
lhsGroup,
rhsGroup,
title, title,
}: ArchitectureEdge) { }: ArchitectureEdge) {
if (!isArchitectureDirection(lhsDir)) { if (!isArchitectureDirection(lhsDir)) {
@@ -152,14 +154,29 @@ const addEdge = function ({
); );
} }
const lhsGroupId = state.records.services[lhsId].in
const rhsGroupId = state.records.services[rhsId].in
if (lhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
throw new Error(
`The left-hand id [${lhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
)
}
if (rhsGroup && lhsGroupId && rhsGroupId && lhsGroupId == rhsGroupId) {
throw new Error(
`The right-hand id [${rhsId}] is modified to traverse the group boundary, but the edge does not pass through two groups.`
)
}
const edge = { const edge = {
lhsId, lhsId,
lhsDir, lhsDir,
lhsInto,
lhsGroup,
rhsId, rhsId,
rhsDir, rhsDir,
title,
lhsInto,
rhsInto, rhsInto,
rhsGroup,
title,
}; };
state.records.edges.push(edge); state.records.edges.push(edge);

View File

@@ -84,7 +84,7 @@ function addGroups(groups: ArchitectureGroup[], cy: cytoscape.Core) {
function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) { function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
edges.forEach((parsedEdge) => { edges.forEach((parsedEdge) => {
const { lhsId, rhsId, lhsInto, rhsInto, lhsDir, rhsDir, title } = parsedEdge; const { lhsId, rhsId, lhsInto, lhsGroup, rhsInto, lhsDir, rhsDir, rhsGroup, title } = parsedEdge;
const edgeType = isArchitectureDirectionXY(parsedEdge.lhsDir, parsedEdge.rhsDir) const edgeType = isArchitectureDirectionXY(parsedEdge.lhsDir, parsedEdge.rhsDir)
? 'segments' ? 'segments'
: 'straight'; : 'straight';
@@ -94,6 +94,7 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
source: lhsId, source: lhsId,
sourceDir: lhsDir, sourceDir: lhsDir,
sourceArrow: lhsInto, sourceArrow: lhsInto,
sourceGroup: lhsGroup,
sourceEndpoint: sourceEndpoint:
lhsDir === 'L' lhsDir === 'L'
? '0 50%' ? '0 50%'
@@ -105,6 +106,7 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
target: rhsId, target: rhsId,
targetDir: rhsDir, targetDir: rhsDir,
targetArrow: rhsInto, targetArrow: rhsInto,
targetGroup: rhsGroup,
targetEndpoint: targetEndpoint:
rhsDir === 'L' rhsDir === 'L'
? '0 50%' ? '0 50%'

View File

@@ -199,11 +199,13 @@ export interface ArchitectureGroup {
export interface ArchitectureEdge { export interface ArchitectureEdge {
lhsId: string; lhsId: string;
lhsDir: ArchitectureDirection; lhsDir: ArchitectureDirection;
title?: string; lhsInto?: boolean;
lhsGroup?: boolean;
rhsId: string; rhsId: string;
rhsDir: ArchitectureDirection; rhsDir: ArchitectureDirection;
lhsInto?: boolean;
rhsInto?: boolean; rhsInto?: boolean;
rhsGroup?: boolean;
title?: string;
} }
export interface ArchitectureDB extends DiagramDB { export interface ArchitectureDB extends DiagramDB {
@@ -246,9 +248,11 @@ export type EdgeSingularData = {
source: string; source: string;
sourceDir: ArchitectureDirection; sourceDir: ArchitectureDirection;
sourceArrow?: boolean; sourceArrow?: boolean;
sourceGroup?: boolean;
target: string; target: string;
targetDir: ArchitectureDirection; targetDir: ArchitectureDirection;
targetArrow?: boolean; targetArrow?: boolean;
targetGroup?: boolean;
[key: string]: any; [key: string]: any;
}; };

View File

@@ -22,17 +22,37 @@ import { getConfigField } from './architectureDb.js';
import { getConfig } from '../../diagram-api/diagramAPI.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) { export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) {
const padding = getConfigField('padding');
const iconSize = getConfigField('iconSize'); const iconSize = getConfigField('iconSize');
const arrowSize = iconSize / 6; const arrowSize = iconSize / 6;
const halfArrowSize = arrowSize / 2; const halfArrowSize = arrowSize / 2;
cy.edges().map((edge, id) => { cy.edges().map((edge, id) => {
const { sourceDir, sourceArrow, targetDir, targetArrow, label } = edgeData(edge); const { sourceDir, sourceArrow, sourceGroup, targetDir, targetArrow, targetGroup, label } = edgeData(edge);
const { x: startX, y: startY } = edge[0].sourceEndpoint(); let { x: startX, y: startY } = edge[0].sourceEndpoint();
const { x: midX, y: midY } = edge[0].midpoint(); const { x: midX, y: midY } = edge[0].midpoint();
const { x: endX, y: endY } = edge[0].targetEndpoint(); let { x: endX, y: endY } = edge[0].targetEndpoint();
const groupEdgeShift = padding + 4;
// +18 comes from the service label height that extends the padding on the bottom side of each group
if (sourceGroup) {
if (isArchitectureDirectionX(sourceDir)) {
sourceDir === 'L' ? startX -= groupEdgeShift : startX += groupEdgeShift;
} else {
sourceDir === 'T' ? startY -= groupEdgeShift : startY += (groupEdgeShift + 18);
}
}
if (targetGroup) {
if (isArchitectureDirectionX(targetDir)) {
targetDir === 'L' ? endX -= groupEdgeShift : endX += groupEdgeShift;
} else {
targetDir === 'T' ? endY -= groupEdgeShift : endY += (groupEdgeShift + 18);
}
}
if (edge[0]._private.rscratch) { if (edge[0]._private.rscratch) {
const bounds = edge[0]._private.rscratch; // const bounds = edge[0]._private.rscratch;
const g = edgesEl.insert('g'); const g = edgesEl.insert('g');
@@ -42,11 +62,11 @@ export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) {
if (sourceArrow) { if (sourceArrow) {
const xShift = isArchitectureDirectionX(sourceDir) const xShift = isArchitectureDirectionX(sourceDir)
? ArchitectureDirectionArrowShift[sourceDir](bounds.startX, arrowSize) ? ArchitectureDirectionArrowShift[sourceDir](startX, arrowSize)
: bounds.startX - halfArrowSize; : startX - halfArrowSize;
const yShift = isArchitectureDirectionY(sourceDir) const yShift = isArchitectureDirectionY(sourceDir)
? ArchitectureDirectionArrowShift[sourceDir](bounds.startY, arrowSize) ? ArchitectureDirectionArrowShift[sourceDir](startY, arrowSize)
: bounds.startY - halfArrowSize; : startY - halfArrowSize;
g.insert('polygon') g.insert('polygon')
.attr('points', ArchitectureDirectionArrow[sourceDir](arrowSize)) .attr('points', ArchitectureDirectionArrow[sourceDir](arrowSize))
@@ -55,11 +75,11 @@ export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) {
} }
if (targetArrow) { if (targetArrow) {
const xShift = isArchitectureDirectionX(targetDir) const xShift = isArchitectureDirectionX(targetDir)
? ArchitectureDirectionArrowShift[targetDir](bounds.endX, arrowSize) ? ArchitectureDirectionArrowShift[targetDir](endX, arrowSize)
: bounds.endX - halfArrowSize; : endX - halfArrowSize;
const yShift = isArchitectureDirectionY(targetDir) const yShift = isArchitectureDirectionY(targetDir)
? ArchitectureDirectionArrowShift[targetDir](bounds.endY, arrowSize) ? ArchitectureDirectionArrowShift[targetDir](endY, arrowSize)
: bounds.endY - halfArrowSize; : endY - halfArrowSize;
g.insert('polygon') g.insert('polygon')
.attr('points', ArchitectureDirectionArrow[targetDir](arrowSize)) .attr('points', ArchitectureDirectionArrow[targetDir](arrowSize))

View File

@@ -30,7 +30,7 @@ Service:
; ;
Edge: Edge:
lhsId=ARCH_ID Arrow rhsId=ARCH_ID EOL lhsId=ARCH_ID lhsGroup?=ARROW_GROUP? Arrow rhsId=ARCH_ID rhsGroup?=ARROW_GROUP? EOL
; ;
terminal ARROW_DIRECTION: 'L' | 'R' | 'T' | 'B'; terminal ARROW_DIRECTION: 'L' | 'R' | 'T' | 'B';
@@ -38,4 +38,5 @@ terminal ARCH_ID: /[\w]+/;
terminal ARCH_TEXT_ICON: /\("[^"]+"\)/; terminal ARCH_TEXT_ICON: /\("[^"]+"\)/;
terminal ARCH_ICON: /\([\w]+\)/; terminal ARCH_ICON: /\([\w]+\)/;
terminal ARCH_TITLE: /\[[\w ]+\]/; terminal ARCH_TITLE: /\[[\w ]+\]/;
terminal ARROW_GROUP: /\{group\}/;
terminal ARROW_INTO: /\(|\)/; terminal ARROW_INTO: /\(|\)/;