style(arch): prettier formatting & code cleanup

This commit is contained in:
NicolasNewman 2024-04-04 09:58:58 -05:00
parent 92d819ede5
commit 2709c2d2e1
11 changed files with 244 additions and 199 deletions

View File

@ -10,7 +10,11 @@ import type {
ArchitectureSpatialMap,
} from './architectureTypes.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { getArchitectureDirectionPair, isArchitectureDirection, shiftPositionByArchitectureDirectionPair } from './architectureTypes.js';
import {
getArchitectureDirectionPair,
isArchitectureDirection,
shiftPositionByArchitectureDirectionPair,
} from './architectureTypes.js';
import {
setAccTitle,
getAccTitle,
@ -54,14 +58,16 @@ const clear = (): void => {
const addService = function (id: string, opts: Omit<ArchitectureService, 'id' | 'edges'> = {}) {
const { icon, in: inside, title } = opts;
if (registeredIds[id] !== undefined) {
throw new Error(`The service id [${id}] is already in use by another ${registeredIds[id]}`)
throw new Error(`The service id [${id}] is already in use by another ${registeredIds[id]}`);
}
if (inside !== undefined) {
if (id === inside) {
throw new Error(`The service [${id}] cannot be placed within itself`)
throw new Error(`The service [${id}] cannot be placed within itself`);
}
if (registeredIds[inside] === undefined) {
throw new Error(`The service [${id}]'s parent does not exist. Please make sure the parent is created before this service`)
throw new Error(
`The service [${id}]'s parent does not exist. Please make sure the parent is created before this service`
);
}
if (registeredIds[inside] === 'service') {
throw new Error(`The service [${id}]'s parent is not a group`);
@ -84,14 +90,16 @@ const getServices = (): ArchitectureService[] => Object.values(services);
const addGroup = function (id: string, opts: Omit<ArchitectureGroup, 'id'> = {}) {
const { icon, in: inside, title } = opts;
if (registeredIds[id] !== undefined) {
throw new Error(`The group id [${id}] is already in use by another ${registeredIds[id]}`)
throw new Error(`The group id [${id}] is already in use by another ${registeredIds[id]}`);
}
if (inside !== undefined) {
if (id === inside) {
throw new Error(`The group [${id}] cannot be placed within itself`)
throw new Error(`The group [${id}] cannot be placed within itself`);
}
if (registeredIds[inside] === undefined) {
throw new Error(`The group [${id}]'s parent does not exist. Please make sure the parent is created before this group`)
throw new Error(
`The group [${id}]'s parent does not exist. Please make sure the parent is created before this group`
);
}
if (registeredIds[inside] === 'service') {
throw new Error(`The group [${id}]'s parent is not a group`);
@ -108,77 +116,85 @@ const addGroup = function (id: string, opts: Omit<ArchitectureGroup, 'id'> = {})
});
};
const getGroups = (): ArchitectureGroup[] => {
return groups
return groups;
};
const getDataStructures = () => {
console.log('===== createSpatialMap =====')
console.log('===== createSpatialMap =====');
if (datastructures === undefined) {
// Create an adjacency list of the diagram to perform BFS on
// Outer reduce applied on all services
// Inner reduce applied on the edges for a service
const adjList = Object.entries(services).reduce<{[id: string]: ArchitectureDirectionPairMap}>((prev, [id, service]) => {
prev[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prev, edge) => {
if (edge.lhs_id === id) { // source is LHS
const pair = getArchitectureDirectionPair(edge.lhs_dir, edge.rhs_dir);
if (pair) {
prev[pair] = edge.rhs_id
const adjList = Object.entries(services).reduce<{ [id: string]: ArchitectureDirectionPairMap }>(
(prev, [id, service]) => {
prev[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prev, edge) => {
if (edge.lhs_id === id) {
// source is LHS
const pair = getArchitectureDirectionPair(edge.lhs_dir, edge.rhs_dir);
if (pair) {
prev[pair] = edge.rhs_id;
}
} else {
// source is RHS
const pair = getArchitectureDirectionPair(edge.rhs_dir, edge.lhs_dir);
if (pair) {
prev[pair] = edge.lhs_id;
}
}
} else { // source is RHS
const pair = getArchitectureDirectionPair(edge.rhs_dir, edge.lhs_dir);
if (pair) {
prev[pair] = edge.lhs_id
}
}
return prev;
}, {});
return prev;
}, {})
return prev
}, {});
},
{}
);
// Configuration for the initial pass of BFS
const [firstId, _] = Object.entries(adjList)[0];
const visited = {[firstId]: 1};
const notVisited = Object.keys(adjList).reduce((prev, id) => (
id === firstId ? prev : {...prev, [id]: 1}
), {} as Record<string, number>);
const visited = { [firstId]: 1 };
const notVisited = Object.keys(adjList).reduce(
(prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
{} as Record<string, number>
);
// Perform BFS on adjacency list
const BFS = (startingId: string): ArchitectureSpatialMap => {
const spatialMap = {[startingId]: [0,0]};
const spatialMap = { [startingId]: [0, 0] };
const queue = [startingId];
while(queue.length > 0) {
while (queue.length > 0) {
const id = queue.shift();
if (id) {
visited[id] = 1
delete notVisited[id]
visited[id] = 1;
delete notVisited[id];
const adj = adjList[id];
const [posX, posY] = spatialMap[id];
Object.entries(adj).forEach(([dir, rhsId]) => {
if (!visited[rhsId]) {
console.log(`${id} -- ${rhsId}`);
spatialMap[rhsId] = shiftPositionByArchitectureDirectionPair([posX, posY], dir as ArchitectureDirectionPair)
spatialMap[rhsId] = shiftPositionByArchitectureDirectionPair(
[posX, posY],
dir as ArchitectureDirectionPair
);
queue.push(rhsId);
}
})
});
}
}
return spatialMap;
}
};
const spatialMaps = [BFS(firstId)];
// If our diagram is disconnected, keep adding additional spatial maps until all disconnected graphs have been found
while (Object.keys(notVisited).length > 0) {
spatialMaps.push(BFS(Object.keys(notVisited)[0]))
spatialMaps.push(BFS(Object.keys(notVisited)[0]));
}
datastructures = {
adjList,
spatialMaps
}
console.log(datastructures)
spatialMaps,
};
console.log(datastructures);
}
return datastructures;
}
};
const addLine = function (
lhs_id: string,
@ -217,12 +233,12 @@ const addLine = function (
title,
lhs_into,
rhs_into,
}
};
lines.push(edge);
services[lhs_id].edges.push(lines[lines.length - 1])
services[rhs_id].edges.push(lines[lines.length - 1])
services[lhs_id].edges.push(lines[lines.length - 1]);
services[rhs_id].edges.push(lines[lines.length - 1]);
};
const getLines = (): ArchitectureLine[] => lines;
@ -251,13 +267,15 @@ export const db: ArchitectureDB = {
getDataStructures,
};
function getConfigField<T extends keyof ArchitectureDiagramConfig>(field: T): Required<ArchitectureDiagramConfig>[T] {
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 arch[field] as Required<ArchitectureDiagramConfig>[T];
}
return DEFAULT_ARCHITECTURE_CONFIG[field]
return DEFAULT_ARCHITECTURE_CONFIG[field];
}
export { getConfigField }
export { getConfigField };

View File

@ -73,7 +73,7 @@ function positionServices(db: ArchitectureDB, cy: cytoscape.Core) {
if (data.type === 'group') return;
data.x = node.position().x;
data.y = node.position().y;
console.log(`Position service (${data.id}): (${data.x}, ${data.y})`)
console.log(`Position service (${data.id}): (${data.x}, ${data.y})`);
const nodeElem = db.getElementById(data.id);
nodeElem.attr('transform', 'translate(' + (data.x || 0) + ',' + (data.y || 0) + ')');
@ -99,7 +99,7 @@ function layoutArchitecture(
services: ArchitectureService[],
groups: ArchitectureGroup[],
lines: ArchitectureLine[],
{adjList, spatialMaps}: ArchitectureDataStructures
{ spatialMaps }: ArchitectureDataStructures
): Promise<cytoscape.Core> {
return new Promise((resolve) => {
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
@ -155,82 +155,91 @@ function layoutArchitecture(
// Use the spatial map to create alignment arrays for fcose
const [horizontalAlignments, verticalAlignments] = (() => {
const alignments = spatialMaps.map(spatialMap => {
const _horizontalAlignments: Record<number, string[]> = {}
const _verticalAlignments: Record<number, string[]> = {}
const alignments = spatialMaps.map((spatialMap) => {
const _horizontalAlignments: Record<number, string[]> = {};
const _verticalAlignments: Record<number, string[]> = {};
// Group service ids in an object with their x and y coordinate as the key
Object.entries(spatialMap).forEach(([id, [x, y]]) => {
if (!_horizontalAlignments[y]) _horizontalAlignments[y] = [];
if (!_verticalAlignments[x]) _verticalAlignments[x] = [];
_horizontalAlignments[y].push(id);
_verticalAlignments[x].push(id);
})
});
// Merge the values of each object into a list if the inner list has at least 2 elements
return {
horiz: Object.values(_horizontalAlignments).filter(arr => arr.length > 1),
vert: Object.values(_verticalAlignments).filter(arr => arr.length > 1)
}
})
horiz: Object.values(_horizontalAlignments).filter((arr) => arr.length > 1),
vert: Object.values(_verticalAlignments).filter((arr) => arr.length > 1),
};
});
// Merge the alginment lists for each spatial map into one 2d array per axis
return alignments.reduce(([prevHoriz, prevVert], {horiz, vert}) => {
return [[...prevHoriz, ...horiz], [...prevVert, ...vert]]
}, [[] as string[][], [] as string[][]])
return alignments.reduce(
([prevHoriz, prevVert], { horiz, vert }) => {
return [
[...prevHoriz, ...horiz],
[...prevVert, ...vert],
];
},
[[] as string[][], [] as string[][]]
);
})();
// Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
const relativeConstraints = (() => {
const _relativeConstraints: fcose.FcoseRelativePlacementConstraint[] = []
const posToStr = (pos: number[]) => `${pos[0]},${pos[1]}`
const strToPos = (pos: string) => pos.split(',').map(p => parseInt(p));
const _relativeConstraints: fcose.FcoseRelativePlacementConstraint[] = [];
const posToStr = (pos: number[]) => `${pos[0]},${pos[1]}`;
const strToPos = (pos: string) => pos.split(',').map((p) => parseInt(p));
spatialMaps.forEach(spatialMap => {
const invSpatialMap = Object.fromEntries(Object.entries(spatialMap).map(([id, pos]) => [posToStr(pos), id]))
console.log('===== invSpatialMap =====')
spatialMaps.forEach((spatialMap) => {
const invSpatialMap = Object.fromEntries(
Object.entries(spatialMap).map(([id, pos]) => [posToStr(pos), id])
);
console.log('===== invSpatialMap =====');
console.log(invSpatialMap);
// perform BFS
const queue = [posToStr([0,0])];
const queue = [posToStr([0, 0])];
const visited: Record<string, number> = {};
const directions: Record<ArchitectureDirection, number[]> = {
"L": [-1, 0],
"R": [1, 0],
"T": [0, 1],
"B": [0, -1]
}
L: [-1, 0],
R: [1, 0],
T: [0, 1],
B: [0, -1],
};
while (queue.length > 0) {
const curr = queue.shift();
if (curr) {
visited[curr] = 1
visited[curr] = 1;
const currId = invSpatialMap[curr];
if (currId) {
const currPos = strToPos(curr);
Object.entries(directions).forEach(([dir, shift]) => {
const newPos = posToStr([(currPos[0]+shift[0]), (currPos[1]+shift[1])]);
const newPos = posToStr([currPos[0] + shift[0], currPos[1] + shift[1]]);
const newId = invSpatialMap[newPos];
// If there is an adjacent service to the current one and it has not yet been visited
if (newId && !visited[newPos]) {
if (newId && !visited[newPos]) {
queue.push(newPos);
// @ts-ignore cannot determine if left/right or top/bottom are paired together
_relativeConstraints.push({
[ArchitectureDirectionName[dir as ArchitectureDirection]]: newId,
[ArchitectureDirectionName[getOppositeArchitectureDirection(dir as ArchitectureDirection)]]: currId,
gap: 100
})
[ArchitectureDirectionName[
getOppositeArchitectureDirection(dir as ArchitectureDirection)
]]: currId,
gap: 100,
});
}
})
});
}
}
}
})
}
});
return _relativeConstraints;
})();
console.log(`Horizontal Alignments:`)
console.log(`Horizontal Alignments:`);
console.log(horizontalAlignments);
console.log(`Vertical Alignments:`)
console.log(`Vertical Alignments:`);
console.log(verticalAlignments);
console.log(`Relative Alignments:`)
console.log(`Relative Alignments:`);
console.log(relativeConstraints);
cy.layout({
@ -242,25 +251,28 @@ function layoutArchitecture(
// Adjust the edge parameters if it passes through the border of a group
// Hacky fix for: https://github.com/iVis-at-Bilkent/cytoscape.js-fcose/issues/67
idealEdgeLength(edge) {
const [nodeA, nodeB] = edge.connectedNodes()
const {parent: parentA} = nodeA.data();
const {parent: parentB} = nodeB.data();
const elasticity = parentA === parentB ? 1.25*getConfigField('iconSize') : 0.5*getConfigField('iconSize');
const [nodeA, nodeB] = edge.connectedNodes();
const { parent: parentA } = nodeA.data();
const { parent: parentB } = nodeB.data();
const elasticity =
parentA === parentB
? 1.25 * getConfigField('iconSize')
: 0.5 * getConfigField('iconSize');
return elasticity;
},
edgeElasticity(edge) {
const [nodeA, nodeB] = edge.connectedNodes()
const [nodeA, nodeB] = edge.connectedNodes();
console.log(nodeA.data());
const {parent: parentA} = nodeA.data();
const {parent: parentB} = nodeB.data();
const { parent: parentA } = nodeA.data();
const { parent: parentB } = nodeB.data();
const elasticity = parentA === parentB ? 0.45 : 0.001;
return elasticity
},
return elasticity;
},
alignmentConstraint: {
horizontal: horizontalAlignments,
vertical: verticalAlignments,
},
relativePlacementConstraint: relativeConstraints
relativePlacementConstraint: relativeConstraints,
} as FcoseLayoutOptions).run();
cy.ready((e) => {
log.info('Ready', e);
@ -295,20 +307,15 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
drawServices(db, servicesElem, services, conf);
const cy = await layoutArchitecture(services, groups, lines, ds);
console.log(cy.nodes().map(node => ({a: node.data()})));
console.log(cy.nodes().map((node) => ({ a: node.data() })));
drawEdges(edgesElem, cy);
drawGroups(groupElem, cy);
positionServices(db, cy);
setupGraphViewbox(
undefined,
svg,
getConfigField('padding'),
getConfigField('useMaxWidth')
);
setupGraphViewbox(undefined, svg, getConfigField('padding'), getConfigField('useMaxWidth'));
console.log('==============================================================')
console.log('==============================================================');
};
export const renderer = { draw };

View File

@ -3,22 +3,24 @@ import type { ArchitectureDiagramConfig } from '../../config.type.js';
import type { D3Element } from '../../mermaidAPI.js';
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
export const ArchitectureDirectionName = {
'L': 'left',
'R': 'right',
'T': 'top',
'B': 'bottom',
L: 'left',
R: 'right',
T: 'top',
B: 'bottom',
} as const;
export const getOppositeArchitectureDirection = function(x: ArchitectureDirection): ArchitectureDirection {
export const getOppositeArchitectureDirection = function (
x: ArchitectureDirection
): ArchitectureDirection {
if (isArchitectureDirectionX(x)) {
return x === 'L' ? 'R' : 'L'
return x === 'L' ? 'R' : 'L';
} else {
return x === 'T' ? 'B' : 'T'
return x === 'T' ? 'B' : 'T';
}
}
};
export const isArchitectureDirection = function (x: unknown): x is ArchitectureDirection {
const temp = x as ArchitectureDirection;
@ -41,7 +43,7 @@ export const isArchitectureDirectionY = function (
export const isArchitectureDirectionXY = function (
a: ArchitectureDirection,
b: ArchitectureDirection,
b: ArchitectureDirection
) {
const aX_bY = isArchitectureDirectionX(a) && isArchitectureDirectionY(b);
const aY_bX = isArchitectureDirectionY(a) && isArchitectureDirectionX(b);
@ -51,48 +53,57 @@ export const isArchitectureDirectionXY = function (
/**
* Contains LL, RR, TT, BB which are impossible conections
*/
export type InvalidArchitectureDirectionPair = `${ArchitectureDirection}${ArchitectureDirection}`
export type ArchitectureDirectionPair = Exclude<InvalidArchitectureDirectionPair, 'LL' | 'RR' | 'TT' | 'BB'>
export const isValidArchitectureDirectionPair = function(x: InvalidArchitectureDirectionPair): x is ArchitectureDirectionPair {
return x !== 'LL' && x !== 'RR' && x !== 'TT' && x !== 'BB'
}
export type InvalidArchitectureDirectionPair = `${ArchitectureDirection}${ArchitectureDirection}`;
export type ArchitectureDirectionPair = Exclude<
InvalidArchitectureDirectionPair,
'LL' | 'RR' | 'TT' | 'BB'
>;
export const isValidArchitectureDirectionPair = function (
x: InvalidArchitectureDirectionPair
): x is ArchitectureDirectionPair {
return x !== 'LL' && x !== 'RR' && x !== 'TT' && x !== 'BB';
};
export type ArchitectureDirectionPairMap = {
[key in ArchitectureDirectionPair]?: string
}
[key in ArchitectureDirectionPair]?: string;
};
/**
* Creates a pair of the directions of each side of an edge. This function should be used instead of manually creating it to ensure that the source is always the first character.
*
* Note: Undefined is returned when sourceDir and targetDir are the same. In theory this should never happen since the diagram parser throws an error if a user defines it as such.
* @param sourceDir
* @param targetDir
* @returns
* Creates a pair of the directions of each side of an edge. This function should be used instead of manually creating it to ensure that the source is always the first character.
*
* Note: Undefined is returned when sourceDir and targetDir are the same. In theory this should never happen since the diagram parser throws an error if a user defines it as such.
* @param sourceDir
* @param targetDir
* @returns
*/
export const getArchitectureDirectionPair = function (sourceDir: ArchitectureDirection, targetDir: ArchitectureDirection): ArchitectureDirectionPair | undefined {
export const getArchitectureDirectionPair = function (
sourceDir: ArchitectureDirection,
targetDir: ArchitectureDirection
): ArchitectureDirectionPair | undefined {
const pair: `${ArchitectureDirection}${ArchitectureDirection}` = `${sourceDir}${targetDir}`;
return isValidArchitectureDirectionPair(pair) ? pair : undefined
}
return isValidArchitectureDirectionPair(pair) ? pair : undefined;
};
export const shiftPositionByArchitectureDirectionPair = function ([x, y]: number[], pair: ArchitectureDirectionPair): number[] {
export const shiftPositionByArchitectureDirectionPair = function (
[x, y]: number[],
pair: ArchitectureDirectionPair
): number[] {
const lhs = pair[0] as ArchitectureDirection;
const rhs = pair[1] as ArchitectureDirection;
console.log(`${pair}: (${x},${y})`);
if (isArchitectureDirectionX(lhs)) {
if (isArchitectureDirectionY(rhs)) {
return [x + (lhs === 'L' ? -1 : 1), y + (rhs === 'T' ? 1 : -1)]
return [x + (lhs === 'L' ? -1 : 1), y + (rhs === 'T' ? 1 : -1)];
} else {
return [x + (lhs === 'L' ? -1 : 1), y]
return [x + (lhs === 'L' ? -1 : 1), y];
}
} else {
if (isArchitectureDirectionX(rhs)) {
return [x + (rhs === 'L' ? 1 : -1), y + (lhs === 'T' ? 1 : -1)]
return [x + (rhs === 'L' ? 1 : -1), y + (lhs === 'T' ? 1 : -1)];
} else {
return [x, y + (lhs === 'T' ? 1 : -1)]
return [x, y + (lhs === 'T' ? 1 : -1)];
}
}
}
};
export interface ArchitectureStyleOptions {
fontFamily: string;
@ -144,12 +155,12 @@ export interface ArchitectureDB extends DiagramDB {
getDataStructures: () => ArchitectureDataStructures;
}
export type ArchitectureAdjacencyList = {[id: string]: ArchitectureDirectionPairMap}
export type ArchitectureSpatialMap = Record<string, number[]>
export type ArchitectureAdjacencyList = { [id: string]: ArchitectureDirectionPairMap };
export type ArchitectureSpatialMap = Record<string, number[]>;
export type ArchitectureDataStructures = {
adjList: ArchitectureAdjacencyList;
spatialMaps: ArchitectureSpatialMap[];
}
};
export interface ArchitectureFields {
services: Record<string, ArchitectureService>;

View File

@ -8,10 +8,9 @@ import type {
import type { MermaidConfig } from '../../config.type.js';
import type cytoscape from 'cytoscape';
import { log } from '../../logger.js';
import { getIcon, isIconNameInUse } from '../../rendering-util/svgRegister.js';
import { getIcon } from '../../rendering-util/svgRegister.js';
import { getConfigField } from './architectureDb.js';
declare module 'cytoscape' {
type _EdgeSingularData = {
id: string;
@ -20,7 +19,7 @@ declare module 'cytoscape' {
target: string;
targetDir: ArchitectureDirection;
[key: string]: any;
}
};
interface EdgeSingular {
_private: {
bodyBounds: unknown;
@ -33,9 +32,8 @@ declare module 'cytoscape' {
endY: number;
};
};
// data: (() => _EdgeSingularData) | (<T extends keyof _EdgeSingularData>(key: T) => _EdgeSingularData[T])
data(): _EdgeSingularData
data<T extends keyof _EdgeSingularData>(key: T): _EdgeSingularData[T]
data(): _EdgeSingularData;
data<T extends keyof _EdgeSingularData>(key: T): _EdgeSingularData[T];
}
interface NodeSingular {
_private: {
@ -90,14 +88,14 @@ export const drawEdges = function (edgesEl: D3Element, cy: cytoscape.Core) {
};
export const drawGroups = function (groupsEl: D3Element, cy: cytoscape.Core) {
const iconSize = getConfigField('iconSize')
const halfIconSize = iconSize / 2
const iconSize = getConfigField('iconSize');
const halfIconSize = iconSize / 2;
cy.nodes().map((node, id) => {
const data = node.data();
if (data.type === 'group') {
const { h, w, x1, x2, y1, y2 } = node.boundingBox();
console.log(`Draw group (${data.id}): pos=(${x1}, ${y1}), dim=(${w}, ${h})`)
console.log(`Draw group (${data.id}): pos=(${x1}, ${y1}), dim=(${w}, ${h})`);
let bkgElem = groupsEl
.append('rect')
.attr('x', x1 + halfIconSize)
@ -118,7 +116,10 @@ export const drawGroups = function (groupsEl: D3Element, cy: cytoscape.Core) {
.attr('dominant-baseline', 'start')
.attr('text-anchor', 'start');
textElem.attr('transform', 'translate(' + (x1 + halfIconSize + 4) + ', ' + (y1 + halfIconSize + 2) + ')');
textElem.attr(
'transform',
'translate(' + (x1 + halfIconSize + 4) + ', ' + (y1 + halfIconSize + 2) + ')'
);
}
});
};
@ -130,13 +131,13 @@ export const drawService = function (
conf: MermaidConfig
): number {
const serviceElem = elem.append('g');
const iconSize = getConfigField('iconSize')
const iconSize = getConfigField('iconSize');
if (service.title) {
const textElem = serviceElem.append('g');
createText(textElem, service.title, {
useHtmlLabels: false,
width: iconSize * 1.5,
width: iconSize * 1.5,
classes: 'architecture-service-label',
});
textElem
@ -145,10 +146,7 @@ export const drawService = function (
.attr('dominant-baseline', 'middle')
.attr('text-anchor', 'middle');
textElem.attr(
'transform',
'translate(' + (iconSize / 2) + ', ' + iconSize + ')'
);
textElem.attr('transform', 'translate(' + iconSize / 2 + ', ' + iconSize + ')');
}
let bkgElem = serviceElem.append('g');
@ -163,7 +161,7 @@ export const drawService = function (
.append('path')
.attr('class', 'node-bkg')
.attr('id', 'node-' + service.id)
.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`);
.attr('d', `M0 ${iconSize} v${-iconSize} q0,-5 5,-5 h${iconSize} q5,0 5,5 v${iconSize} H0 Z`);
}
serviceElem.attr('class', 'architecture-service');
@ -171,7 +169,7 @@ export const drawService = function (
const { width, height } = serviceElem._groups[0][0].getBBox();
service.width = width;
service.height = height;
console.log(`Draw service (${service.id})`)
console.log(`Draw service (${service.id})`);
db.setElementForId(service.id, serviceElem);
return 0;
};

View File

@ -504,7 +504,7 @@ function initialize(options: MermaidConfig = {}) {
// Set default options
configApi.saveConfigFromInitialize(options);
registerIcons(defaultIconLibrary)
registerIcons(defaultIconLibrary);
if (options?.iconLibraries) {
options.iconLibraries.forEach((library) => {
registerIcons(library);

View File

@ -2,9 +2,10 @@
* @author Nicolas Newman
* @see https://github.com/NicolasNewman/IconLibrary
*/
import { createIcon } from "../svgRegister.js";
import { createIcon } from '../svgRegister.js';
export default createIcon(`<g>
export default createIcon(
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<path id="b" data-name="4" d="m20,57.86c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<path id="c" data-name="3" d="m20,45.95c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
@ -12,5 +13,6 @@ export default createIcon(`<g>
<ellipse id="e" data-name="1" cx="40" cy="22.14" rx="20" ry="7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="20" y1="57.86" x2="20" y2="22.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="60" y1="57.86" x2="60" y2="22.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
</g>`, 80)
</g>`,
80
);

View File

@ -2,9 +2,10 @@
* @author Nicolas Newman
* @see https://github.com/NicolasNewman/IconLibrary
*/
import { createIcon } from "../svgRegister.js";
import { createIcon } from '../svgRegister.js';
export default createIcon(`<g>
export default createIcon(
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<rect x="20" y="15" width="40" height="50" rx="1" ry="1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<ellipse cx="24" cy="19.17" rx=".8" ry=".83" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
@ -14,5 +15,6 @@ export default createIcon(`<g>
<ellipse cx="40" cy="33.75" rx="14" ry="14.58" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<ellipse cx="40" cy="33.75" rx="4" ry="4.17" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<path d="m37.51,42.52l-4.83,13.22c-.26.71-1.1,1.02-1.76.64l-4.18-2.42c-.66-.38-.81-1.26-.33-1.84l9.01-10.8c.88-1.05,2.56-.08,2.09,1.2Z" style="fill: #fff; stroke-width: 0px;"/>
</g>`, 80)
</g>`,
80
);

View File

@ -1,16 +1,16 @@
import { IconLibrary } from "../svgRegister.js";
import database from "./database.js";
import server from "./server.js";
import disk from "./disk.js";
import internet from "./internet.js";
import unknown from "./unknown.js";
import { IconLibrary } from '../svgRegister.js';
import database from './database.js';
import server from './server.js';
import disk from './disk.js';
import internet from './internet.js';
import unknown from './unknown.js';
const defaultIconLibrary: IconLibrary = {
database: database,
server: server,
disk: disk,
internet: internet,
unknown: unknown,
}
database: database,
server: server,
disk: disk,
internet: internet,
unknown: unknown,
};
export default defaultIconLibrary
export default defaultIconLibrary;

View File

@ -2,9 +2,10 @@
* @author Nicolas Newman
* @see https://github.com/NicolasNewman/IconLibrary
*/
import { createIcon } from "../svgRegister.js";
import { createIcon } from '../svgRegister.js';
export default createIcon(`<g>
export default createIcon(
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<circle cx="40" cy="40" r="22.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="40" y1="17.5" x2="40" y2="62.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
@ -13,5 +14,6 @@ export default createIcon(`<g>
<path d="m40.01,17.51c15.28,11.1,15.28,33.88,0,44.98" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="19.75" y1="30.1" x2="60.25" y2="30.1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="19.75" y1="49.9" x2="60.25" y2="49.9" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
</g>`, 80)
</g>`,
80
);

View File

@ -2,9 +2,10 @@
* @author Nicolas Newman
* @see https://github.com/NicolasNewman/IconLibrary
*/
import { createIcon } from "../svgRegister.js";
import { createIcon } from '../svgRegister.js';
export default createIcon(`<g>
export default createIcon(
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<rect x="17.5" y="17.5" width="45" height="45" rx="2" ry="2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
<line x1="17.5" y1="32.5" x2="62.5" y2="32.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
@ -36,5 +37,6 @@ export default createIcon(`<g>
<circle cx="27.5" cy="55" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/>
<circle cx="22.5" cy="55" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/>
</g>
</g>`, 80)
</g>`,
80
);

View File

@ -2,9 +2,12 @@
* @author Nicolas Newman
* @see https://github.com/NicolasNewman/IconLibrary
*/
import { createIcon } from "../svgRegister.js";
import { createIcon } from '../svgRegister.js';
export default createIcon(`<g>
export default createIcon(
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<text transform="translate(21.16 64.67)" style="fill: #fff; font-family: ArialMT, Arial; font-size: 67.75px;"><tspan x="0" y="0">?</tspan></text>
</g>`, 80)
</g>`,
80
);