fix: ensure architecture diagram uses unified rendering

on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
This commit is contained in:
darshanr0107
2025-09-29 15:13:19 +05:30
parent 7effdc147b
commit 0a23304d1a
4 changed files with 200 additions and 14 deletions

View File

@@ -3,7 +3,9 @@ import type { ArchitectureDiagramConfig } from '../../config.type.js';
import DEFAULT_CONFIG from '../../defaultConfig.js';
import type { DiagramDB } from '../../diagram-api/types.js';
import type { D3Element } from '../../types.js';
import { cleanAndMerge } from '../../utils.js';
import { cleanAndMerge, getEdgeId } from '../../utils.js';
import type { LayoutData, Node, Edge } from '../../rendering-util/types.js';
import {
clear as commonClear,
getAccDescription,
@@ -351,15 +353,147 @@ export class ArchitectureDB implements DiagramDB {
public getDiagramTitle = getDiagramTitle;
public getAccDescription = getAccDescription;
public setAccDescription = setAccDescription;
}
/**
* Typed wrapper for resolving an architecture diagram's config fields. Returns the default value if undefined
* @param field - the config field to access
* @returns
*/
// export function getConfigField<T extends keyof ArchitectureDiagramConfig>(
// field: T
// ): Required<ArchitectureDiagramConfig>[T] {
// return db.getConfig()[field];
// }
/**
* Converts architecture diagram data to LayoutData format for unified rendering
*/
public getData(): LayoutData {
const config = commonGetConfig();
const nodes: Node[] = [];
const edges: Edge[] = [];
const groups = this.getGroups();
for (const group of groups) {
const padding = this.getConfigField('padding');
const fontSize = this.getConfigField('fontSize');
const groupWidth = 200;
let groupHeight = 150;
if (group.title || group.icon) {
groupHeight += fontSize + padding;
}
nodes.push({
id: group.id,
label: group.title,
parentId: group.in,
isGroup: true,
shape: 'rect',
icon: group.icon,
width: groupWidth,
height: groupHeight,
padding: padding,
cssClasses: 'architecture-group',
cssCompiledStyles: [
'stroke: #cccccc',
'stroke-width: 2px',
'stroke-dasharray: 8,8',
'fill: transparent',
],
labelStyle: '',
look: config.look || 'classic',
rx: 5,
ry: 5,
});
}
const services = this.getServices();
for (const service of services) {
const iconSize = this.getConfigField('iconSize');
let nodeWidth = iconSize;
let nodeHeight = iconSize;
if (service.title) {
nodeHeight += iconSize * 0.3;
nodeWidth = Math.max(nodeWidth, iconSize * 1.5);
}
nodes.push({
id: service.id,
label: service.title,
parentId: service.in,
isGroup: false,
shape: service.icon || (service as any).iconText ? 'icon' : 'squareRect',
icon: service.icon ? `mermaid-architecture:${service.icon}` : 'mermaid-architecture:blank',
width: service.width || nodeWidth,
height: service.height || nodeHeight,
cssClasses: 'architecture-service',
look: config.look,
padding: this.getConfigField('padding') / 4,
description: (service as any).iconText ? [(service as any).iconText] : undefined,
assetWidth: iconSize,
assetHeight: iconSize,
});
}
const junctions = this.getJunctions();
for (const junction of junctions) {
nodes.push({
id: junction.id,
parentId: junction.in,
isGroup: false,
shape: 'squareRect',
width: 2,
height: 2,
cssClasses: 'architecture-junction',
look: config.look,
type: 'junction' as any,
padding: 0,
});
}
const architectureEdges = this.getEdges();
let edgeCounter = 0;
for (const edge of architectureEdges) {
const edgeData = {
id: getEdgeId(edge.lhsId, edge.rhsId, { counter: edgeCounter, prefix: 'L' }),
start: edge.lhsId,
end: edge.rhsId,
source: edge.lhsId,
target: edge.rhsId,
label: edge.title || '',
labelpos: 'c',
type: 'normal',
minlen: 2,
weight: 1,
classes: 'edge-thickness-normal edge-pattern-solid architecture-edge',
look: config.look || 'classic',
curve: 'linear',
arrowTypeStart: edge.lhsInto ? 'point' : 'none',
arrowTypeEnd: edge.rhsInto ? 'point' : 'none',
arrowheadStyle: 'fill: #333',
thickness: 'normal',
pattern: 'solid',
style: ['stroke: #333333', 'stroke-width: 3px', 'fill: none'],
cssCompiledStyles: [],
labelStyle: [],
lhsDir: edge.lhsDir,
rhsDir: edge.rhsDir,
lhsInto: edge.lhsInto,
rhsInto: edge.rhsInto,
lhsGroup: edge.lhsGroup,
rhsGroup: edge.rhsGroup,
} as Edge & {
lhsDir: any;
rhsDir: any;
lhsInto?: boolean;
rhsInto?: boolean;
lhsGroup?: boolean;
rhsGroup?: boolean;
};
edges.push(edgeData);
edgeCounter++;
}
const result = {
nodes,
edges,
config,
dataStructures: this.getDataStructures(),
};
return result;
}
}

View File

@@ -2,7 +2,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
import { parser } from './architectureParser.js';
import { ArchitectureDB } from './architectureDb.js';
import styles from './architectureStyles.js';
import { renderer } from './architectureRenderer.js';
import { renderer } from './architectureRenderer-unified.js';
export const diagram: DiagramDefinition = {
parser,

View File

@@ -0,0 +1,50 @@
import { getConfig } from '../../diagram-api/diagramAPI.js';
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.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';
import { registerIconPacks } from '../../rendering-util/icons.js';
import { architectureIcons } from './architectureIcons.js';
export const getClasses = function (
_text: string,
_diagramObj: any
): Map<string, DiagramStyleClassDef> {
return new Map();
};
export const draw = async function (_text: string, id: string, _version: string, diag: any) {
registerIconPacks([
{
name: architectureIcons.prefix,
icons: architectureIcons,
},
]);
const { securityLevel, architecture: conf, layout } = getConfig();
const data4Layout = diag.db.getData() as LayoutData;
const svg = getDiagramElement(id, securityLevel);
data4Layout.type = diag.type;
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout, { fallback: 'dagre' });
data4Layout.nodeSpacing = 100;
data4Layout.rankSpacing = 100;
data4Layout.markers = ['point'];
data4Layout.diagramId = id;
log.debug('Architecture layout data:', data4Layout);
await render(data4Layout, svg);
const padding = conf?.padding ?? 8;
utils.insertTitle(svg, 'architectureTitleText', 0, diag.db.getDiagramTitle());
setupViewPortForSVG(svg, padding, 'architecture', conf?.useMaxWidth ?? true);
};
export const renderer = { draw };

View File

@@ -2,6 +2,7 @@ import type { DiagramDBBase } from '../../diagram-api/types.js';
import type { ArchitectureDiagramConfig } from '../../config.type.js';
import type { D3Element } from '../../types.js';
import type cytoscape from 'cytoscape';
import type { LayoutData } from '../../rendering-util/types.js';
/*=======================================*\
| Architecture Diagram Types |
@@ -256,7 +257,8 @@ export interface ArchitectureDB extends DiagramDBBase<ArchitectureDiagramConfig>
getEdges: () => ArchitectureEdge[];
setElementForId: (id: string, element: D3Element) => void;
getElementById: (id: string) => D3Element;
getDataStructures: () => ArchitectureDataStructures;
getData: () => LayoutData;
getDirection: () => string;
}
export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;