feat(arch): dynamic node sizing

This commit is contained in:
NicolasNewman
2024-03-25 14:17:05 -05:00
parent 5e214877a4
commit a493e2fbb3
5 changed files with 33 additions and 22 deletions

View File

@@ -638,7 +638,7 @@ export interface RequirementDiagramConfig extends BaseDiagramConfig {
*/ */
export interface ArchitectureDiagramConfig extends BaseDiagramConfig { export interface ArchitectureDiagramConfig extends BaseDiagramConfig {
padding?: number; padding?: number;
maxNodeWidth?: number; iconSize?: number;
} }
/** /**
* The object containing configurations specific for mindmap diagrams * The object containing configurations specific for mindmap diagrams

View File

@@ -6,6 +6,7 @@ import type {
ArchitectureDirection, ArchitectureDirection,
ArchitectureLine, ArchitectureLine,
} from './architectureTypes.js'; } from './architectureTypes.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { isArchitectureDirection } from './architectureTypes.js'; import { isArchitectureDirection } from './architectureTypes.js';
import { import {
setAccTitle, setAccTitle,
@@ -36,10 +37,6 @@ let lines = DEFAULT_ARCHITECTURE_DB.lines;
let elements: Record<string, D3Element> = {}; let elements: Record<string, D3Element> = {};
let cnt = DEFAULT_ARCHITECTURE_DB.cnt; let cnt = DEFAULT_ARCHITECTURE_DB.cnt;
const config: Required<ArchitectureDiagramConfig> = structuredClone(DEFAULT_ARCHITECTURE_CONFIG);
const getConfig = (): Required<ArchitectureDiagramConfig> => structuredClone(config);
const clear = (): void => { const clear = (): void => {
services = structuredClone(DEFAULT_ARCHITECTURE_DB.services); services = structuredClone(DEFAULT_ARCHITECTURE_DB.services);
groups = structuredClone(DEFAULT_ARCHITECTURE_DB.groups); groups = structuredClone(DEFAULT_ARCHITECTURE_DB.groups);
@@ -109,7 +106,6 @@ const setElementForId = (id: string, element: D3Element) => {
const getElementById = (id: string) => elements[id]; const getElementById = (id: string) => elements[id];
export const db: ArchitectureDB = { export const db: ArchitectureDB = {
getConfig,
clear, clear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
@@ -127,3 +123,14 @@ export const db: ArchitectureDB = {
setElementForId, setElementForId,
getElementById, getElementById,
}; };
function getConfigField<T extends keyof ArchitectureDiagramConfig>(field: T): Required<ArchitectureDiagramConfig>[T] {
const arch = getConfig().architecture;
if (arch && arch[field] !== undefined) {
const a = arch[field];
return arch[field] as Required<ArchitectureDiagramConfig>[T]
}
return DEFAULT_ARCHITECTURE_CONFIG[field]
}
export { getConfigField }

View File

@@ -17,9 +17,9 @@ import {
} from './architectureTypes.js'; } from './architectureTypes.js';
import { select } from 'd3'; import { select } from 'd3';
import { setupGraphViewbox } from '../../setupGraphViewbox.js'; import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import defaultConfig from '../../defaultConfig.js';
import type { D3Element } from '../../mermaidAPI.js'; import type { D3Element } from '../../mermaidAPI.js';
import { drawEdges, drawGroups, drawService } from './svgDraw.js'; import { drawEdges, drawGroups, drawService } from './svgDraw.js';
import { getConfigField } from './architectureDb.js';
cytoscape.use(fcose); cytoscape.use(fcose);
@@ -33,9 +33,8 @@ function addServices(services: ArchitectureService[], cy: cytoscape.Core) {
icon: service.icon, icon: service.icon,
label: service.title, label: service.title,
parent: service.in, parent: service.in,
// TODO: dynamic size width: getConfigField('iconSize'),
width: 80, height: getConfigField('iconSize'),
height: 80,
}, },
classes: 'node-service', classes: 'node-service',
}); });
@@ -286,8 +285,8 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
setupGraphViewbox( setupGraphViewbox(
undefined, undefined,
svg, svg,
conf.architecture?.padding ?? defaultConfig.architecture.padding, getConfigField('padding'),
conf.architecture?.useMaxWidth ?? defaultConfig.architecture.useMaxWidth getConfigField('useMaxWidth')
); );
}; };

View File

@@ -8,6 +8,7 @@ import type { MermaidConfig } from '../../config.type.js';
import type cytoscape from 'cytoscape'; import type cytoscape from 'cytoscape';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getIcon, isIconNameInUse } from '../../rendering-util/svgRegister.js'; import { getIcon, isIconNameInUse } from '../../rendering-util/svgRegister.js';
import { getConfigField } from './architectureDb.js';
declare module 'cytoscape' { declare module 'cytoscape' {
interface EdgeSingular { interface EdgeSingular {
@@ -76,20 +77,23 @@ export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) {
}; };
export const drawGroups = function (groupsEl: D3Element, cy: cytoscape.Core) { export const drawGroups = function (groupsEl: D3Element, cy: cytoscape.Core) {
const iconSize = getConfigField('iconSize')
const halfIconSize = iconSize / 2
cy.nodes().map((node, id) => { cy.nodes().map((node, id) => {
const data = node.data(); const data = node.data();
if (data.type === 'group') { if (data.type === 'group') {
const { h, w, x1, x2, y1, y2 } = node.boundingBox(); const { h, w, x1, x2, y1, y2 } = node.boundingBox();
let bkgElem = groupsEl let bkgElem = groupsEl
.append('rect') .append('rect')
.attr('x', x1 + 40) .attr('x', x1 + halfIconSize)
.attr('y', y1 + 40) .attr('y', y1 + halfIconSize)
.attr('width', w) .attr('width', w)
.attr('height', h) .attr('height', h)
.attr('class', 'node-bkg'); .attr('class', 'node-bkg');
const textElem = groupsEl.append('g'); const textElem = groupsEl.append('g');
createText(textElem, data.title, { createText(textElem, data.label, {
useHtmlLabels: false, useHtmlLabels: false,
width: w, width: w,
classes: 'architecture-service-label', classes: 'architecture-service-label',
@@ -100,7 +104,7 @@ export const drawGroups = function (groupsEl: D3Element, cy: cytoscape.Core) {
.attr('dominant-baseline', 'start') .attr('dominant-baseline', 'start')
.attr('text-anchor', 'start'); .attr('text-anchor', 'start');
textElem.attr('transform', 'translate(' + (x1 + 44) + ', ' + (y1 + 42) + ')'); textElem.attr('transform', 'translate(' + (x1 + halfIconSize + 4) + ', ' + (y1 + halfIconSize + 2) + ')');
} }
}); });
}; };
@@ -112,6 +116,7 @@ export const drawService = function (
conf: MermaidConfig conf: MermaidConfig
): number { ): number {
const serviceElem = elem.append('g'); const serviceElem = elem.append('g');
const iconSize = getConfigField('iconSize')
if (service.title) { if (service.title) {
const textElem = serviceElem.append('g'); const textElem = serviceElem.append('g');
@@ -129,7 +134,7 @@ export const drawService = function (
textElem.attr( textElem.attr(
'transform', 'transform',
// TODO: dynamic size // TODO: dynamic size
'translate(' + 80 / 2 + ', ' + 80 + ')' 'translate(' + (iconSize / 2) + ', ' + iconSize + ')'
); );
} }
@@ -138,13 +143,13 @@ export const drawService = function (
if (!isIconNameInUse(service.icon)) { if (!isIconNameInUse(service.icon)) {
throw new Error(`Invalid SVG Icon name: "${service.icon}"`); throw new Error(`Invalid SVG Icon name: "${service.icon}"`);
} }
bkgElem = getIcon(service.icon)?.(bkgElem); bkgElem = getIcon(service.icon)?.(bkgElem, iconSize);
} else { } else {
bkgElem bkgElem
.append('path') .append('path')
.attr('class', 'node-bkg') .attr('class', 'node-bkg')
.attr('id', 'node-' + service.id) .attr('id', 'node-' + service.id)
.attr('d', `M0 ${80 - 0} v${-80 + 2 * 0} q0,-5 5,-5 h${80 - 2 * 0} q5,0 5,5 v${80 - 0} H0 Z`); .attr('d', `M0 ${iconSize - 0} v${-iconSize + 2 * 0} q0,-5 5,-5 h${iconSize - 2 * 0} q5,0 5,5 v${iconSize - 0} H0 Z`);
} }
serviceElem.attr('class', 'architecture-service'); serviceElem.attr('class', 'architecture-service');

View File

@@ -865,14 +865,14 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
required: required:
- useMaxWidth - useMaxWidth
- padding - padding
- maxNodeWidth - iconSize
properties: properties:
padding: padding:
type: number type: number
default: 10 default: 10
maxNodeWidth: iconSize:
type: number type: number
default: 200 default: 80
MindmapDiagramConfig: MindmapDiagramConfig:
title: Mindmap Diagram Config title: Mindmap Diagram Config