Generated
Vendored
+1201
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+3819
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+2600
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+102
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
insertEdge,
|
||||
insertEdgeLabel,
|
||||
markers_default,
|
||||
positionEdgeLabel
|
||||
} from "./chunk-ENJZ2VHE.mjs";
|
||||
import {
|
||||
insertCluster,
|
||||
insertNode,
|
||||
labelHelper
|
||||
} from "./chunk-5FUZZQ4R.mjs";
|
||||
import {
|
||||
interpolateToCurve
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
common_default,
|
||||
getConfig
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/internals.ts
|
||||
var internalHelpers = {
|
||||
common: common_default,
|
||||
getConfig,
|
||||
insertCluster,
|
||||
insertEdge,
|
||||
insertEdgeLabel,
|
||||
insertMarkers: markers_default,
|
||||
insertNode,
|
||||
interpolateToCurve,
|
||||
labelHelper,
|
||||
log,
|
||||
positionEdgeLabel
|
||||
};
|
||||
|
||||
// src/rendering-util/render.ts
|
||||
var layoutAlgorithms = {};
|
||||
var registerLayoutLoaders = /* @__PURE__ */ __name((loaders) => {
|
||||
for (const loader of loaders) {
|
||||
layoutAlgorithms[loader.name] = loader;
|
||||
}
|
||||
}, "registerLayoutLoaders");
|
||||
var registerDefaultLayoutLoaders = /* @__PURE__ */ __name(() => {
|
||||
registerLayoutLoaders([
|
||||
{
|
||||
name: "dagre",
|
||||
loader: /* @__PURE__ */ __name(async () => await import("./dagre-KV5264BT.mjs"), "loader")
|
||||
},
|
||||
...true ? [
|
||||
{
|
||||
name: "cose-bilkent",
|
||||
loader: /* @__PURE__ */ __name(async () => await import("./cose-bilkent-S5V4N54A.mjs"), "loader")
|
||||
}
|
||||
] : []
|
||||
]);
|
||||
}, "registerDefaultLayoutLoaders");
|
||||
registerDefaultLayoutLoaders();
|
||||
var render = /* @__PURE__ */ __name(async (data4Layout, svg) => {
|
||||
if (!(data4Layout.layoutAlgorithm in layoutAlgorithms)) {
|
||||
throw new Error(`Unknown layout algorithm: ${data4Layout.layoutAlgorithm}`);
|
||||
}
|
||||
if (data4Layout.diagramId) {
|
||||
for (const node of data4Layout.nodes) {
|
||||
const originalDomId = node.domId || node.id;
|
||||
node.domId = `${data4Layout.diagramId}-${originalDomId}`;
|
||||
}
|
||||
}
|
||||
const layoutDefinition = layoutAlgorithms[data4Layout.layoutAlgorithm];
|
||||
const layoutRenderer = await layoutDefinition.loader();
|
||||
const { theme, themeVariables } = data4Layout.config;
|
||||
const { useGradient, gradientStart, gradientStop } = themeVariables;
|
||||
const svgId = svg.attr("id");
|
||||
svg.append("defs").append("filter").attr("id", `${svgId}-drop-shadow`).attr("height", "130%").attr("width", "130%").append("feDropShadow").attr("dx", "4").attr("dy", "4").attr("stdDeviation", 0).attr("flood-opacity", "0.06").attr("flood-color", `${theme?.includes("dark") ? "#FFFFFF" : "#000000"}`);
|
||||
svg.append("defs").append("filter").attr("id", `${svgId}-drop-shadow-small`).attr("height", "150%").attr("width", "150%").append("feDropShadow").attr("dx", "2").attr("dy", "2").attr("stdDeviation", 0).attr("flood-opacity", "0.06").attr("flood-color", `${theme?.includes("dark") ? "#FFFFFF" : "#000000"}`);
|
||||
if (useGradient) {
|
||||
const gradient = svg.append("linearGradient").attr("id", svg.attr("id") + "-gradient").attr("gradientUnits", "objectBoundingBox").attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%");
|
||||
gradient.append("svg:stop").attr("offset", "0%").attr("stop-color", gradientStart).attr("stop-opacity", 1);
|
||||
gradient.append("svg:stop").attr("offset", "100%").attr("stop-color", gradientStop).attr("stop-opacity", 1);
|
||||
}
|
||||
return layoutRenderer.render(data4Layout, svg, internalHelpers, {
|
||||
algorithm: layoutDefinition.algorithm
|
||||
});
|
||||
}, "render");
|
||||
var getRegisteredLayoutAlgorithm = /* @__PURE__ */ __name((algorithm = "", { fallback = "dagre" } = {}) => {
|
||||
if (algorithm in layoutAlgorithms) {
|
||||
return algorithm;
|
||||
}
|
||||
if (fallback in layoutAlgorithms) {
|
||||
log.warn(`Layout algorithm ${algorithm} is not registered. Using ${fallback} as fallback.`);
|
||||
return fallback;
|
||||
}
|
||||
throw new Error(`Both layout algorithms ${algorithm} and ${fallback} are not registered.`);
|
||||
}, "getRegisteredLayoutAlgorithm");
|
||||
|
||||
export {
|
||||
registerLayoutLoaders,
|
||||
render,
|
||||
getRegisteredLayoutAlgorithm
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
getConfig2 as getConfig
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/selectSvgElement.ts
|
||||
import { select } from "d3";
|
||||
var selectSvgElement = /* @__PURE__ */ __name((id) => {
|
||||
const { securityLevel } = getConfig();
|
||||
let root = select("body");
|
||||
if (securityLevel === "sandbox") {
|
||||
const sandboxElement = select(`#i${id}`);
|
||||
const doc = sandboxElement.node()?.contentDocument ?? document;
|
||||
root = select(doc.body);
|
||||
}
|
||||
const svg = root.select(`#${id}`);
|
||||
return svg;
|
||||
}, "selectSvgElement");
|
||||
|
||||
export {
|
||||
selectSvgElement
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/rendering-util/selectSvgElement.ts"],
|
||||
"sourcesContent": ["import { select } from 'd3';\nimport { getConfig } from '../diagram-api/diagramAPI.js';\nimport type { HTML, SVG } from '../diagram-api/types.js';\n\n/**\n * Selects the SVG element using {@link id}.\n *\n * @param id - The diagram ID.\n * @returns The selected {@link SVG} element using {@link id}.\n */\nexport const selectSvgElement = (id: string): SVG => {\n const { securityLevel } = getConfig();\n // handle root and document for when rendering in sandbox mode\n let root: HTML = select('body');\n if (securityLevel === 'sandbox') {\n const sandboxElement: HTML = select(`#i${id}`);\n const doc: Document = sandboxElement.node()?.contentDocument ?? document;\n root = select(doc.body as HTMLIFrameElement);\n }\n const svg: SVG = root.select(`#${id}`);\n return svg;\n};\n"],
|
||||
"mappings": ";;;;;;;;AAAA,SAAS,cAAc;AAUhB,IAAM,mBAAmB,wBAAC,OAAoB;AACnD,QAAM,EAAE,cAAc,IAAI,UAAU;AAEpC,MAAI,OAAa,OAAO,MAAM;AAC9B,MAAI,kBAAkB,WAAW;AAC/B,UAAM,iBAAuB,OAAO,KAAK,EAAE,EAAE;AAC7C,UAAM,MAAgB,eAAe,KAAK,GAAG,mBAAmB;AAChE,WAAO,OAAO,IAAI,IAAyB;AAAA,EAC7C;AACA,QAAM,MAAW,KAAK,OAAO,IAAI,EAAE,EAAE;AACrC,SAAO;AACT,GAXgC;",
|
||||
"names": []
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/common/populateCommonDb.ts
|
||||
function populateCommonDb(ast, db) {
|
||||
if (ast.accDescr) {
|
||||
db.setAccDescription?.(ast.accDescr);
|
||||
}
|
||||
if (ast.accTitle) {
|
||||
db.setAccTitle?.(ast.accTitle);
|
||||
}
|
||||
if (ast.title) {
|
||||
db.setDiagramTitle?.(ast.title);
|
||||
}
|
||||
}
|
||||
__name(populateCommonDb, "populateCommonDb");
|
||||
|
||||
export {
|
||||
populateCommonDb
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/common/populateCommonDb.ts"],
|
||||
"sourcesContent": ["import type { DiagramAST } from '@mermaid-js/parser';\nimport type { DiagramDB } from '../../diagram-api/types.js';\n\nexport function populateCommonDb(ast: DiagramAST, db: DiagramDB) {\n if (ast.accDescr) {\n db.setAccDescription?.(ast.accDescr);\n }\n if (ast.accTitle) {\n db.setAccTitle?.(ast.accTitle);\n }\n if (ast.title) {\n db.setDiagramTitle?.(ast.title);\n }\n}\n"],
|
||||
"mappings": ";;;;;AAGO,SAAS,iBAAiB,KAAiB,IAAe;AAC/D,MAAI,IAAI,UAAU;AAChB,OAAG,oBAAoB,IAAI,QAAQ;AAAA,EACrC;AACA,MAAI,IAAI,UAAU;AAChB,OAAG,cAAc,IAAI,QAAQ;AAAA,EAC/B;AACA,MAAI,IAAI,OAAO;AACb,OAAG,kBAAkB,IAAI,KAAK;AAAA,EAChC;AACF;AAVgB;",
|
||||
"names": []
|
||||
}
|
||||
+2055
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/insertElementsForSize.js
|
||||
import { select } from "d3";
|
||||
var getDiagramElement = /* @__PURE__ */ __name((id, securityLevel) => {
|
||||
let sandboxElement;
|
||||
if (securityLevel === "sandbox") {
|
||||
sandboxElement = select("#i" + id);
|
||||
}
|
||||
const root = securityLevel === "sandbox" ? select(sandboxElement.nodes()[0].contentDocument.body) : select("body");
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
return svg;
|
||||
}, "getDiagramElement");
|
||||
|
||||
export {
|
||||
getDiagramElement
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/rendering-util/insertElementsForSize.js"],
|
||||
"sourcesContent": ["import { select } from 'd3';\n\nexport const getDiagramElement = (id, securityLevel) => {\n let sandboxElement;\n if (securityLevel === 'sandbox') {\n sandboxElement = select('#i' + id);\n }\n const root =\n securityLevel === 'sandbox'\n ? select(sandboxElement.nodes()[0].contentDocument.body)\n : select('body');\n\n const svg = root.select(`[id=\"${id}\"]`);\n\n // Run the renderer. This is what draws the final graph.\n\n return svg;\n};\n"],
|
||||
"mappings": ";;;;;AAAA,SAAS,cAAc;AAEhB,IAAM,oBAAoB,wBAAC,IAAI,kBAAkB;AACtD,MAAI;AACJ,MAAI,kBAAkB,WAAW;AAC/B,qBAAiB,OAAO,OAAO,EAAE;AAAA,EACnC;AACA,QAAM,OACJ,kBAAkB,YACd,OAAO,eAAe,MAAM,EAAE,CAAC,EAAE,gBAAgB,IAAI,IACrD,OAAO,MAAM;AAEnB,QAAM,MAAM,KAAK,OAAO,QAAQ,EAAE,IAAI;AAItC,SAAO;AACT,GAfiC;",
|
||||
"names": []
|
||||
}
|
||||
+5781
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+585
@@ -0,0 +1,585 @@
|
||||
import {
|
||||
assignWithDepth_default,
|
||||
common_default,
|
||||
detectType,
|
||||
directiveRegex,
|
||||
sanitizeDirective
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/utils.ts
|
||||
import { sanitizeUrl } from "@braintree/sanitize-url";
|
||||
import {
|
||||
curveBasis,
|
||||
curveBasisClosed,
|
||||
curveBasisOpen,
|
||||
curveBumpX,
|
||||
curveBumpY,
|
||||
curveBundle,
|
||||
curveCardinalClosed,
|
||||
curveCardinalOpen,
|
||||
curveCardinal,
|
||||
curveCatmullRomClosed,
|
||||
curveCatmullRomOpen,
|
||||
curveCatmullRom,
|
||||
curveLinear,
|
||||
curveLinearClosed,
|
||||
curveMonotoneX,
|
||||
curveMonotoneY,
|
||||
curveNatural,
|
||||
curveStep,
|
||||
curveStepAfter,
|
||||
curveStepBefore,
|
||||
select
|
||||
} from "d3";
|
||||
import memoize from "lodash-es/memoize.js";
|
||||
import merge from "lodash-es/merge.js";
|
||||
var ZERO_WIDTH_SPACE = "\u200B";
|
||||
var d3CurveTypes = {
|
||||
curveBasis,
|
||||
curveBasisClosed,
|
||||
curveBasisOpen,
|
||||
curveBumpX,
|
||||
curveBumpY,
|
||||
curveBundle,
|
||||
curveCardinalClosed,
|
||||
curveCardinalOpen,
|
||||
curveCardinal,
|
||||
curveCatmullRomClosed,
|
||||
curveCatmullRomOpen,
|
||||
curveCatmullRom,
|
||||
curveLinear,
|
||||
curveLinearClosed,
|
||||
curveMonotoneX,
|
||||
curveMonotoneY,
|
||||
curveNatural,
|
||||
curveStep,
|
||||
curveStepAfter,
|
||||
curveStepBefore
|
||||
};
|
||||
var directiveWithoutOpen = /\s*(?:(\w+)(?=:):|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi;
|
||||
var detectInit = /* @__PURE__ */ __name(function(text, config) {
|
||||
const inits = detectDirective(text, /(?:init\b)|(?:initialize\b)/);
|
||||
let results = {};
|
||||
if (Array.isArray(inits)) {
|
||||
const args = inits.map((init) => init.args);
|
||||
sanitizeDirective(args);
|
||||
results = assignWithDepth_default(results, [...args]);
|
||||
} else {
|
||||
results = inits.args;
|
||||
}
|
||||
if (!results) {
|
||||
return;
|
||||
}
|
||||
let type = detectType(text, config);
|
||||
const prop = "config";
|
||||
if (results[prop] !== void 0) {
|
||||
if (type === "flowchart-v2") {
|
||||
type = "flowchart";
|
||||
}
|
||||
results[type] = results[prop];
|
||||
delete results[prop];
|
||||
}
|
||||
return results;
|
||||
}, "detectInit");
|
||||
var detectDirective = /* @__PURE__ */ __name(function(text, type = null) {
|
||||
try {
|
||||
const commentWithoutDirectives = new RegExp(
|
||||
`[%]{2}(?![{]${directiveWithoutOpen.source})(?=[}][%]{2}).*
|
||||
`,
|
||||
"ig"
|
||||
);
|
||||
text = text.trim().replace(commentWithoutDirectives, "").replace(/'/gm, '"');
|
||||
log.debug(
|
||||
`Detecting diagram directive${type !== null ? " type:" + type : ""} based on the text:${text}`
|
||||
);
|
||||
let match;
|
||||
const result = [];
|
||||
while ((match = directiveRegex.exec(text)) !== null) {
|
||||
if (match.index === directiveRegex.lastIndex) {
|
||||
directiveRegex.lastIndex++;
|
||||
}
|
||||
if (match && !type || type && match[1]?.match(type) || type && match[2]?.match(type)) {
|
||||
const type2 = match[1] ? match[1] : match[2];
|
||||
const args = match[3] ? match[3].trim() : match[4] ? JSON.parse(match[4].trim()) : null;
|
||||
result.push({ type: type2, args });
|
||||
}
|
||||
}
|
||||
if (result.length === 0) {
|
||||
return { type: text, args: null };
|
||||
}
|
||||
return result.length === 1 ? result[0] : result;
|
||||
} catch (error) {
|
||||
log.error(
|
||||
`ERROR: ${error.message} - Unable to parse directive type: '${type}' based on the text: '${text}'`
|
||||
);
|
||||
return { type: void 0, args: null };
|
||||
}
|
||||
}, "detectDirective");
|
||||
var removeDirectives = /* @__PURE__ */ __name(function(text) {
|
||||
return text.replace(directiveRegex, "");
|
||||
}, "removeDirectives");
|
||||
var isSubstringInArray = /* @__PURE__ */ __name(function(str, arr) {
|
||||
for (const [i, element] of arr.entries()) {
|
||||
if (element.match(str)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}, "isSubstringInArray");
|
||||
function interpolateToCurve(interpolate, defaultCurve) {
|
||||
if (!interpolate) {
|
||||
return defaultCurve;
|
||||
}
|
||||
const curveName = `curve${interpolate.charAt(0).toUpperCase() + interpolate.slice(1)}`;
|
||||
return d3CurveTypes[curveName] ?? defaultCurve;
|
||||
}
|
||||
__name(interpolateToCurve, "interpolateToCurve");
|
||||
function formatUrl(linkStr, config) {
|
||||
const url = linkStr.trim();
|
||||
if (!url) {
|
||||
return void 0;
|
||||
}
|
||||
if (config.securityLevel !== "loose") {
|
||||
return sanitizeUrl(url);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
__name(formatUrl, "formatUrl");
|
||||
var runFunc = /* @__PURE__ */ __name((functionName, ...params) => {
|
||||
const arrPaths = functionName.split(".");
|
||||
const len = arrPaths.length - 1;
|
||||
const fnName = arrPaths[len];
|
||||
let obj = window;
|
||||
for (let i = 0; i < len; i++) {
|
||||
obj = obj[arrPaths[i]];
|
||||
if (!obj) {
|
||||
log.error(`Function name: ${functionName} not found in window`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
obj[fnName](...params);
|
||||
}, "runFunc");
|
||||
function distance(p1, p2) {
|
||||
if (!p1 || !p2) {
|
||||
return 0;
|
||||
}
|
||||
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
|
||||
}
|
||||
__name(distance, "distance");
|
||||
function traverseEdge(points) {
|
||||
let prevPoint;
|
||||
let totalDistance = 0;
|
||||
points.forEach((point) => {
|
||||
totalDistance += distance(point, prevPoint);
|
||||
prevPoint = point;
|
||||
});
|
||||
const remainingDistance = totalDistance / 2;
|
||||
return calculatePoint(points, remainingDistance);
|
||||
}
|
||||
__name(traverseEdge, "traverseEdge");
|
||||
function calcLabelPosition(points) {
|
||||
if (points.length === 1) {
|
||||
return points[0];
|
||||
}
|
||||
return traverseEdge(points);
|
||||
}
|
||||
__name(calcLabelPosition, "calcLabelPosition");
|
||||
var roundNumber = /* @__PURE__ */ __name((num, precision = 2) => {
|
||||
const factor = Math.pow(10, precision);
|
||||
return Math.round(num * factor) / factor;
|
||||
}, "roundNumber");
|
||||
var calculatePoint = /* @__PURE__ */ __name((points, distanceToTraverse) => {
|
||||
let prevPoint = void 0;
|
||||
let remainingDistance = distanceToTraverse;
|
||||
for (const point of points) {
|
||||
if (prevPoint) {
|
||||
const vectorDistance = distance(point, prevPoint);
|
||||
if (vectorDistance === 0) {
|
||||
return prevPoint;
|
||||
}
|
||||
if (vectorDistance < remainingDistance) {
|
||||
remainingDistance -= vectorDistance;
|
||||
} else {
|
||||
const distanceRatio = remainingDistance / vectorDistance;
|
||||
if (distanceRatio <= 0) {
|
||||
return prevPoint;
|
||||
}
|
||||
if (distanceRatio >= 1) {
|
||||
return { x: point.x, y: point.y };
|
||||
}
|
||||
if (distanceRatio > 0 && distanceRatio < 1) {
|
||||
return {
|
||||
x: roundNumber((1 - distanceRatio) * prevPoint.x + distanceRatio * point.x, 5),
|
||||
y: roundNumber((1 - distanceRatio) * prevPoint.y + distanceRatio * point.y, 5)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
prevPoint = point;
|
||||
}
|
||||
throw new Error("Could not find a suitable point for the given distance");
|
||||
}, "calculatePoint");
|
||||
var calcCardinalityPosition = /* @__PURE__ */ __name((isRelationTypePresent, points, initialPosition) => {
|
||||
log.info(`our points ${JSON.stringify(points)}`);
|
||||
if (points[0] !== initialPosition) {
|
||||
points = points.reverse();
|
||||
}
|
||||
const distanceToCardinalityPoint = 25;
|
||||
const center = calculatePoint(points, distanceToCardinalityPoint);
|
||||
const d = isRelationTypePresent ? 10 : 5;
|
||||
const angle = Math.atan2(points[0].y - center.y, points[0].x - center.x);
|
||||
const cardinalityPosition = { x: 0, y: 0 };
|
||||
cardinalityPosition.x = Math.sin(angle) * d + (points[0].x + center.x) / 2;
|
||||
cardinalityPosition.y = -Math.cos(angle) * d + (points[0].y + center.y) / 2;
|
||||
return cardinalityPosition;
|
||||
}, "calcCardinalityPosition");
|
||||
function calcTerminalLabelPosition(terminalMarkerSize, position, _points) {
|
||||
const points = structuredClone(_points);
|
||||
log.info("our points", points);
|
||||
if (position !== "start_left" && position !== "start_right") {
|
||||
points.reverse();
|
||||
}
|
||||
const distanceToCardinalityPoint = 25 + terminalMarkerSize;
|
||||
const center = calculatePoint(points, distanceToCardinalityPoint);
|
||||
const d = 10 + terminalMarkerSize * 0.5;
|
||||
const angle = Math.atan2(points[0].y - center.y, points[0].x - center.x);
|
||||
const cardinalityPosition = { x: 0, y: 0 };
|
||||
if (position === "start_left") {
|
||||
cardinalityPosition.x = Math.sin(angle + Math.PI) * d + (points[0].x + center.x) / 2;
|
||||
cardinalityPosition.y = -Math.cos(angle + Math.PI) * d + (points[0].y + center.y) / 2;
|
||||
} else if (position === "end_right") {
|
||||
cardinalityPosition.x = Math.sin(angle - Math.PI) * d + (points[0].x + center.x) / 2 - 5;
|
||||
cardinalityPosition.y = -Math.cos(angle - Math.PI) * d + (points[0].y + center.y) / 2 - 5;
|
||||
} else if (position === "end_left") {
|
||||
cardinalityPosition.x = Math.sin(angle) * d + (points[0].x + center.x) / 2 - 5;
|
||||
cardinalityPosition.y = -Math.cos(angle) * d + (points[0].y + center.y) / 2 - 5;
|
||||
} else {
|
||||
cardinalityPosition.x = Math.sin(angle) * d + (points[0].x + center.x) / 2;
|
||||
cardinalityPosition.y = -Math.cos(angle) * d + (points[0].y + center.y) / 2;
|
||||
}
|
||||
return cardinalityPosition;
|
||||
}
|
||||
__name(calcTerminalLabelPosition, "calcTerminalLabelPosition");
|
||||
function getStylesFromArray(arr) {
|
||||
let style = "";
|
||||
let labelStyle = "";
|
||||
for (const element of arr) {
|
||||
if (element !== void 0) {
|
||||
if (element.startsWith("color:") || element.startsWith("text-align:")) {
|
||||
labelStyle = labelStyle + element + ";";
|
||||
} else {
|
||||
style = style + element + ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
return { style, labelStyle };
|
||||
}
|
||||
__name(getStylesFromArray, "getStylesFromArray");
|
||||
var cnt = 0;
|
||||
var generateId = /* @__PURE__ */ __name(() => {
|
||||
cnt++;
|
||||
return "id-" + Math.random().toString(36).substr(2, 12) + "-" + cnt;
|
||||
}, "generateId");
|
||||
function makeRandomHex(length) {
|
||||
let result = "";
|
||||
const characters = "0123456789abcdef";
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
__name(makeRandomHex, "makeRandomHex");
|
||||
var random = /* @__PURE__ */ __name((options) => {
|
||||
return makeRandomHex(options.length);
|
||||
}, "random");
|
||||
var getTextObj = /* @__PURE__ */ __name(function() {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
fill: void 0,
|
||||
anchor: "start",
|
||||
style: "#666",
|
||||
width: 100,
|
||||
height: 100,
|
||||
textMargin: 0,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
valign: void 0,
|
||||
text: ""
|
||||
};
|
||||
}, "getTextObj");
|
||||
var drawSimpleText = /* @__PURE__ */ __name(function(elem, textData) {
|
||||
const nText = textData.text.replace(common_default.lineBreakRegex, " ");
|
||||
const [, _fontSizePx] = parseFontSize(textData.fontSize);
|
||||
const textElem = elem.append("text");
|
||||
textElem.attr("x", textData.x);
|
||||
textElem.attr("y", textData.y);
|
||||
textElem.style("text-anchor", textData.anchor);
|
||||
textElem.style("font-family", textData.fontFamily);
|
||||
textElem.style("font-size", _fontSizePx);
|
||||
textElem.style("font-weight", textData.fontWeight);
|
||||
textElem.attr("fill", textData.fill);
|
||||
if (textData.class !== void 0) {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
const span = textElem.append("tspan");
|
||||
span.attr("x", textData.x + textData.textMargin * 2);
|
||||
span.attr("fill", textData.fill);
|
||||
span.text(nText);
|
||||
return textElem;
|
||||
}, "drawSimpleText");
|
||||
var wrapLabel = memoize(
|
||||
(label, maxWidth, config) => {
|
||||
if (!label) {
|
||||
return label;
|
||||
}
|
||||
config = Object.assign(
|
||||
{ fontSize: 12, fontWeight: 400, fontFamily: "Arial", joinWith: "<br/>" },
|
||||
config
|
||||
);
|
||||
if (common_default.lineBreakRegex.test(label)) {
|
||||
return label;
|
||||
}
|
||||
const words = label.split(" ").filter(Boolean);
|
||||
const completedLines = [];
|
||||
let nextLine = "";
|
||||
words.forEach((word, index) => {
|
||||
const wordLength = calculateTextWidth(`${word} `, config);
|
||||
const nextLineLength = calculateTextWidth(nextLine, config);
|
||||
if (wordLength > maxWidth) {
|
||||
const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, "-", config);
|
||||
completedLines.push(nextLine, ...hyphenatedStrings);
|
||||
nextLine = remainingWord;
|
||||
} else if (nextLineLength + wordLength >= maxWidth) {
|
||||
completedLines.push(nextLine);
|
||||
nextLine = word;
|
||||
} else {
|
||||
nextLine = [nextLine, word].filter(Boolean).join(" ");
|
||||
}
|
||||
const currentWord = index + 1;
|
||||
const isLastWord = currentWord === words.length;
|
||||
if (isLastWord) {
|
||||
completedLines.push(nextLine);
|
||||
}
|
||||
});
|
||||
return completedLines.filter((line) => line !== "").join(config.joinWith);
|
||||
},
|
||||
(label, maxWidth, config) => `${label}${maxWidth}${config.fontSize}${config.fontWeight}${config.fontFamily}${config.joinWith}`
|
||||
);
|
||||
var breakString = memoize(
|
||||
(word, maxWidth, hyphenCharacter = "-", config) => {
|
||||
config = Object.assign(
|
||||
{ fontSize: 12, fontWeight: 400, fontFamily: "Arial", margin: 0 },
|
||||
config
|
||||
);
|
||||
const characters = [...word];
|
||||
const lines = [];
|
||||
let currentLine = "";
|
||||
characters.forEach((character, index) => {
|
||||
const nextLine = `${currentLine}${character}`;
|
||||
const lineWidth = calculateTextWidth(nextLine, config);
|
||||
if (lineWidth >= maxWidth) {
|
||||
const currentCharacter = index + 1;
|
||||
const isLastLine = characters.length === currentCharacter;
|
||||
const hyphenatedNextLine = `${nextLine}${hyphenCharacter}`;
|
||||
lines.push(isLastLine ? nextLine : hyphenatedNextLine);
|
||||
currentLine = "";
|
||||
} else {
|
||||
currentLine = nextLine;
|
||||
}
|
||||
});
|
||||
return { hyphenatedStrings: lines, remainingWord: currentLine };
|
||||
},
|
||||
(word, maxWidth, hyphenCharacter = "-", config) => `${word}${maxWidth}${hyphenCharacter}${config.fontSize}${config.fontWeight}${config.fontFamily}`
|
||||
);
|
||||
function calculateTextHeight(text, config) {
|
||||
return calculateTextDimensions(text, config).height;
|
||||
}
|
||||
__name(calculateTextHeight, "calculateTextHeight");
|
||||
function calculateTextWidth(text, config) {
|
||||
return calculateTextDimensions(text, config).width;
|
||||
}
|
||||
__name(calculateTextWidth, "calculateTextWidth");
|
||||
var calculateTextDimensions = memoize(
|
||||
(text, config) => {
|
||||
const { fontSize = 12, fontFamily = "Arial", fontWeight = 400 } = config;
|
||||
if (!text) {
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
const [, _fontSizePx] = parseFontSize(fontSize);
|
||||
const fontFamilies = ["sans-serif", fontFamily];
|
||||
const lines = text.split(common_default.lineBreakRegex);
|
||||
const dims = [];
|
||||
const body = select("body");
|
||||
if (!body.remove) {
|
||||
return { width: 0, height: 0, lineHeight: 0 };
|
||||
}
|
||||
const g = body.append("svg");
|
||||
for (const fontFamily2 of fontFamilies) {
|
||||
let cHeight = 0;
|
||||
const dim = { width: 0, height: 0, lineHeight: 0 };
|
||||
for (const line of lines) {
|
||||
const textObj = getTextObj();
|
||||
textObj.text = line || ZERO_WIDTH_SPACE;
|
||||
const textElem = drawSimpleText(g, textObj).style("font-size", _fontSizePx).style("font-weight", fontWeight).style("font-family", fontFamily2);
|
||||
const bBox = (textElem._groups || textElem)[0][0].getBBox();
|
||||
if (bBox.width === 0 && bBox.height === 0) {
|
||||
throw new Error("svg element not in render tree");
|
||||
}
|
||||
dim.width = Math.round(Math.max(dim.width, bBox.width));
|
||||
cHeight = Math.round(bBox.height);
|
||||
dim.height += cHeight;
|
||||
dim.lineHeight = Math.round(Math.max(dim.lineHeight, cHeight));
|
||||
}
|
||||
dims.push(dim);
|
||||
}
|
||||
g.remove();
|
||||
const index = isNaN(dims[1].height) || isNaN(dims[1].width) || isNaN(dims[1].lineHeight) || dims[0].height > dims[1].height && dims[0].width > dims[1].width && dims[0].lineHeight > dims[1].lineHeight ? 0 : 1;
|
||||
return dims[index];
|
||||
},
|
||||
(text, config) => `${text}${config.fontSize}${config.fontWeight}${config.fontFamily}`
|
||||
);
|
||||
var InitIDGenerator = class {
|
||||
constructor(deterministic = false, seed) {
|
||||
this.count = 0;
|
||||
this.count = seed ? seed.length : 0;
|
||||
this.next = deterministic ? () => this.count++ : () => Date.now();
|
||||
}
|
||||
static {
|
||||
__name(this, "InitIDGenerator");
|
||||
}
|
||||
};
|
||||
var decoder;
|
||||
var entityDecode = /* @__PURE__ */ __name(function(html) {
|
||||
decoder = decoder || document.createElement("div");
|
||||
html = escape(html).replace(/%26/g, "&").replace(/%23/g, "#").replace(/%3B/g, ";");
|
||||
decoder.innerHTML = html;
|
||||
return unescape(decoder.textContent);
|
||||
}, "entityDecode");
|
||||
function isDetailedError(error) {
|
||||
return "str" in error;
|
||||
}
|
||||
__name(isDetailedError, "isDetailedError");
|
||||
var insertTitle = /* @__PURE__ */ __name((parent, cssClass, titleTopMargin, title) => {
|
||||
if (!title) {
|
||||
return;
|
||||
}
|
||||
const bounds = parent.node()?.getBBox();
|
||||
if (!bounds) {
|
||||
return;
|
||||
}
|
||||
parent.append("text").text(title).attr("text-anchor", "middle").attr("x", bounds.x + bounds.width / 2).attr("y", -titleTopMargin).attr("class", cssClass);
|
||||
}, "insertTitle");
|
||||
var parseFontSize = /* @__PURE__ */ __name((fontSize) => {
|
||||
if (typeof fontSize === "number") {
|
||||
return [fontSize, fontSize + "px"];
|
||||
}
|
||||
const fontSizeNumber = parseInt(fontSize ?? "", 10);
|
||||
if (Number.isNaN(fontSizeNumber)) {
|
||||
return [void 0, void 0];
|
||||
} else if (fontSize === String(fontSizeNumber)) {
|
||||
return [fontSizeNumber, fontSize + "px"];
|
||||
} else {
|
||||
return [fontSizeNumber, fontSize];
|
||||
}
|
||||
}, "parseFontSize");
|
||||
function cleanAndMerge(defaultData, data) {
|
||||
return merge({}, defaultData, data);
|
||||
}
|
||||
__name(cleanAndMerge, "cleanAndMerge");
|
||||
var utils_default = {
|
||||
assignWithDepth: assignWithDepth_default,
|
||||
wrapLabel,
|
||||
calculateTextHeight,
|
||||
calculateTextWidth,
|
||||
calculateTextDimensions,
|
||||
cleanAndMerge,
|
||||
detectInit,
|
||||
detectDirective,
|
||||
isSubstringInArray,
|
||||
interpolateToCurve,
|
||||
calcLabelPosition,
|
||||
calcCardinalityPosition,
|
||||
calcTerminalLabelPosition,
|
||||
formatUrl,
|
||||
getStylesFromArray,
|
||||
generateId,
|
||||
random,
|
||||
runFunc,
|
||||
entityDecode,
|
||||
insertTitle,
|
||||
isLabelCoordinateInPath,
|
||||
parseFontSize,
|
||||
InitIDGenerator
|
||||
};
|
||||
var encodeEntities = /* @__PURE__ */ __name(function(text) {
|
||||
let txt = text;
|
||||
txt = txt.replace(/style.*:\S*#.*;/g, function(s) {
|
||||
return s.substring(0, s.length - 1);
|
||||
});
|
||||
txt = txt.replace(/classDef.*:\S*#.*;/g, function(s) {
|
||||
return s.substring(0, s.length - 1);
|
||||
});
|
||||
txt = txt.replace(/#\w+;/g, function(s) {
|
||||
const innerTxt = s.substring(1, s.length - 1);
|
||||
const isInt = /^\+?\d+$/.test(innerTxt);
|
||||
if (isInt) {
|
||||
return "\uFB02\xB0\xB0" + innerTxt + "\xB6\xDF";
|
||||
} else {
|
||||
return "\uFB02\xB0" + innerTxt + "\xB6\xDF";
|
||||
}
|
||||
});
|
||||
return txt;
|
||||
}, "encodeEntities");
|
||||
var decodeEntities = /* @__PURE__ */ __name(function(text) {
|
||||
return text.replace(/fl°°/g, "&#").replace(/fl°/g, "&").replace(/¶ß/g, ";");
|
||||
}, "decodeEntities");
|
||||
var getEdgeId = /* @__PURE__ */ __name((from, to, {
|
||||
counter = 0,
|
||||
prefix,
|
||||
suffix
|
||||
}, id) => {
|
||||
if (id) {
|
||||
return id;
|
||||
}
|
||||
return `${prefix ? `${prefix}_` : ""}${from}_${to}_${counter}${suffix ? `_${suffix}` : ""}`;
|
||||
}, "getEdgeId");
|
||||
function handleUndefinedAttr(attrValue) {
|
||||
return attrValue ?? null;
|
||||
}
|
||||
__name(handleUndefinedAttr, "handleUndefinedAttr");
|
||||
function isLabelCoordinateInPath(point, dAttr) {
|
||||
const roundedX = Math.round(point.x);
|
||||
const roundedY = Math.round(point.y);
|
||||
const sanitizedD = dAttr.replace(
|
||||
/(\d+\.\d+)/g,
|
||||
(match) => Math.round(parseFloat(match)).toString()
|
||||
);
|
||||
return sanitizedD.includes(roundedX.toString()) || sanitizedD.includes(roundedY.toString());
|
||||
}
|
||||
__name(isLabelCoordinateInPath, "isLabelCoordinateInPath");
|
||||
|
||||
export {
|
||||
ZERO_WIDTH_SPACE,
|
||||
removeDirectives,
|
||||
interpolateToCurve,
|
||||
getStylesFromArray,
|
||||
generateId,
|
||||
random,
|
||||
wrapLabel,
|
||||
calculateTextHeight,
|
||||
calculateTextWidth,
|
||||
isDetailedError,
|
||||
parseFontSize,
|
||||
cleanAndMerge,
|
||||
utils_default,
|
||||
encodeEntities,
|
||||
decodeEntities,
|
||||
getEdgeId,
|
||||
handleUndefinedAttr
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+82
@@ -0,0 +1,82 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
|
||||
// src/logger.ts
|
||||
import dayjs from "dayjs";
|
||||
var LEVELS = {
|
||||
trace: 0,
|
||||
debug: 1,
|
||||
info: 2,
|
||||
warn: 3,
|
||||
error: 4,
|
||||
fatal: 5
|
||||
};
|
||||
var log = {
|
||||
trace: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "trace"),
|
||||
debug: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "debug"),
|
||||
info: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "info"),
|
||||
warn: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "warn"),
|
||||
error: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "error"),
|
||||
fatal: /* @__PURE__ */ __name((..._args) => {
|
||||
}, "fatal")
|
||||
};
|
||||
var setLogLevel = /* @__PURE__ */ __name(function(level = "fatal") {
|
||||
let numericLevel = LEVELS.fatal;
|
||||
if (typeof level === "string") {
|
||||
if (level.toLowerCase() in LEVELS) {
|
||||
numericLevel = LEVELS[level];
|
||||
}
|
||||
} else if (typeof level === "number") {
|
||||
numericLevel = level;
|
||||
}
|
||||
log.trace = () => {
|
||||
};
|
||||
log.debug = () => {
|
||||
};
|
||||
log.info = () => {
|
||||
};
|
||||
log.warn = () => {
|
||||
};
|
||||
log.error = () => {
|
||||
};
|
||||
log.fatal = () => {
|
||||
};
|
||||
if (numericLevel <= LEVELS.fatal) {
|
||||
log.fatal = console.error ? console.error.bind(console, format("FATAL"), "color: orange") : console.log.bind(console, "\x1B[35m", format("FATAL"));
|
||||
}
|
||||
if (numericLevel <= LEVELS.error) {
|
||||
log.error = console.error ? console.error.bind(console, format("ERROR"), "color: orange") : console.log.bind(console, "\x1B[31m", format("ERROR"));
|
||||
}
|
||||
if (numericLevel <= LEVELS.warn) {
|
||||
log.warn = console.warn ? console.warn.bind(console, format("WARN"), "color: orange") : console.log.bind(console, `\x1B[33m`, format("WARN"));
|
||||
}
|
||||
if (numericLevel <= LEVELS.info) {
|
||||
log.info = console.info ? console.info.bind(console, format("INFO"), "color: lightblue") : console.log.bind(console, "\x1B[34m", format("INFO"));
|
||||
}
|
||||
if (numericLevel <= LEVELS.debug) {
|
||||
log.debug = console.debug ? console.debug.bind(console, format("DEBUG"), "color: lightgreen") : console.log.bind(console, "\x1B[32m", format("DEBUG"));
|
||||
}
|
||||
if (numericLevel <= LEVELS.trace) {
|
||||
log.trace = console.debug ? console.debug.bind(console, format("TRACE"), "color: lightgreen") : console.log.bind(console, "\x1B[32m", format("TRACE"));
|
||||
}
|
||||
}, "setLogLevel");
|
||||
var format = /* @__PURE__ */ __name((level) => {
|
||||
const time = dayjs().format("ss.SSS");
|
||||
return `%c${time} : ${level} : `;
|
||||
}, "format");
|
||||
|
||||
export {
|
||||
__name,
|
||||
__export,
|
||||
log,
|
||||
setLogLevel
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/logger.ts"],
|
||||
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-empty-function */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/* eslint-disable no-console */\nimport dayjs from 'dayjs';\n\nexport type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\nexport const LEVELS: Record<LogLevel, number> = {\n trace: 0,\n debug: 1,\n info: 2,\n warn: 3,\n error: 4,\n fatal: 5,\n};\n\nexport const log: Record<keyof typeof LEVELS, typeof console.log> = {\n trace: (..._args: any[]) => {},\n debug: (..._args: any[]) => {},\n info: (..._args: any[]) => {},\n warn: (..._args: any[]) => {},\n error: (..._args: any[]) => {},\n fatal: (..._args: any[]) => {},\n};\n\n/**\n * Sets a log level\n *\n * @param level - The level to set the logging to. Default is `\"fatal\"`\n */\nexport const setLogLevel = function (level: keyof typeof LEVELS | number = 'fatal') {\n let numericLevel: number = LEVELS.fatal;\n if (typeof level === 'string') {\n if (level.toLowerCase() in LEVELS) {\n numericLevel = LEVELS[level];\n }\n } else if (typeof level === 'number') {\n numericLevel = level;\n }\n log.trace = () => {};\n log.debug = () => {};\n log.info = () => {};\n log.warn = () => {};\n log.error = () => {};\n log.fatal = () => {};\n\n if (numericLevel <= LEVELS.fatal) {\n log.fatal = console.error\n ? console.error.bind(console, format('FATAL'), 'color: orange')\n : console.log.bind(console, '\\x1b[35m', format('FATAL'));\n }\n if (numericLevel <= LEVELS.error) {\n log.error = console.error\n ? console.error.bind(console, format('ERROR'), 'color: orange')\n : console.log.bind(console, '\\x1b[31m', format('ERROR'));\n }\n if (numericLevel <= LEVELS.warn) {\n log.warn = console.warn\n ? console.warn.bind(console, format('WARN'), 'color: orange')\n : console.log.bind(console, `\\x1b[33m`, format('WARN'));\n }\n if (numericLevel <= LEVELS.info) {\n log.info = console.info\n ? console.info.bind(console, format('INFO'), 'color: lightblue')\n : console.log.bind(console, '\\x1b[34m', format('INFO'));\n }\n if (numericLevel <= LEVELS.debug) {\n log.debug = console.debug\n ? console.debug.bind(console, format('DEBUG'), 'color: lightgreen')\n : console.log.bind(console, '\\x1b[32m', format('DEBUG'));\n }\n if (numericLevel <= LEVELS.trace) {\n log.trace = console.debug\n ? console.debug.bind(console, format('TRACE'), 'color: lightgreen')\n : console.log.bind(console, '\\x1b[32m', format('TRACE'));\n }\n};\n\n/**\n * Returns a format with the timestamp and the log level\n *\n * @param level - The level for the log format\n * @returns The format with the timestamp and log level\n */\nconst format = (level: Uppercase<LogLevel>): string => {\n const time = dayjs().format('ss.SSS');\n return `%c${time} : ${level} : `;\n};\n"],
|
||||
"mappings": ";;;;;;;;AAIA,OAAO,WAAW;AAIX,IAAM,SAAmC;AAAA,EAC9C,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACT;AAEO,IAAM,MAAuD;AAAA,EAClE,OAAO,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AAAA,EACP,OAAO,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AAAA,EACP,MAAM,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AAAA,EACN,MAAM,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AAAA,EACN,OAAO,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AAAA,EACP,OAAO,2BAAI,UAAiB;AAAA,EAAC,GAAtB;AACT;AAOO,IAAM,cAAc,gCAAU,QAAsC,SAAS;AAClF,MAAI,eAAuB,OAAO;AAClC,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,MAAM,YAAY,KAAK,QAAQ;AACjC,qBAAe,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF,WAAW,OAAO,UAAU,UAAU;AACpC,mBAAe;AAAA,EACjB;AACA,MAAI,QAAQ,MAAM;AAAA,EAAC;AACnB,MAAI,QAAQ,MAAM;AAAA,EAAC;AACnB,MAAI,OAAO,MAAM;AAAA,EAAC;AAClB,MAAI,OAAO,MAAM;AAAA,EAAC;AAClB,MAAI,QAAQ,MAAM;AAAA,EAAC;AACnB,MAAI,QAAQ,MAAM;AAAA,EAAC;AAEnB,MAAI,gBAAgB,OAAO,OAAO;AAChC,QAAI,QAAQ,QAAQ,QAChB,QAAQ,MAAM,KAAK,SAAS,OAAO,OAAO,GAAG,eAAe,IAC5D,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,OAAO,CAAC;AAAA,EAC3D;AACA,MAAI,gBAAgB,OAAO,OAAO;AAChC,QAAI,QAAQ,QAAQ,QAChB,QAAQ,MAAM,KAAK,SAAS,OAAO,OAAO,GAAG,eAAe,IAC5D,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,OAAO,CAAC;AAAA,EAC3D;AACA,MAAI,gBAAgB,OAAO,MAAM;AAC/B,QAAI,OAAO,QAAQ,OACf,QAAQ,KAAK,KAAK,SAAS,OAAO,MAAM,GAAG,eAAe,IAC1D,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,MAAM,CAAC;AAAA,EAC1D;AACA,MAAI,gBAAgB,OAAO,MAAM;AAC/B,QAAI,OAAO,QAAQ,OACf,QAAQ,KAAK,KAAK,SAAS,OAAO,MAAM,GAAG,kBAAkB,IAC7D,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,MAAM,CAAC;AAAA,EAC1D;AACA,MAAI,gBAAgB,OAAO,OAAO;AAChC,QAAI,QAAQ,QAAQ,QAChB,QAAQ,MAAM,KAAK,SAAS,OAAO,OAAO,GAAG,mBAAmB,IAChE,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,OAAO,CAAC;AAAA,EAC3D;AACA,MAAI,gBAAgB,OAAO,OAAO;AAChC,QAAI,QAAQ,QAAQ,QAChB,QAAQ,MAAM,KAAK,SAAS,OAAO,OAAO,GAAG,mBAAmB,IAChE,QAAQ,IAAI,KAAK,SAAS,YAAY,OAAO,OAAO,CAAC;AAAA,EAC3D;AACF,GA9C2B;AAsD3B,IAAM,SAAS,wBAAC,UAAuC;AACrD,QAAM,OAAO,MAAM,EAAE,OAAO,QAAQ;AACpC,SAAO,KAAK,IAAI,MAAM,KAAK;AAC7B,GAHe;",
|
||||
"names": []
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/labelTransform.ts
|
||||
var computeLabelTransform = /* @__PURE__ */ __name((bbox, useHtmlLabels) => {
|
||||
if (useHtmlLabels) {
|
||||
return "translate(" + -bbox.width / 2 + ", " + -bbox.height / 2 + ")";
|
||||
}
|
||||
const x = bbox.x ?? 0;
|
||||
const y = bbox.y ?? 0;
|
||||
return "translate(" + -(x + bbox.width / 2) + ", " + -(y + bbox.height / 2) + ")";
|
||||
}, "computeLabelTransform");
|
||||
|
||||
// src/utils/lineWithOffset.ts
|
||||
var markerOffsets = {
|
||||
aggregation: 17.25,
|
||||
extension: 17.25,
|
||||
composition: 17.25,
|
||||
dependency: 6,
|
||||
lollipop: 13.5,
|
||||
arrow_point: 4,
|
||||
arrow_barb: 0,
|
||||
arrow_barb_neo: 5.5
|
||||
//arrow_cross: 24,
|
||||
};
|
||||
var markerOffsets2 = {
|
||||
arrow_point: 4,
|
||||
arrow_cross: 12.5,
|
||||
arrow_circle: 12.5
|
||||
};
|
||||
function calculateDeltaAndAngle(point1, point2) {
|
||||
if (point1 === void 0 || point2 === void 0) {
|
||||
return { angle: 0, deltaX: 0, deltaY: 0 };
|
||||
}
|
||||
point1 = pointTransformer(point1);
|
||||
point2 = pointTransformer(point2);
|
||||
const [x1, y1] = [point1.x, point1.y];
|
||||
const [x2, y2] = [point2.x, point2.y];
|
||||
const deltaX = x2 - x1;
|
||||
const deltaY = y2 - y1;
|
||||
return { angle: Math.atan(deltaY / deltaX), deltaX, deltaY };
|
||||
}
|
||||
__name(calculateDeltaAndAngle, "calculateDeltaAndAngle");
|
||||
var pointTransformer = /* @__PURE__ */ __name((data) => {
|
||||
if (Array.isArray(data)) {
|
||||
return { x: data[0], y: data[1] };
|
||||
}
|
||||
return data;
|
||||
}, "pointTransformer");
|
||||
var getLineFunctionsWithOffset = /* @__PURE__ */ __name((edge) => {
|
||||
return {
|
||||
x: /* @__PURE__ */ __name(function(d, i, data) {
|
||||
let offset = 0;
|
||||
const DIRECTION = pointTransformer(data[0]).x < pointTransformer(data[data.length - 1]).x ? "left" : "right";
|
||||
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
|
||||
const { angle, deltaX } = calculateDeltaAndAngle(data[0], data[1]);
|
||||
offset = markerOffsets[edge.arrowTypeStart] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1);
|
||||
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
|
||||
const { angle, deltaX } = calculateDeltaAndAngle(
|
||||
data[data.length - 1],
|
||||
data[data.length - 2]
|
||||
);
|
||||
offset = markerOffsets[edge.arrowTypeEnd] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1);
|
||||
}
|
||||
const differenceToEnd = Math.abs(
|
||||
pointTransformer(d).x - pointTransformer(data[data.length - 1]).x
|
||||
);
|
||||
const differenceInYEnd = Math.abs(
|
||||
pointTransformer(d).y - pointTransformer(data[data.length - 1]).y
|
||||
);
|
||||
const differenceToStart = Math.abs(pointTransformer(d).x - pointTransformer(data[0]).x);
|
||||
const differenceInYStart = Math.abs(pointTransformer(d).y - pointTransformer(data[0]).y);
|
||||
const startMarkerHeight = markerOffsets[edge.arrowTypeStart];
|
||||
const endMarkerHeight = markerOffsets[edge.arrowTypeEnd];
|
||||
const extraRoom = 1;
|
||||
if (differenceToEnd < endMarkerHeight && differenceToEnd > 0 && differenceInYEnd < endMarkerHeight) {
|
||||
let adjustment = endMarkerHeight + extraRoom - differenceToEnd;
|
||||
adjustment *= DIRECTION === "right" ? -1 : 1;
|
||||
offset -= adjustment;
|
||||
}
|
||||
if (differenceToStart < startMarkerHeight && differenceToStart > 0 && differenceInYStart < startMarkerHeight) {
|
||||
let adjustment = startMarkerHeight + extraRoom - differenceToStart;
|
||||
adjustment *= DIRECTION === "right" ? -1 : 1;
|
||||
offset += adjustment;
|
||||
}
|
||||
return pointTransformer(d).x + offset;
|
||||
}, "x"),
|
||||
y: /* @__PURE__ */ __name(function(d, i, data) {
|
||||
let offset = 0;
|
||||
const DIRECTION = pointTransformer(data[0]).y < pointTransformer(data[data.length - 1]).y ? "down" : "up";
|
||||
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
|
||||
const { angle, deltaY } = calculateDeltaAndAngle(data[0], data[1]);
|
||||
offset = markerOffsets[edge.arrowTypeStart] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
|
||||
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
|
||||
const { angle, deltaY } = calculateDeltaAndAngle(
|
||||
data[data.length - 1],
|
||||
data[data.length - 2]
|
||||
);
|
||||
offset = markerOffsets[edge.arrowTypeEnd] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
|
||||
}
|
||||
const differenceToEnd = Math.abs(
|
||||
pointTransformer(d).y - pointTransformer(data[data.length - 1]).y
|
||||
);
|
||||
const differenceInXEnd = Math.abs(
|
||||
pointTransformer(d).x - pointTransformer(data[data.length - 1]).x
|
||||
);
|
||||
const differenceToStart = Math.abs(pointTransformer(d).y - pointTransformer(data[0]).y);
|
||||
const differenceInXStart = Math.abs(pointTransformer(d).x - pointTransformer(data[0]).x);
|
||||
const startMarkerHeight = markerOffsets[edge.arrowTypeStart];
|
||||
const endMarkerHeight = markerOffsets[edge.arrowTypeEnd];
|
||||
const extraRoom = 1;
|
||||
if (differenceToEnd < endMarkerHeight && differenceToEnd > 0 && differenceInXEnd < endMarkerHeight) {
|
||||
let adjustment = endMarkerHeight + extraRoom - differenceToEnd;
|
||||
adjustment *= DIRECTION === "up" ? -1 : 1;
|
||||
offset -= adjustment;
|
||||
}
|
||||
if (differenceToStart < startMarkerHeight && differenceToStart > 0 && differenceInXStart < startMarkerHeight) {
|
||||
let adjustment = startMarkerHeight + extraRoom - differenceToStart;
|
||||
adjustment *= DIRECTION === "up" ? -1 : 1;
|
||||
offset += adjustment;
|
||||
}
|
||||
return pointTransformer(d).y + offset;
|
||||
}, "y")
|
||||
};
|
||||
}, "getLineFunctionsWithOffset");
|
||||
if (void 0) {
|
||||
const { it, expect, describe } = void 0;
|
||||
describe("calculateDeltaAndAngle", () => {
|
||||
it("should calculate the angle and deltas between two points", () => {
|
||||
expect(calculateDeltaAndAngle([0, 0], [0, 1])).toStrictEqual({
|
||||
angle: 1.5707963267948966,
|
||||
deltaX: 0,
|
||||
deltaY: 1
|
||||
});
|
||||
expect(calculateDeltaAndAngle([1, 0], [0, -1])).toStrictEqual({
|
||||
angle: 0.7853981633974483,
|
||||
deltaX: -1,
|
||||
deltaY: -1
|
||||
});
|
||||
expect(calculateDeltaAndAngle({ x: 1, y: 0 }, [0, -1])).toStrictEqual({
|
||||
angle: 0.7853981633974483,
|
||||
deltaX: -1,
|
||||
deltaY: -1
|
||||
});
|
||||
expect(calculateDeltaAndAngle({ x: 1, y: 0 }, { x: 1, y: 0 })).toStrictEqual({
|
||||
angle: NaN,
|
||||
deltaX: 0,
|
||||
deltaY: 0
|
||||
});
|
||||
});
|
||||
it("should calculate the angle and deltas if one point in undefined", () => {
|
||||
expect(calculateDeltaAndAngle(void 0, [0, 1])).toStrictEqual({
|
||||
angle: 0,
|
||||
deltaX: 0,
|
||||
deltaY: 0
|
||||
});
|
||||
expect(calculateDeltaAndAngle([0, 1], void 0)).toStrictEqual({
|
||||
angle: 0,
|
||||
deltaX: 0,
|
||||
deltaY: 0
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
computeLabelTransform,
|
||||
markerOffsets,
|
||||
markerOffsets2,
|
||||
getLineFunctionsWithOffset
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+33
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
configureSvgSize
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/setupViewPortForSVG.ts
|
||||
var setupViewPortForSVG = /* @__PURE__ */ __name((svg, padding, cssDiagram, useMaxWidth) => {
|
||||
svg.attr("class", cssDiagram);
|
||||
const { width, height, x, y } = calculateDimensionsWithPadding(svg, padding);
|
||||
configureSvgSize(svg, height, width, useMaxWidth);
|
||||
const viewBox = createViewBox(x, y, width, height, padding);
|
||||
svg.attr("viewBox", viewBox);
|
||||
log.debug(`viewBox configured: ${viewBox} with padding: ${padding}`);
|
||||
}, "setupViewPortForSVG");
|
||||
var calculateDimensionsWithPadding = /* @__PURE__ */ __name((svg, padding) => {
|
||||
const bounds = svg.node()?.getBBox() || { width: 0, height: 0, x: 0, y: 0 };
|
||||
return {
|
||||
width: bounds.width + padding * 2,
|
||||
height: bounds.height + padding * 2,
|
||||
x: bounds.x,
|
||||
y: bounds.y
|
||||
};
|
||||
}, "calculateDimensionsWithPadding");
|
||||
var createViewBox = /* @__PURE__ */ __name((x, y, width, height, padding) => {
|
||||
return `${x - padding} ${y - padding} ${width} ${height}`;
|
||||
}, "createViewBox");
|
||||
|
||||
export {
|
||||
setupViewPortForSVG
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/rendering-util/setupViewPortForSVG.ts"],
|
||||
"sourcesContent": ["import { configureSvgSize } from '../setupGraphViewbox.js';\nimport type { SVG } from '../diagram-api/types.js';\nimport { log } from '../logger.js';\n\nexport const setupViewPortForSVG = (\n svg: SVG,\n padding: number,\n cssDiagram: string,\n useMaxWidth: boolean\n) => {\n // Initialize the SVG element and set the diagram class\n svg.attr('class', cssDiagram);\n\n // Calculate the dimensions and position with padding\n const { width, height, x, y } = calculateDimensionsWithPadding(svg, padding);\n\n // Configure the size and aspect ratio of the SVG\n configureSvgSize(svg, height, width, useMaxWidth);\n\n // Update the viewBox to ensure all content is visible with padding\n const viewBox = createViewBox(x, y, width, height, padding);\n svg.attr('viewBox', viewBox);\n\n // Log the viewBox configuration for debugging\n log.debug(`viewBox configured: ${viewBox} with padding: ${padding}`);\n};\n\nconst calculateDimensionsWithPadding = (svg: SVG, padding: number) => {\n const bounds = svg.node()?.getBBox() || { width: 0, height: 0, x: 0, y: 0 };\n return {\n width: bounds.width + padding * 2,\n height: bounds.height + padding * 2,\n x: bounds.x,\n y: bounds.y,\n };\n};\n\nconst createViewBox = (x: number, y: number, width: number, height: number, padding: number) => {\n return `${x - padding} ${y - padding} ${width} ${height}`;\n};\n"],
|
||||
"mappings": ";;;;;;;;;AAIO,IAAM,sBAAsB,wBACjC,KACA,SACA,YACA,gBACG;AAEH,MAAI,KAAK,SAAS,UAAU;AAG5B,QAAM,EAAE,OAAO,QAAQ,GAAG,EAAE,IAAI,+BAA+B,KAAK,OAAO;AAG3E,mBAAiB,KAAK,QAAQ,OAAO,WAAW;AAGhD,QAAM,UAAU,cAAc,GAAG,GAAG,OAAO,QAAQ,OAAO;AAC1D,MAAI,KAAK,WAAW,OAAO;AAG3B,MAAI,MAAM,uBAAuB,OAAO,kBAAkB,OAAO,EAAE;AACrE,GArBmC;AAuBnC,IAAM,iCAAiC,wBAAC,KAAU,YAAoB;AACpE,QAAM,SAAS,IAAI,KAAK,GAAG,QAAQ,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,EAAE;AAC1E,SAAO;AAAA,IACL,OAAO,OAAO,QAAQ,UAAU;AAAA,IAChC,QAAQ,OAAO,SAAS,UAAU;AAAA,IAClC,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,EACZ;AACF,GARuC;AAUvC,IAAM,gBAAgB,wBAAC,GAAW,GAAW,OAAe,QAAgB,YAAoB;AAC9F,SAAO,GAAG,IAAI,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM;AACzD,GAFsB;",
|
||||
"names": []
|
||||
}
|
||||
+1055
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/globalStyles.ts
|
||||
var getIconStyles = /* @__PURE__ */ __name(() => `
|
||||
/* Font Awesome icon styling - consolidated */
|
||||
.label-icon {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
|
||||
.node .label-icon path {
|
||||
fill: currentColor;
|
||||
stroke: revert;
|
||||
stroke-width: revert;
|
||||
}
|
||||
`, "getIconStyles");
|
||||
|
||||
export {
|
||||
getIconStyles
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/globalStyles.ts"],
|
||||
"sourcesContent": ["export const getIconStyles = () => `\n /* Font Awesome icon styling - consolidated */\n .label-icon {\n display: inline-block;\n height: 1em;\n overflow: visible;\n vertical-align: -0.125em;\n }\n \n .node .label-icon path {\n fill: currentColor;\n stroke: revert;\n stroke-width: revert;\n }\n`;\n"],
|
||||
"mappings": ";;;;;AAAO,IAAM,gBAAgB,6BAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAAN;",
|
||||
"names": []
|
||||
}
|
||||
+5197
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+2051
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/utils/imperativeState.ts
|
||||
var ImperativeState = class {
|
||||
/**
|
||||
* @param init - Function that creates the default state.
|
||||
*/
|
||||
constructor(init) {
|
||||
this.init = init;
|
||||
this.records = this.init();
|
||||
}
|
||||
static {
|
||||
__name(this, "ImperativeState");
|
||||
}
|
||||
reset() {
|
||||
this.records = this.init();
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
ImperativeState
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/utils/imperativeState.ts"],
|
||||
"sourcesContent": ["/**\n * Resettable state storage.\n * @example\n * ```\n * const state = new ImperativeState(() => ({\n * foo: undefined as string | undefined,\n * bar: [] as number[],\n * baz: 1 as number | undefined,\n * }));\n *\n * state.records.foo = \"hi\";\n * console.log(state.records.foo); // prints \"hi\";\n * state.reset();\n * console.log(state.records.foo); // prints \"default\";\n *\n * // typeof state.records:\n * // {\n * // foo: string | undefined, // actual: undefined\n * // bar: number[], // actual: []\n * // baz: number | undefined, // actual: 1\n * // }\n * ```\n */\nexport class ImperativeState<S> {\n public records: S;\n\n /**\n * @param init - Function that creates the default state.\n */\n constructor(private init: () => S) {\n this.records = this.init();\n }\n\n reset() {\n this.records = this.init();\n }\n}\n"],
|
||||
"mappings": ";;;;;AAuBO,IAAM,kBAAN,MAAyB;AAAA;AAAA;AAAA;AAAA,EAM9B,YAAoB,MAAe;AAAf;AAClB,SAAK,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EA/BF,OAuBgC;AAAA;AAAA;AAAA,EAU9B,QAAQ;AACN,SAAK,UAAU,KAAK,KAAK;AAAA,EAC3B;AACF;",
|
||||
"names": []
|
||||
}
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
import {
|
||||
decodeEntities
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
common_default,
|
||||
getConfig,
|
||||
hasKatex,
|
||||
renderKatexSanitized,
|
||||
sanitizeText
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/icons.ts
|
||||
import { getIconData, iconToHTML, iconToSVG, replaceIDs, stringToIcon } from "@iconify/utils";
|
||||
var unknownIcon = {
|
||||
body: '<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>',
|
||||
height: 80,
|
||||
width: 80
|
||||
};
|
||||
var iconsStore = /* @__PURE__ */ new Map();
|
||||
var loaderStore = /* @__PURE__ */ new Map();
|
||||
var registerIconPacks = /* @__PURE__ */ __name((iconLoaders) => {
|
||||
for (const iconLoader of iconLoaders) {
|
||||
if (!iconLoader.name) {
|
||||
throw new Error(
|
||||
'Invalid icon loader. Must have a "name" property with non-empty string value.'
|
||||
);
|
||||
}
|
||||
log.debug("Registering icon pack:", iconLoader.name);
|
||||
if ("loader" in iconLoader) {
|
||||
loaderStore.set(iconLoader.name, iconLoader.loader);
|
||||
} else if ("icons" in iconLoader) {
|
||||
iconsStore.set(iconLoader.name, iconLoader.icons);
|
||||
} else {
|
||||
log.error("Invalid icon loader:", iconLoader);
|
||||
throw new Error('Invalid icon loader. Must have either "icons" or "loader" property.');
|
||||
}
|
||||
}
|
||||
}, "registerIconPacks");
|
||||
var getRegisteredIconData = /* @__PURE__ */ __name(async (iconName, fallbackPrefix) => {
|
||||
const data = stringToIcon(iconName, true, fallbackPrefix !== void 0);
|
||||
if (!data) {
|
||||
throw new Error(`Invalid icon name: ${iconName}`);
|
||||
}
|
||||
const prefix = data.prefix || fallbackPrefix;
|
||||
if (!prefix) {
|
||||
throw new Error(`Icon name must contain a prefix: ${iconName}`);
|
||||
}
|
||||
let icons = iconsStore.get(prefix);
|
||||
if (!icons) {
|
||||
const loader = loaderStore.get(prefix);
|
||||
if (!loader) {
|
||||
throw new Error(`Icon set not found: ${data.prefix}`);
|
||||
}
|
||||
try {
|
||||
const loaded = await loader();
|
||||
icons = { ...loaded, prefix };
|
||||
iconsStore.set(prefix, icons);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
throw new Error(`Failed to load icon set: ${data.prefix}`);
|
||||
}
|
||||
}
|
||||
const iconData = getIconData(icons, data.name);
|
||||
if (!iconData) {
|
||||
throw new Error(`Icon not found: ${iconName}`);
|
||||
}
|
||||
return iconData;
|
||||
}, "getRegisteredIconData");
|
||||
var isIconAvailable = /* @__PURE__ */ __name(async (iconName) => {
|
||||
try {
|
||||
await getRegisteredIconData(iconName);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}, "isIconAvailable");
|
||||
var getIconSVG = /* @__PURE__ */ __name(async (iconName, customisations, extraAttributes) => {
|
||||
let iconData;
|
||||
try {
|
||||
iconData = await getRegisteredIconData(iconName, customisations?.fallbackPrefix);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
iconData = unknownIcon;
|
||||
}
|
||||
const renderData = iconToSVG(iconData, customisations);
|
||||
const svg = iconToHTML(replaceIDs(renderData.body), {
|
||||
...renderData.attributes,
|
||||
...extraAttributes
|
||||
});
|
||||
return sanitizeText(svg, getConfig());
|
||||
}, "getIconSVG");
|
||||
|
||||
// src/rendering-util/createText.ts
|
||||
import { select } from "d3";
|
||||
|
||||
// src/rendering-util/handle-markdown-text.ts
|
||||
import { marked } from "marked";
|
||||
import { dedent } from "ts-dedent";
|
||||
function preprocessMarkdown(markdown, { markdownAutoWrap }) {
|
||||
const withoutBR = markdown.replace(/<br\/>/g, "\n");
|
||||
const withoutMultipleNewlines = withoutBR.replace(/\n{2,}/g, "\n");
|
||||
const withoutExtraSpaces = dedent(withoutMultipleNewlines);
|
||||
if (markdownAutoWrap === false) {
|
||||
}
|
||||
return withoutExtraSpaces;
|
||||
}
|
||||
__name(preprocessMarkdown, "preprocessMarkdown");
|
||||
function nonMarkdownToLines(nonMarkdownText) {
|
||||
return nonMarkdownText.split(/\\n|\n|<br\s*\/?>/gi).map(
|
||||
(line) => line.trim().match(/<[^>]+>|[^\s<>]+/g)?.map((word) => ({ content: word, type: "normal" })) ?? []
|
||||
);
|
||||
}
|
||||
__name(nonMarkdownToLines, "nonMarkdownToLines");
|
||||
function markdownToLines(markdown, config = {}) {
|
||||
const preprocessedMarkdown = preprocessMarkdown(markdown, config);
|
||||
const nodes = marked.lexer(preprocessedMarkdown);
|
||||
const lines = [[]];
|
||||
let currentLine = 0;
|
||||
function processNode(node, parentType = "normal") {
|
||||
if (node.type === "text") {
|
||||
const textLines = node.text.split("\n");
|
||||
textLines.forEach((textLine, index) => {
|
||||
if (index !== 0) {
|
||||
currentLine++;
|
||||
lines.push([]);
|
||||
}
|
||||
textLine.split(" ").forEach((word) => {
|
||||
word = word.replace(/'/g, `'`);
|
||||
if (word) {
|
||||
lines[currentLine].push({ content: word, type: parentType });
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (node.type === "strong" || node.type === "em") {
|
||||
node.tokens.forEach((contentNode) => {
|
||||
processNode(contentNode, node.type);
|
||||
});
|
||||
} else if (node.type === "html") {
|
||||
lines[currentLine].push({ content: node.text, type: "normal" });
|
||||
}
|
||||
}
|
||||
__name(processNode, "processNode");
|
||||
nodes.forEach((treeNode) => {
|
||||
if (treeNode.type === "paragraph") {
|
||||
treeNode.tokens?.forEach((contentNode) => {
|
||||
processNode(contentNode);
|
||||
});
|
||||
} else if (treeNode.type === "html") {
|
||||
lines[currentLine].push({ content: treeNode.text, type: "normal" });
|
||||
} else {
|
||||
lines[currentLine].push({ content: treeNode.raw, type: "normal" });
|
||||
}
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
__name(markdownToLines, "markdownToLines");
|
||||
function nonMarkdownToHTML(text) {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
return `<p>${/**
|
||||
* Replace new lines with <br /> tags.
|
||||
*
|
||||
* Unlike in markdown text, `\n` sequences are treated as line breaks here.
|
||||
*/
|
||||
text.replace(/\\n|\n/g, "<br />")}</p>`;
|
||||
}
|
||||
__name(nonMarkdownToHTML, "nonMarkdownToHTML");
|
||||
function markdownToHTML(markdown, { markdownAutoWrap } = {}) {
|
||||
const nodes = marked.lexer(markdown);
|
||||
function output(node) {
|
||||
if (node.type === "text") {
|
||||
if (markdownAutoWrap === false) {
|
||||
return node.text.replace(/\n */g, "<br/>").replace(/ /g, " ");
|
||||
}
|
||||
return node.text.replace(/\n */g, "<br/>");
|
||||
} else if (node.type === "strong") {
|
||||
return `<strong>${node.tokens?.map(output).join("")}</strong>`;
|
||||
} else if (node.type === "em") {
|
||||
return `<em>${node.tokens?.map(output).join("")}</em>`;
|
||||
} else if (node.type === "paragraph") {
|
||||
return `<p>${node.tokens?.map(output).join("")}</p>`;
|
||||
} else if (node.type === "space") {
|
||||
return "";
|
||||
} else if (node.type === "html") {
|
||||
return `${node.text}`;
|
||||
} else if (node.type === "escape") {
|
||||
return node.text;
|
||||
}
|
||||
log.warn(`Unsupported markdown: ${node.type}`);
|
||||
return node.raw;
|
||||
}
|
||||
__name(output, "output");
|
||||
return nodes.map(output).join("");
|
||||
}
|
||||
__name(markdownToHTML, "markdownToHTML");
|
||||
|
||||
// src/rendering-util/splitText.ts
|
||||
function splitTextToChars(text) {
|
||||
if (Intl.Segmenter) {
|
||||
return [...new Intl.Segmenter().segment(text)].map((s) => s.segment);
|
||||
}
|
||||
return [...text];
|
||||
}
|
||||
__name(splitTextToChars, "splitTextToChars");
|
||||
function splitWordToFitWidth(checkFit, word) {
|
||||
const characters = splitTextToChars(word.content);
|
||||
return splitWordToFitWidthRecursion(checkFit, [], characters, word.type);
|
||||
}
|
||||
__name(splitWordToFitWidth, "splitWordToFitWidth");
|
||||
function splitWordToFitWidthRecursion(checkFit, usedChars, remainingChars, type) {
|
||||
if (remainingChars.length === 0) {
|
||||
return [
|
||||
{ content: usedChars.join(""), type },
|
||||
{ content: "", type }
|
||||
];
|
||||
}
|
||||
const [nextChar, ...rest] = remainingChars;
|
||||
const newWord = [...usedChars, nextChar];
|
||||
if (checkFit([{ content: newWord.join(""), type }])) {
|
||||
return splitWordToFitWidthRecursion(checkFit, newWord, rest, type);
|
||||
}
|
||||
if (usedChars.length === 0 && nextChar) {
|
||||
usedChars.push(nextChar);
|
||||
remainingChars.shift();
|
||||
}
|
||||
return [
|
||||
{ content: usedChars.join(""), type },
|
||||
{ content: remainingChars.join(""), type }
|
||||
];
|
||||
}
|
||||
__name(splitWordToFitWidthRecursion, "splitWordToFitWidthRecursion");
|
||||
function splitLineToFitWidth(line, checkFit) {
|
||||
if (line.some(({ content }) => content.includes("\n"))) {
|
||||
throw new Error("splitLineToFitWidth does not support newlines in the line");
|
||||
}
|
||||
return splitLineToFitWidthRecursion(line, checkFit);
|
||||
}
|
||||
__name(splitLineToFitWidth, "splitLineToFitWidth");
|
||||
function splitLineToFitWidthRecursion(words, checkFit, lines = [], newLine = []) {
|
||||
if (words.length === 0) {
|
||||
if (newLine.length > 0) {
|
||||
lines.push(newLine);
|
||||
}
|
||||
return lines.length > 0 ? lines : [];
|
||||
}
|
||||
let joiner = "";
|
||||
if (words[0].content === " ") {
|
||||
joiner = " ";
|
||||
words.shift();
|
||||
}
|
||||
const nextWord = words.shift() ?? { content: " ", type: "normal" };
|
||||
const lineWithNextWord = [...newLine];
|
||||
if (joiner !== "") {
|
||||
lineWithNextWord.push({ content: joiner, type: "normal" });
|
||||
}
|
||||
lineWithNextWord.push(nextWord);
|
||||
if (checkFit(lineWithNextWord)) {
|
||||
return splitLineToFitWidthRecursion(words, checkFit, lines, lineWithNextWord);
|
||||
}
|
||||
if (newLine.length > 0) {
|
||||
lines.push(newLine);
|
||||
words.unshift(nextWord);
|
||||
} else if (nextWord.content) {
|
||||
const [line, rest] = splitWordToFitWidth(checkFit, nextWord);
|
||||
lines.push([line]);
|
||||
if (rest.content) {
|
||||
words.unshift(rest);
|
||||
}
|
||||
}
|
||||
return splitLineToFitWidthRecursion(words, checkFit, lines);
|
||||
}
|
||||
__name(splitLineToFitWidthRecursion, "splitLineToFitWidthRecursion");
|
||||
|
||||
// src/rendering-util/createText.ts
|
||||
function applyStyle(dom, styleFn) {
|
||||
if (styleFn) {
|
||||
dom.attr("style", styleFn);
|
||||
}
|
||||
}
|
||||
__name(applyStyle, "applyStyle");
|
||||
var maxSafeSizeForWidth = 16384;
|
||||
async function addHtmlSpan(element, node, width, classes, addBackground = false, config = getConfig()) {
|
||||
const fo = element.append("foreignObject");
|
||||
fo.attr("width", `${Math.min(10 * width, maxSafeSizeForWidth)}px`);
|
||||
fo.attr("height", `${Math.min(10 * width, maxSafeSizeForWidth)}px`);
|
||||
const div = fo.append("xhtml:div");
|
||||
const sanitizedLabel = hasKatex(node.label) ? await renderKatexSanitized(node.label.replace(common_default.lineBreakRegex, "\n"), config) : sanitizeText(node.label, config);
|
||||
const labelClass = node.isNode ? "nodeLabel" : "edgeLabel";
|
||||
const span = div.append("span");
|
||||
span.html(sanitizedLabel);
|
||||
applyStyle(span, node.labelStyle);
|
||||
span.attr("class", `${labelClass} ${classes}`);
|
||||
applyStyle(div, node.labelStyle);
|
||||
div.style("display", "table-cell");
|
||||
div.style("white-space", "nowrap");
|
||||
div.style("line-height", "1.5");
|
||||
if (width !== Number.POSITIVE_INFINITY) {
|
||||
div.style("max-width", width + "px");
|
||||
div.style("text-align", "center");
|
||||
}
|
||||
div.attr("xmlns", "http://www.w3.org/1999/xhtml");
|
||||
if (addBackground) {
|
||||
div.attr("class", "labelBkg");
|
||||
}
|
||||
let bbox = div.node().getBoundingClientRect();
|
||||
if (bbox.width === width) {
|
||||
div.style("display", "table");
|
||||
div.style("white-space", "break-spaces");
|
||||
div.style("width", width + "px");
|
||||
bbox = div.node().getBoundingClientRect();
|
||||
}
|
||||
return fo.node();
|
||||
}
|
||||
__name(addHtmlSpan, "addHtmlSpan");
|
||||
function createTspan(textElement, lineIndex, lineHeight, centerText = false) {
|
||||
const tspan = textElement.append("tspan").attr("class", "text-outer-tspan").attr("x", 0).attr("y", lineIndex * lineHeight - 0.1 + "em").attr("dy", lineHeight + "em");
|
||||
if (centerText) {
|
||||
tspan.attr("text-anchor", "middle");
|
||||
}
|
||||
return tspan;
|
||||
}
|
||||
__name(createTspan, "createTspan");
|
||||
function computeWidthOfText(parentNode, lineHeight, line) {
|
||||
const testElement = parentNode.append("text");
|
||||
const testSpan = createTspan(testElement, 1, lineHeight);
|
||||
updateTextContentAndStyles(testSpan, line);
|
||||
const textLength = testSpan.node().getComputedTextLength();
|
||||
testElement.remove();
|
||||
return textLength;
|
||||
}
|
||||
__name(computeWidthOfText, "computeWidthOfText");
|
||||
function computeDimensionOfText(parentNode, lineHeight, text) {
|
||||
const testElement = parentNode.append("text");
|
||||
const testSpan = createTspan(testElement, 1, lineHeight);
|
||||
updateTextContentAndStyles(testSpan, [{ content: text, type: "normal" }]);
|
||||
const textDimension = testSpan.node()?.getBoundingClientRect();
|
||||
if (textDimension) {
|
||||
testElement.remove();
|
||||
}
|
||||
return textDimension;
|
||||
}
|
||||
__name(computeDimensionOfText, "computeDimensionOfText");
|
||||
function createFormattedText(width, g, structuredText, addBackground = false, centerText = false) {
|
||||
const lineHeight = 1.1;
|
||||
const labelGroup = g.append("g");
|
||||
const bkg = labelGroup.insert("rect").attr("class", "background").attr("style", "stroke: none");
|
||||
const textElement = labelGroup.append("text").attr("y", "-10.1");
|
||||
if (centerText) {
|
||||
textElement.attr("text-anchor", "middle");
|
||||
}
|
||||
let lineIndex = 0;
|
||||
for (const line of structuredText) {
|
||||
const checkWidth = /* @__PURE__ */ __name((line2) => computeWidthOfText(labelGroup, lineHeight, line2) <= width, "checkWidth");
|
||||
const linesUnderWidth = checkWidth(line) ? [line] : splitLineToFitWidth(line, checkWidth);
|
||||
for (const preparedLine of linesUnderWidth) {
|
||||
const tspan = createTspan(textElement, lineIndex, lineHeight, centerText);
|
||||
updateTextContentAndStyles(tspan, preparedLine);
|
||||
lineIndex++;
|
||||
}
|
||||
}
|
||||
if (addBackground) {
|
||||
const bbox = textElement.node().getBBox();
|
||||
const padding = 2;
|
||||
bkg.attr("x", bbox.x - padding).attr("y", bbox.y - padding).attr("width", bbox.width + 2 * padding).attr("height", bbox.height + 2 * padding);
|
||||
return labelGroup.node();
|
||||
} else {
|
||||
return textElement.node();
|
||||
}
|
||||
}
|
||||
__name(createFormattedText, "createFormattedText");
|
||||
function decodeHTMLEntities(text) {
|
||||
const regex = /&(amp|lt|gt);/g;
|
||||
return text.replace(regex, (match, entity) => {
|
||||
switch (entity) {
|
||||
case "amp":
|
||||
return "&";
|
||||
case "lt":
|
||||
return "<";
|
||||
case "gt":
|
||||
return ">";
|
||||
default:
|
||||
return match;
|
||||
}
|
||||
});
|
||||
}
|
||||
__name(decodeHTMLEntities, "decodeHTMLEntities");
|
||||
function updateTextContentAndStyles(tspan, wrappedLine) {
|
||||
tspan.text("");
|
||||
wrappedLine.forEach((word, index) => {
|
||||
const innerTspan = tspan.append("tspan").attr("font-style", word.type === "em" ? "italic" : "normal").attr("class", "text-inner-tspan").attr("font-weight", word.type === "strong" ? "bold" : "normal");
|
||||
if (index === 0) {
|
||||
innerTspan.text(decodeHTMLEntities(word.content));
|
||||
} else {
|
||||
innerTspan.text(" " + decodeHTMLEntities(word.content));
|
||||
}
|
||||
});
|
||||
}
|
||||
__name(updateTextContentAndStyles, "updateTextContentAndStyles");
|
||||
async function replaceIconSubstring(text, config = {}) {
|
||||
const pendingReplacements = [];
|
||||
text.replace(/(fa[bklrs]?):fa-([\w-]+)/g, (fullMatch, prefix, iconName) => {
|
||||
pendingReplacements.push(
|
||||
(async () => {
|
||||
const registeredIconName = `${prefix}:${iconName}`;
|
||||
if (await isIconAvailable(registeredIconName)) {
|
||||
return await getIconSVG(registeredIconName, void 0, { class: "label-icon" });
|
||||
} else {
|
||||
return `<i class='${sanitizeText(fullMatch, config).replace(":", " ")}'></i>`;
|
||||
}
|
||||
})()
|
||||
);
|
||||
return fullMatch;
|
||||
});
|
||||
const replacements = await Promise.all(pendingReplacements);
|
||||
return text.replace(/(fa[bklrs]?):fa-([\w-]+)/g, () => replacements.shift() ?? "");
|
||||
}
|
||||
__name(replaceIconSubstring, "replaceIconSubstring");
|
||||
var createText = /* @__PURE__ */ __name(async (el, text = "", {
|
||||
style = "",
|
||||
isTitle = false,
|
||||
classes = "",
|
||||
useHtmlLabels = true,
|
||||
markdown = true,
|
||||
isNode = true,
|
||||
/**
|
||||
* The width to wrap the text within. Set to `Number.POSITIVE_INFINITY` for no wrapping.
|
||||
*/
|
||||
width = 200,
|
||||
addSvgBackground = false
|
||||
} = {}, config) => {
|
||||
log.debug(
|
||||
"XYZ createText",
|
||||
text,
|
||||
style,
|
||||
isTitle,
|
||||
classes,
|
||||
useHtmlLabels,
|
||||
isNode,
|
||||
"addSvgBackground: ",
|
||||
addSvgBackground
|
||||
);
|
||||
if (useHtmlLabels) {
|
||||
const htmlText = markdown ? markdownToHTML(text, config) : nonMarkdownToHTML(text);
|
||||
const decodedReplacedText = await replaceIconSubstring(decodeEntities(htmlText), config);
|
||||
const inputForKatex = text.replace(/\\\\/g, "\\");
|
||||
const node = {
|
||||
isNode,
|
||||
label: hasKatex(text) ? inputForKatex : decodedReplacedText,
|
||||
labelStyle: style.replace("fill:", "color:")
|
||||
};
|
||||
const vertexNode = await addHtmlSpan(el, node, width, classes, addSvgBackground, config);
|
||||
return vertexNode;
|
||||
} else {
|
||||
const sanitizeBR = decodeEntities(text.replace(/<br\s*\/?>/g, "<br/>"));
|
||||
const structuredText = markdown ? markdownToLines(sanitizeBR.replace("<br>", "<br/>"), config) : nonMarkdownToLines(sanitizeBR);
|
||||
const svgLabel = createFormattedText(
|
||||
width,
|
||||
el,
|
||||
structuredText,
|
||||
text ? addSvgBackground : false,
|
||||
!isNode
|
||||
);
|
||||
if (isNode) {
|
||||
if (/stroke:/.exec(style)) {
|
||||
style = style.replace("stroke:", "lineColor:");
|
||||
}
|
||||
const nodeLabelTextStyle = style.replace(/stroke:[^;]+;?/g, "").replace(/stroke-width:[^;]+;?/g, "").replace(/fill:[^;]+;?/g, "").replace(/color:/g, "fill:");
|
||||
select(svgLabel).attr("style", nodeLabelTextStyle);
|
||||
} else {
|
||||
const edgeLabelRectStyle = style.replace(/stroke:[^;]+;?/g, "").replace(/stroke-width:[^;]+;?/g, "").replace(/fill:[^;]+;?/g, "").replace(/background:/g, "fill:");
|
||||
select(svgLabel).select("rect").attr("style", edgeLabelRectStyle.replace(/background:/g, "fill:"));
|
||||
const edgeLabelTextStyle = style.replace(/stroke:[^;]+;?/g, "").replace(/stroke-width:[^;]+;?/g, "").replace(/fill:[^;]+;?/g, "").replace(/color:/g, "fill:");
|
||||
select(svgLabel).select("text").attr("style", edgeLabelTextStyle);
|
||||
}
|
||||
if (isTitle) {
|
||||
select(svgLabel).selectAll("tspan.text-outer-tspan").classed("title-row", true);
|
||||
} else {
|
||||
select(svgLabel).selectAll("tspan.text-outer-tspan").classed("row", true);
|
||||
}
|
||||
return svgLabel;
|
||||
}
|
||||
}, "createText");
|
||||
|
||||
export {
|
||||
unknownIcon,
|
||||
registerIconPacks,
|
||||
getIconSVG,
|
||||
computeDimensionOfText,
|
||||
createText
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+111
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
getConfig2 as getConfig
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts
|
||||
var solidStateFill = /* @__PURE__ */ __name((color) => {
|
||||
const { handDrawnSeed } = getConfig();
|
||||
return {
|
||||
fill: color,
|
||||
hachureAngle: 120,
|
||||
// angle of hachure,
|
||||
hachureGap: 4,
|
||||
fillWeight: 2,
|
||||
roughness: 0.7,
|
||||
stroke: color,
|
||||
seed: handDrawnSeed
|
||||
};
|
||||
}, "solidStateFill");
|
||||
var compileStyles = /* @__PURE__ */ __name((node) => {
|
||||
const stylesMap = styles2Map([
|
||||
...node.cssCompiledStyles || [],
|
||||
...node.cssStyles || [],
|
||||
...node.labelStyle || []
|
||||
]);
|
||||
return { stylesMap, stylesArray: [...stylesMap] };
|
||||
}, "compileStyles");
|
||||
var styles2Map = /* @__PURE__ */ __name((styles) => {
|
||||
const styleMap = /* @__PURE__ */ new Map();
|
||||
styles.forEach((style) => {
|
||||
const [key, value] = style.split(":");
|
||||
styleMap.set(key.trim(), value?.trim());
|
||||
});
|
||||
return styleMap;
|
||||
}, "styles2Map");
|
||||
var isLabelStyle = /* @__PURE__ */ __name((key) => {
|
||||
return key === "color" || key === "font-size" || key === "font-family" || key === "font-weight" || key === "font-style" || key === "text-decoration" || key === "text-align" || key === "text-transform" || key === "line-height" || key === "letter-spacing" || key === "word-spacing" || key === "text-shadow" || key === "text-overflow" || key === "white-space" || key === "word-wrap" || key === "word-break" || key === "overflow-wrap" || key === "hyphens";
|
||||
}, "isLabelStyle");
|
||||
var styles2String = /* @__PURE__ */ __name((node) => {
|
||||
const { stylesArray } = compileStyles(node);
|
||||
const labelStyles = [];
|
||||
const nodeStyles = [];
|
||||
const borderStyles = [];
|
||||
const backgroundStyles = [];
|
||||
stylesArray.forEach((style) => {
|
||||
const key = style[0];
|
||||
if (isLabelStyle(key)) {
|
||||
labelStyles.push(style.join(":") + " !important");
|
||||
} else {
|
||||
nodeStyles.push(style.join(":") + " !important");
|
||||
if (key.includes("stroke")) {
|
||||
borderStyles.push(style.join(":") + " !important");
|
||||
}
|
||||
if (key === "fill") {
|
||||
backgroundStyles.push(style.join(":") + " !important");
|
||||
}
|
||||
}
|
||||
});
|
||||
return {
|
||||
labelStyles: labelStyles.join(";"),
|
||||
nodeStyles: nodeStyles.join(";"),
|
||||
stylesArray,
|
||||
borderStyles,
|
||||
backgroundStyles
|
||||
};
|
||||
}, "styles2String");
|
||||
var userNodeOverrides = /* @__PURE__ */ __name((node, options) => {
|
||||
const { themeVariables, handDrawnSeed } = getConfig();
|
||||
const { nodeBorder, mainBkg } = themeVariables;
|
||||
const { stylesMap } = compileStyles(node);
|
||||
const result = Object.assign(
|
||||
{
|
||||
roughness: 0.7,
|
||||
fill: stylesMap.get("fill") || mainBkg,
|
||||
fillStyle: "hachure",
|
||||
// solid fill
|
||||
fillWeight: 4,
|
||||
hachureGap: 5.2,
|
||||
stroke: stylesMap.get("stroke") || nodeBorder,
|
||||
seed: handDrawnSeed,
|
||||
strokeWidth: stylesMap.get("stroke-width")?.replace("px", "") || 1.3,
|
||||
fillLineDash: [0, 0],
|
||||
strokeLineDash: getStrokeDashArray(stylesMap.get("stroke-dasharray"))
|
||||
},
|
||||
options
|
||||
);
|
||||
return result;
|
||||
}, "userNodeOverrides");
|
||||
var getStrokeDashArray = /* @__PURE__ */ __name((strokeDasharrayStyle) => {
|
||||
if (!strokeDasharrayStyle) {
|
||||
return [0, 0];
|
||||
}
|
||||
const dashArray = strokeDasharrayStyle.trim().split(/\s+/).map(Number);
|
||||
if (dashArray.length === 1) {
|
||||
const val = isNaN(dashArray[0]) ? 0 : dashArray[0];
|
||||
return [val, val];
|
||||
}
|
||||
const first = isNaN(dashArray[0]) ? 0 : dashArray[0];
|
||||
const second = isNaN(dashArray[1]) ? 0 : dashArray[1];
|
||||
return [first, second];
|
||||
}, "getStrokeDashArray");
|
||||
|
||||
export {
|
||||
solidStateFill,
|
||||
compileStyles,
|
||||
isLabelStyle,
|
||||
styles2String,
|
||||
userNodeOverrides
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts"],
|
||||
"sourcesContent": ["import { getConfig } from '../../../diagram-api/diagramAPI.js';\nimport type { Node } from '../../types.js';\n\n// Striped fill like start or fork nodes in state diagrams\nexport const solidStateFill = (color: string) => {\n const { handDrawnSeed } = getConfig();\n return {\n fill: color,\n hachureAngle: 120, // angle of hachure,\n hachureGap: 4,\n fillWeight: 2,\n roughness: 0.7,\n stroke: color,\n seed: handDrawnSeed,\n };\n};\n\nexport const compileStyles = (node: Node) => {\n // node.cssCompiledStyles is an array of strings in the form of 'key: value' where key is the css property and value is the value\n // the array is the styles of node from the classes it is using\n // node.cssStyles is an array of styles directly set on the node\n // concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates\n const stylesMap = styles2Map([\n ...(node.cssCompiledStyles || []),\n ...(node.cssStyles || []),\n ...(node.labelStyle || []),\n ]);\n return { stylesMap, stylesArray: [...stylesMap] };\n};\n\nexport const styles2Map = (styles: string[]) => {\n const styleMap = new Map<string, string>();\n styles.forEach((style) => {\n const [key, value] = style.split(':');\n styleMap.set(key.trim(), value?.trim());\n });\n return styleMap;\n};\nexport const isLabelStyle = (key: string) => {\n return (\n key === 'color' ||\n key === 'font-size' ||\n key === 'font-family' ||\n key === 'font-weight' ||\n key === 'font-style' ||\n key === 'text-decoration' ||\n key === 'text-align' ||\n key === 'text-transform' ||\n key === 'line-height' ||\n key === 'letter-spacing' ||\n key === 'word-spacing' ||\n key === 'text-shadow' ||\n key === 'text-overflow' ||\n key === 'white-space' ||\n key === 'word-wrap' ||\n key === 'word-break' ||\n key === 'overflow-wrap' ||\n key === 'hyphens'\n );\n};\nexport const styles2String = (node: Node) => {\n const { stylesArray } = compileStyles(node);\n const labelStyles: string[] = [];\n const nodeStyles: string[] = [];\n const borderStyles: string[] = [];\n const backgroundStyles: string[] = [];\n\n stylesArray.forEach((style) => {\n const key = style[0];\n if (isLabelStyle(key)) {\n labelStyles.push(style.join(':') + ' !important');\n } else {\n nodeStyles.push(style.join(':') + ' !important');\n if (key.includes('stroke')) {\n borderStyles.push(style.join(':') + ' !important');\n }\n if (key === 'fill') {\n backgroundStyles.push(style.join(':') + ' !important');\n }\n }\n });\n\n return {\n labelStyles: labelStyles.join(';'),\n nodeStyles: nodeStyles.join(';'),\n stylesArray,\n borderStyles,\n backgroundStyles,\n };\n};\n\n// Striped fill like start or fork nodes in state diagrams\n// TODO remove any\nexport const userNodeOverrides = (node: Node, options: any) => {\n const { themeVariables, handDrawnSeed } = getConfig();\n const { nodeBorder, mainBkg } = themeVariables;\n const { stylesMap } = compileStyles(node);\n\n // index the style array to a map object\n const result = Object.assign(\n {\n roughness: 0.7,\n fill: stylesMap.get('fill') || mainBkg,\n fillStyle: 'hachure', // solid fill\n fillWeight: 4,\n hachureGap: 5.2,\n stroke: stylesMap.get('stroke') || nodeBorder,\n seed: handDrawnSeed,\n strokeWidth: stylesMap.get('stroke-width')?.replace('px', '') || 1.3,\n fillLineDash: [0, 0],\n strokeLineDash: getStrokeDashArray(stylesMap.get('stroke-dasharray')),\n },\n options\n );\n return result;\n};\n\nconst getStrokeDashArray = (strokeDasharrayStyle?: string) => {\n if (!strokeDasharrayStyle) {\n return [0, 0];\n }\n const dashArray = strokeDasharrayStyle.trim().split(/\\s+/).map(Number);\n if (dashArray.length === 1) {\n const val = isNaN(dashArray[0]) ? 0 : dashArray[0];\n return [val, val];\n }\n const first = isNaN(dashArray[0]) ? 0 : dashArray[0];\n const second = isNaN(dashArray[1]) ? 0 : dashArray[1];\n return [first, second];\n};\n"],
|
||||
"mappings": ";;;;;;;;AAIO,IAAM,iBAAiB,wBAAC,UAAkB;AAC/C,QAAM,EAAE,cAAc,IAAI,UAAU;AACpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,cAAc;AAAA;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,MAAM;AAAA,EACR;AACF,GAX8B;AAavB,IAAM,gBAAgB,wBAAC,SAAe;AAK3C,QAAM,YAAY,WAAW;AAAA,IAC3B,GAAI,KAAK,qBAAqB,CAAC;AAAA,IAC/B,GAAI,KAAK,aAAa,CAAC;AAAA,IACvB,GAAI,KAAK,cAAc,CAAC;AAAA,EAC1B,CAAC;AACD,SAAO,EAAE,WAAW,aAAa,CAAC,GAAG,SAAS,EAAE;AAClD,GAX6B;AAatB,IAAM,aAAa,wBAAC,WAAqB;AAC9C,QAAM,WAAW,oBAAI,IAAoB;AACzC,SAAO,QAAQ,CAAC,UAAU;AACxB,UAAM,CAAC,KAAK,KAAK,IAAI,MAAM,MAAM,GAAG;AACpC,aAAS,IAAI,IAAI,KAAK,GAAG,OAAO,KAAK,CAAC;AAAA,EACxC,CAAC;AACD,SAAO;AACT,GAP0B;AAQnB,IAAM,eAAe,wBAAC,QAAgB;AAC3C,SACE,QAAQ,WACR,QAAQ,eACR,QAAQ,iBACR,QAAQ,iBACR,QAAQ,gBACR,QAAQ,qBACR,QAAQ,gBACR,QAAQ,oBACR,QAAQ,iBACR,QAAQ,oBACR,QAAQ,kBACR,QAAQ,iBACR,QAAQ,mBACR,QAAQ,iBACR,QAAQ,eACR,QAAQ,gBACR,QAAQ,mBACR,QAAQ;AAEZ,GArB4B;AAsBrB,IAAM,gBAAgB,wBAAC,SAAe;AAC3C,QAAM,EAAE,YAAY,IAAI,cAAc,IAAI;AAC1C,QAAM,cAAwB,CAAC;AAC/B,QAAM,aAAuB,CAAC;AAC9B,QAAM,eAAyB,CAAC;AAChC,QAAM,mBAA6B,CAAC;AAEpC,cAAY,QAAQ,CAAC,UAAU;AAC7B,UAAM,MAAM,MAAM,CAAC;AACnB,QAAI,aAAa,GAAG,GAAG;AACrB,kBAAY,KAAK,MAAM,KAAK,GAAG,IAAI,aAAa;AAAA,IAClD,OAAO;AACL,iBAAW,KAAK,MAAM,KAAK,GAAG,IAAI,aAAa;AAC/C,UAAI,IAAI,SAAS,QAAQ,GAAG;AAC1B,qBAAa,KAAK,MAAM,KAAK,GAAG,IAAI,aAAa;AAAA,MACnD;AACA,UAAI,QAAQ,QAAQ;AAClB,yBAAiB,KAAK,MAAM,KAAK,GAAG,IAAI,aAAa;AAAA,MACvD;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,aAAa,YAAY,KAAK,GAAG;AAAA,IACjC,YAAY,WAAW,KAAK,GAAG;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF,GA7B6B;AAiCtB,IAAM,oBAAoB,wBAAC,MAAY,YAAiB;AAC7D,QAAM,EAAE,gBAAgB,cAAc,IAAI,UAAU;AACpD,QAAM,EAAE,YAAY,QAAQ,IAAI;AAChC,QAAM,EAAE,UAAU,IAAI,cAAc,IAAI;AAGxC,QAAM,SAAS,OAAO;AAAA,IACpB;AAAA,MACE,WAAW;AAAA,MACX,MAAM,UAAU,IAAI,MAAM,KAAK;AAAA,MAC/B,WAAW;AAAA;AAAA,MACX,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,QAAQ,UAAU,IAAI,QAAQ,KAAK;AAAA,MACnC,MAAM;AAAA,MACN,aAAa,UAAU,IAAI,cAAc,GAAG,QAAQ,MAAM,EAAE,KAAK;AAAA,MACjE,cAAc,CAAC,GAAG,CAAC;AAAA,MACnB,gBAAgB,mBAAmB,UAAU,IAAI,kBAAkB,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT,GAtBiC;AAwBjC,IAAM,qBAAqB,wBAAC,yBAAkC;AAC5D,MAAI,CAAC,sBAAsB;AACzB,WAAO,CAAC,GAAG,CAAC;AAAA,EACd;AACA,QAAM,YAAY,qBAAqB,KAAK,EAAE,MAAM,KAAK,EAAE,IAAI,MAAM;AACrE,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,IAAI,UAAU,CAAC;AACjD,WAAO,CAAC,KAAK,GAAG;AAAA,EAClB;AACA,QAAM,QAAQ,MAAM,UAAU,CAAC,CAAC,IAAI,IAAI,UAAU,CAAC;AACnD,QAAM,SAAS,MAAM,UAAU,CAAC,CAAC,IAAI,IAAI,UAAU,CAAC;AACpD,SAAO,CAAC,OAAO,MAAM;AACvB,GAZ2B;",
|
||||
"names": []
|
||||
}
|
||||
+2716
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+126
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
lineBreakRegex
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/common/svgDrawCommon.ts
|
||||
import { sanitizeUrl } from "@braintree/sanitize-url";
|
||||
import { select } from "d3";
|
||||
var drawRect = /* @__PURE__ */ __name((element, rectData) => {
|
||||
const rectElement = element.append("rect");
|
||||
rectElement.attr("x", rectData.x);
|
||||
rectElement.attr("y", rectData.y);
|
||||
rectElement.attr("fill", rectData.fill);
|
||||
rectElement.attr("stroke", rectData.stroke);
|
||||
rectElement.attr("width", rectData.width);
|
||||
rectElement.attr("height", rectData.height);
|
||||
if (rectData.name) {
|
||||
rectElement.attr("name", rectData.name);
|
||||
}
|
||||
if (rectData.rx) {
|
||||
rectElement.attr("rx", rectData.rx);
|
||||
}
|
||||
if (rectData.ry) {
|
||||
rectElement.attr("ry", rectData.ry);
|
||||
}
|
||||
if (rectData.attrs !== void 0) {
|
||||
for (const attrKey in rectData.attrs) {
|
||||
rectElement.attr(attrKey, rectData.attrs[attrKey]);
|
||||
}
|
||||
}
|
||||
if (rectData.class) {
|
||||
rectElement.attr("class", rectData.class);
|
||||
}
|
||||
return rectElement;
|
||||
}, "drawRect");
|
||||
var drawBackgroundRect = /* @__PURE__ */ __name((element, bounds) => {
|
||||
const rectData = {
|
||||
x: bounds.startx,
|
||||
y: bounds.starty,
|
||||
width: bounds.stopx - bounds.startx,
|
||||
height: bounds.stopy - bounds.starty,
|
||||
fill: bounds.fill,
|
||||
stroke: bounds.stroke,
|
||||
class: "rect"
|
||||
};
|
||||
const rectElement = drawRect(element, rectData);
|
||||
rectElement.lower();
|
||||
}, "drawBackgroundRect");
|
||||
var drawText = /* @__PURE__ */ __name((element, textData) => {
|
||||
const nText = textData.text.replace(lineBreakRegex, " ");
|
||||
const textElem = element.append("text");
|
||||
textElem.attr("x", textData.x);
|
||||
textElem.attr("y", textData.y);
|
||||
textElem.attr("class", "legend");
|
||||
textElem.style("text-anchor", textData.anchor);
|
||||
if (textData.class) {
|
||||
textElem.attr("class", textData.class);
|
||||
}
|
||||
const tspan = textElem.append("tspan");
|
||||
tspan.attr("x", textData.x + textData.textMargin * 2);
|
||||
tspan.text(nText);
|
||||
return textElem;
|
||||
}, "drawText");
|
||||
var drawImage = /* @__PURE__ */ __name((elem, x, y, link) => {
|
||||
const imageElement = elem.append("image");
|
||||
imageElement.attr("x", x);
|
||||
imageElement.attr("y", y);
|
||||
const sanitizedLink = sanitizeUrl(link);
|
||||
imageElement.attr("xlink:href", sanitizedLink);
|
||||
}, "drawImage");
|
||||
var drawEmbeddedImage = /* @__PURE__ */ __name((element, x, y, link) => {
|
||||
const imageElement = element.append("use");
|
||||
imageElement.attr("x", x);
|
||||
imageElement.attr("y", y);
|
||||
const sanitizedLink = sanitizeUrl(link);
|
||||
imageElement.attr("xlink:href", `#${sanitizedLink}`);
|
||||
}, "drawEmbeddedImage");
|
||||
var getNoteRect = /* @__PURE__ */ __name(() => {
|
||||
const noteRectData = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fill: "#EDF2AE",
|
||||
stroke: "#666",
|
||||
anchor: "start",
|
||||
rx: 0,
|
||||
ry: 0
|
||||
};
|
||||
return noteRectData;
|
||||
}, "getNoteRect");
|
||||
var getTextObj = /* @__PURE__ */ __name(() => {
|
||||
const testObject = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
"text-anchor": "start",
|
||||
style: "#666",
|
||||
textMargin: 0,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
tspan: true
|
||||
};
|
||||
return testObject;
|
||||
}, "getTextObj");
|
||||
var createTooltip = /* @__PURE__ */ __name(() => {
|
||||
let tooltipElem = select(".mermaidTooltip");
|
||||
if (tooltipElem.empty()) {
|
||||
tooltipElem = select("body").append("div").attr("class", "mermaidTooltip").style("opacity", 0).style("position", "absolute").style("text-align", "center").style("max-width", "200px").style("padding", "2px").style("font-size", "12px").style("background", "#ffffde").style("border", "1px solid #333").style("border-radius", "2px").style("pointer-events", "none").style("z-index", "100");
|
||||
}
|
||||
return tooltipElem;
|
||||
}, "createTooltip");
|
||||
|
||||
export {
|
||||
drawRect,
|
||||
drawBackgroundRect,
|
||||
drawText,
|
||||
drawImage,
|
||||
drawEmbeddedImage,
|
||||
getNoteRect,
|
||||
getTextObj,
|
||||
createTooltip
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/common/svgDrawCommon.ts"],
|
||||
"sourcesContent": ["import { sanitizeUrl } from '@braintree/sanitize-url';\nimport { select } from 'd3';\nimport type { SVG, SVGGroup } from '../../diagram-api/types.js';\nimport { lineBreakRegex } from './common.js';\nimport type {\n Bound,\n D3ImageElement,\n D3RectElement,\n D3TSpanElement,\n D3TextElement,\n D3UseElement,\n RectData,\n TextData,\n TextObject,\n} from './commonTypes.js';\n\nexport const drawRect = (element: SVG | SVGGroup, rectData: RectData): D3RectElement => {\n const rectElement: D3RectElement = element.append('rect');\n rectElement.attr('x', rectData.x);\n rectElement.attr('y', rectData.y);\n rectElement.attr('fill', rectData.fill);\n rectElement.attr('stroke', rectData.stroke);\n rectElement.attr('width', rectData.width);\n rectElement.attr('height', rectData.height);\n if (rectData.name) {\n rectElement.attr('name', rectData.name);\n }\n if (rectData.rx) {\n rectElement.attr('rx', rectData.rx);\n }\n if (rectData.ry) {\n rectElement.attr('ry', rectData.ry);\n }\n\n if (rectData.attrs !== undefined) {\n for (const attrKey in rectData.attrs) {\n rectElement.attr(attrKey, rectData.attrs[attrKey]);\n }\n }\n\n if (rectData.class) {\n rectElement.attr('class', rectData.class);\n }\n\n return rectElement;\n};\n\n/**\n * Draws a background rectangle\n *\n * @param element - Diagram (reference for bounds)\n * @param bounds - Shape of the rectangle\n */\nexport const drawBackgroundRect = (element: SVG | SVGGroup, bounds: Bound): void => {\n const rectData: RectData = {\n x: bounds.startx,\n y: bounds.starty,\n width: bounds.stopx - bounds.startx,\n height: bounds.stopy - bounds.starty,\n fill: bounds.fill,\n stroke: bounds.stroke,\n class: 'rect',\n };\n const rectElement: D3RectElement = drawRect(element, rectData);\n rectElement.lower();\n};\n\nexport const drawText = (element: SVG | SVGGroup, textData: TextData): D3TextElement => {\n const nText: string = textData.text.replace(lineBreakRegex, ' ');\n\n const textElem: D3TextElement = element.append('text');\n textElem.attr('x', textData.x);\n textElem.attr('y', textData.y);\n textElem.attr('class', 'legend');\n\n textElem.style('text-anchor', textData.anchor);\n if (textData.class) {\n textElem.attr('class', textData.class);\n }\n\n const tspan: D3TSpanElement = textElem.append('tspan');\n tspan.attr('x', textData.x + textData.textMargin * 2);\n tspan.text(nText);\n\n return textElem;\n};\n\nexport const drawImage = (elem: SVG | SVGGroup, x: number, y: number, link: string): void => {\n const imageElement: D3ImageElement = elem.append('image');\n imageElement.attr('x', x);\n imageElement.attr('y', y);\n const sanitizedLink: string = sanitizeUrl(link);\n imageElement.attr('xlink:href', sanitizedLink);\n};\n\nexport const drawEmbeddedImage = (\n element: SVG | SVGGroup,\n x: number,\n y: number,\n link: string\n): void => {\n const imageElement: D3UseElement = element.append('use');\n imageElement.attr('x', x);\n imageElement.attr('y', y);\n const sanitizedLink: string = sanitizeUrl(link);\n imageElement.attr('xlink:href', `#${sanitizedLink}`);\n};\n\nexport const getNoteRect = (): RectData => {\n const noteRectData: RectData = {\n x: 0,\n y: 0,\n width: 100,\n height: 100,\n fill: '#EDF2AE',\n stroke: '#666',\n anchor: 'start',\n rx: 0,\n ry: 0,\n };\n return noteRectData;\n};\n\nexport const getTextObj = (): TextObject => {\n const testObject: TextObject = {\n x: 0,\n y: 0,\n width: 100,\n height: 100,\n 'text-anchor': 'start',\n style: '#666',\n textMargin: 0,\n rx: 0,\n ry: 0,\n tspan: true,\n };\n return testObject;\n};\n\nexport const createTooltip = () => {\n let tooltipElem = select<HTMLDivElement, unknown>('.mermaidTooltip');\n if (tooltipElem.empty()) {\n tooltipElem = select('body')\n .append('div')\n .attr('class', 'mermaidTooltip')\n .style('opacity', 0)\n .style('position', 'absolute')\n .style('text-align', 'center')\n .style('max-width', '200px')\n .style('padding', '2px')\n .style('font-size', '12px')\n .style('background', '#ffffde')\n .style('border', '1px solid #333')\n .style('border-radius', '2px')\n .style('pointer-events', 'none')\n .style('z-index', '100');\n }\n return tooltipElem;\n};\n"],
|
||||
"mappings": ";;;;;;;;AAAA,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AAehB,IAAM,WAAW,wBAAC,SAAyB,aAAsC;AACtF,QAAM,cAA6B,QAAQ,OAAO,MAAM;AACxD,cAAY,KAAK,KAAK,SAAS,CAAC;AAChC,cAAY,KAAK,KAAK,SAAS,CAAC;AAChC,cAAY,KAAK,QAAQ,SAAS,IAAI;AACtC,cAAY,KAAK,UAAU,SAAS,MAAM;AAC1C,cAAY,KAAK,SAAS,SAAS,KAAK;AACxC,cAAY,KAAK,UAAU,SAAS,MAAM;AAC1C,MAAI,SAAS,MAAM;AACjB,gBAAY,KAAK,QAAQ,SAAS,IAAI;AAAA,EACxC;AACA,MAAI,SAAS,IAAI;AACf,gBAAY,KAAK,MAAM,SAAS,EAAE;AAAA,EACpC;AACA,MAAI,SAAS,IAAI;AACf,gBAAY,KAAK,MAAM,SAAS,EAAE;AAAA,EACpC;AAEA,MAAI,SAAS,UAAU,QAAW;AAChC,eAAW,WAAW,SAAS,OAAO;AACpC,kBAAY,KAAK,SAAS,SAAS,MAAM,OAAO,CAAC;AAAA,IACnD;AAAA,EACF;AAEA,MAAI,SAAS,OAAO;AAClB,gBAAY,KAAK,SAAS,SAAS,KAAK;AAAA,EAC1C;AAEA,SAAO;AACT,GA7BwB;AAqCjB,IAAM,qBAAqB,wBAAC,SAAyB,WAAwB;AAClF,QAAM,WAAqB;AAAA,IACzB,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,OAAO,OAAO,QAAQ,OAAO;AAAA,IAC7B,QAAQ,OAAO,QAAQ,OAAO;AAAA,IAC9B,MAAM,OAAO;AAAA,IACb,QAAQ,OAAO;AAAA,IACf,OAAO;AAAA,EACT;AACA,QAAM,cAA6B,SAAS,SAAS,QAAQ;AAC7D,cAAY,MAAM;AACpB,GAZkC;AAc3B,IAAM,WAAW,wBAAC,SAAyB,aAAsC;AACtF,QAAM,QAAgB,SAAS,KAAK,QAAQ,gBAAgB,GAAG;AAE/D,QAAM,WAA0B,QAAQ,OAAO,MAAM;AACrD,WAAS,KAAK,KAAK,SAAS,CAAC;AAC7B,WAAS,KAAK,KAAK,SAAS,CAAC;AAC7B,WAAS,KAAK,SAAS,QAAQ;AAE/B,WAAS,MAAM,eAAe,SAAS,MAAM;AAC7C,MAAI,SAAS,OAAO;AAClB,aAAS,KAAK,SAAS,SAAS,KAAK;AAAA,EACvC;AAEA,QAAM,QAAwB,SAAS,OAAO,OAAO;AACrD,QAAM,KAAK,KAAK,SAAS,IAAI,SAAS,aAAa,CAAC;AACpD,QAAM,KAAK,KAAK;AAEhB,SAAO;AACT,GAlBwB;AAoBjB,IAAM,YAAY,wBAAC,MAAsB,GAAW,GAAW,SAAuB;AAC3F,QAAM,eAA+B,KAAK,OAAO,OAAO;AACxD,eAAa,KAAK,KAAK,CAAC;AACxB,eAAa,KAAK,KAAK,CAAC;AACxB,QAAM,gBAAwB,YAAY,IAAI;AAC9C,eAAa,KAAK,cAAc,aAAa;AAC/C,GANyB;AAQlB,IAAM,oBAAoB,wBAC/B,SACA,GACA,GACA,SACS;AACT,QAAM,eAA6B,QAAQ,OAAO,KAAK;AACvD,eAAa,KAAK,KAAK,CAAC;AACxB,eAAa,KAAK,KAAK,CAAC;AACxB,QAAM,gBAAwB,YAAY,IAAI;AAC9C,eAAa,KAAK,cAAc,IAAI,aAAa,EAAE;AACrD,GAXiC;AAa1B,IAAM,cAAc,6BAAgB;AACzC,QAAM,eAAyB;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG;AAAA,IACH,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AACA,SAAO;AACT,GAb2B;AAepB,IAAM,aAAa,6BAAkB;AAC1C,QAAM,aAAyB;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG;AAAA,IACH,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO;AAAA,EACT;AACA,SAAO;AACT,GAd0B;AAgBnB,IAAM,gBAAgB,6BAAM;AACjC,MAAI,cAAc,OAAgC,iBAAiB;AACnE,MAAI,YAAY,MAAM,GAAG;AACvB,kBAAc,OAAO,MAAM,EACxB,OAAO,KAAK,EACZ,KAAK,SAAS,gBAAgB,EAC9B,MAAM,WAAW,CAAC,EAClB,MAAM,YAAY,UAAU,EAC5B,MAAM,cAAc,QAAQ,EAC5B,MAAM,aAAa,OAAO,EAC1B,MAAM,WAAW,KAAK,EACtB,MAAM,aAAa,MAAM,EACzB,MAAM,cAAc,SAAS,EAC7B,MAAM,UAAU,gBAAgB,EAChC,MAAM,iBAAiB,KAAK,EAC5B,MAAM,kBAAkB,MAAM,EAC9B,MAAM,WAAW,KAAK;AAAA,EAC3B;AACA,SAAO;AACT,GAnB6B;",
|
||||
"names": []
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
parseFontSize
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
defaultConfig_default,
|
||||
getConfig2 as getConfig
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/utils/subGraphTitleMargins.ts
|
||||
var getSubGraphTitleMargins = /* @__PURE__ */ __name(({
|
||||
flowchart
|
||||
}) => {
|
||||
const subGraphTitleTopMargin = flowchart?.subGraphTitleMargin?.top ?? 0;
|
||||
const subGraphTitleBottomMargin = flowchart?.subGraphTitleMargin?.bottom ?? 0;
|
||||
const subGraphTitleTotalMargin = subGraphTitleTopMargin + subGraphTitleBottomMargin;
|
||||
return {
|
||||
subGraphTitleTopMargin,
|
||||
subGraphTitleBottomMargin,
|
||||
subGraphTitleTotalMargin
|
||||
};
|
||||
}, "getSubGraphTitleMargins");
|
||||
|
||||
// src/rendering-util/rendering-elements/shapes/labelImageUtils.ts
|
||||
async function configureLabelImages(container, labelText) {
|
||||
const images = container.getElementsByTagName("img");
|
||||
if (!images || images.length === 0) {
|
||||
return;
|
||||
}
|
||||
const noImgText = labelText.replace(/<img[^>]*>/g, "").trim() === "";
|
||||
await Promise.all(
|
||||
[...images].map(
|
||||
(img) => new Promise((res) => {
|
||||
function setupImage() {
|
||||
img.style.display = "flex";
|
||||
img.style.flexDirection = "column";
|
||||
if (noImgText) {
|
||||
const bodyFontSize = getConfig().fontSize ? getConfig().fontSize : window.getComputedStyle(document.body).fontSize;
|
||||
const enlargingFactor = 5;
|
||||
const [parsedBodyFontSize = defaultConfig_default.fontSize] = parseFontSize(bodyFontSize);
|
||||
const width = parsedBodyFontSize * enlargingFactor + "px";
|
||||
img.style.minWidth = width;
|
||||
img.style.maxWidth = width;
|
||||
} else {
|
||||
img.style.width = "100%";
|
||||
}
|
||||
res(img);
|
||||
}
|
||||
__name(setupImage, "setupImage");
|
||||
setTimeout(() => {
|
||||
if (img.complete) {
|
||||
setupImage();
|
||||
}
|
||||
});
|
||||
img.addEventListener("error", setupImage);
|
||||
img.addEventListener("load", setupImage);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
__name(configureLabelImages, "configureLabelImages");
|
||||
|
||||
export {
|
||||
configureLabelImages,
|
||||
getSubGraphTitleMargins
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/utils/subGraphTitleMargins.ts", "../../../src/rendering-util/rendering-elements/shapes/labelImageUtils.ts"],
|
||||
"sourcesContent": ["import type { FlowchartDiagramConfig } from '../config.type.js';\n\nexport const getSubGraphTitleMargins = ({\n flowchart,\n}: {\n flowchart: FlowchartDiagramConfig;\n}): {\n subGraphTitleTopMargin: number;\n subGraphTitleBottomMargin: number;\n subGraphTitleTotalMargin: number;\n} => {\n const subGraphTitleTopMargin = flowchart?.subGraphTitleMargin?.top ?? 0;\n const subGraphTitleBottomMargin = flowchart?.subGraphTitleMargin?.bottom ?? 0;\n const subGraphTitleTotalMargin = subGraphTitleTopMargin + subGraphTitleBottomMargin;\n\n return {\n subGraphTitleTopMargin,\n subGraphTitleBottomMargin,\n subGraphTitleTotalMargin,\n };\n};\n", "import { getConfig } from '../../../diagram-api/diagramAPI.js';\nimport defaultConfig from '../../../defaultConfig.js';\nimport { parseFontSize } from '../../../utils.js';\n\n/**\n * Waits for all images in a container to load and applies appropriate styling.\n * This ensures accurate bounding box measurements after images are loaded.\n *\n * @param container - The HTML element containing img tags\n * @param labelText - The original label text to check if there's text besides images\n * @returns Promise that resolves when all images are loaded and styled\n */\nexport async function configureLabelImages(\n container: HTMLElement,\n labelText: string\n): Promise<void> {\n const images = container.getElementsByTagName('img');\n if (!images || images.length === 0) {\n return;\n }\n\n const noImgText = labelText.replace(/<img[^>]*>/g, '').trim() === '';\n\n await Promise.all(\n [...images].map(\n (img) =>\n new Promise((res) => {\n function setupImage() {\n img.style.display = 'flex';\n img.style.flexDirection = 'column';\n\n if (noImgText) {\n // default size if no text\n const bodyFontSize = getConfig().fontSize\n ? getConfig().fontSize\n : window.getComputedStyle(document.body).fontSize;\n const enlargingFactor = 5;\n const [parsedBodyFontSize = defaultConfig.fontSize] = parseFontSize(bodyFontSize);\n const width = parsedBodyFontSize * enlargingFactor + 'px';\n img.style.minWidth = width;\n img.style.maxWidth = width;\n } else {\n img.style.width = '100%';\n }\n res(img);\n }\n setTimeout(() => {\n if (img.complete) {\n setupImage();\n }\n });\n img.addEventListener('error', setupImage);\n img.addEventListener('load', setupImage);\n })\n )\n );\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;AAEO,IAAM,0BAA0B,wBAAC;AAAA,EACtC;AACF,MAMK;AACH,QAAM,yBAAyB,WAAW,qBAAqB,OAAO;AACtE,QAAM,4BAA4B,WAAW,qBAAqB,UAAU;AAC5E,QAAM,2BAA2B,yBAAyB;AAE1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF,GAlBuC;;;ACUvC,eAAsB,qBACpB,WACA,WACe;AACf,QAAM,SAAS,UAAU,qBAAqB,KAAK;AACnD,MAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC;AAAA,EACF;AAEA,QAAM,YAAY,UAAU,QAAQ,eAAe,EAAE,EAAE,KAAK,MAAM;AAElE,QAAM,QAAQ;AAAA,IACZ,CAAC,GAAG,MAAM,EAAE;AAAA,MACV,CAAC,QACC,IAAI,QAAQ,CAAC,QAAQ;AACnB,iBAAS,aAAa;AACpB,cAAI,MAAM,UAAU;AACpB,cAAI,MAAM,gBAAgB;AAE1B,cAAI,WAAW;AAEb,kBAAM,eAAe,UAAU,EAAE,WAC7B,UAAU,EAAE,WACZ,OAAO,iBAAiB,SAAS,IAAI,EAAE;AAC3C,kBAAM,kBAAkB;AACxB,kBAAM,CAAC,qBAAqB,sBAAc,QAAQ,IAAI,cAAc,YAAY;AAChF,kBAAM,QAAQ,qBAAqB,kBAAkB;AACrD,gBAAI,MAAM,WAAW;AACrB,gBAAI,MAAM,WAAW;AAAA,UACvB,OAAO;AACL,gBAAI,MAAM,QAAQ;AAAA,UACpB;AACA,cAAI,GAAG;AAAA,QACT;AAlBS;AAmBT,mBAAW,MAAM;AACf,cAAI,IAAI,UAAU;AAChB,uBAAW;AAAA,UACb;AAAA,QACF,CAAC;AACD,YAAI,iBAAiB,SAAS,UAAU;AACxC,YAAI,iBAAiB,QAAQ,UAAU;AAAA,MACzC,CAAC;AAAA,IACL;AAAA,EACF;AACF;AA5CsB;",
|
||||
"names": []
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
ClassDB,
|
||||
classDiagram_default,
|
||||
classRenderer_v3_unified_default,
|
||||
styles_default
|
||||
} from "./chunk-4TB4RGXK.mjs";
|
||||
import "./chunk-FMBD7UC4.mjs";
|
||||
import "./chunk-YZCP3GAM.mjs";
|
||||
import "./chunk-55IACEB6.mjs";
|
||||
import "./chunk-EDXVE4YY.mjs";
|
||||
import "./chunk-336JU56O.mjs";
|
||||
import "./chunk-ENJZ2VHE.mjs";
|
||||
import "./chunk-BSJP7CBP.mjs";
|
||||
import "./chunk-5FUZZQ4R.mjs";
|
||||
import "./chunk-ZZ45TVLE.mjs";
|
||||
import "./chunk-X2U36JSP.mjs";
|
||||
import "./chunk-U2HBQHQK.mjs";
|
||||
import "./chunk-5PVQY5BW.mjs";
|
||||
import "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/class/classDiagram.ts
|
||||
var diagram = {
|
||||
parser: classDiagram_default,
|
||||
get db() {
|
||||
return new ClassDB();
|
||||
},
|
||||
renderer: classRenderer_v3_unified_default,
|
||||
styles: styles_default,
|
||||
init: /* @__PURE__ */ __name((cnf) => {
|
||||
if (!cnf.class) {
|
||||
cnf.class = {};
|
||||
}
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
}, "init")
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/class/classDiagram.ts"],
|
||||
"sourcesContent": ["import type { DiagramDefinition } from '../../diagram-api/types.js';\n// @ts-ignore: JISON doesn't support types\nimport parser from './parser/classDiagram.jison';\nimport { ClassDB } from './classDb.js';\nimport styles from './styles.js';\nimport renderer from './classRenderer-v3-unified.js';\n\nexport const diagram: DiagramDefinition = {\n parser,\n get db() {\n return new ClassDB();\n },\n renderer,\n styles,\n init: (cnf) => {\n if (!cnf.class) {\n cnf.class = {};\n }\n cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;\n },\n};\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAOO,IAAM,UAA6B;AAAA,EACxC;AAAA,EACA,IAAI,KAAK;AACP,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM,wBAAC,QAAQ;AACb,QAAI,CAAC,IAAI,OAAO;AACd,UAAI,QAAQ,CAAC;AAAA,IACf;AACA,QAAI,MAAM,sBAAsB,IAAI;AAAA,EACtC,GALM;AAMR;",
|
||||
"names": []
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
ClassDB,
|
||||
classDiagram_default,
|
||||
classRenderer_v3_unified_default,
|
||||
styles_default
|
||||
} from "./chunk-4TB4RGXK.mjs";
|
||||
import "./chunk-FMBD7UC4.mjs";
|
||||
import "./chunk-YZCP3GAM.mjs";
|
||||
import "./chunk-55IACEB6.mjs";
|
||||
import "./chunk-EDXVE4YY.mjs";
|
||||
import "./chunk-336JU56O.mjs";
|
||||
import "./chunk-ENJZ2VHE.mjs";
|
||||
import "./chunk-BSJP7CBP.mjs";
|
||||
import "./chunk-5FUZZQ4R.mjs";
|
||||
import "./chunk-ZZ45TVLE.mjs";
|
||||
import "./chunk-X2U36JSP.mjs";
|
||||
import "./chunk-U2HBQHQK.mjs";
|
||||
import "./chunk-5PVQY5BW.mjs";
|
||||
import "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/class/classDiagram-v2.ts
|
||||
var diagram = {
|
||||
parser: classDiagram_default,
|
||||
get db() {
|
||||
return new ClassDB();
|
||||
},
|
||||
renderer: classRenderer_v3_unified_default,
|
||||
styles: styles_default,
|
||||
init: /* @__PURE__ */ __name((cnf) => {
|
||||
if (!cnf.class) {
|
||||
cnf.class = {};
|
||||
}
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
}, "init")
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/class/classDiagram-v2.ts"],
|
||||
"sourcesContent": ["import type { DiagramDefinition } from '../../diagram-api/types.js';\n// @ts-ignore: JISON doesn't support types\nimport parser from './parser/classDiagram.jison';\nimport { ClassDB } from './classDb.js';\nimport styles from './styles.js';\nimport renderer from './classRenderer-v3-unified.js';\n\nexport const diagram: DiagramDefinition = {\n parser,\n get db() {\n return new ClassDB();\n },\n renderer,\n styles,\n init: (cnf) => {\n if (!cnf.class) {\n cnf.class = {};\n }\n cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;\n },\n};\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAOO,IAAM,UAA6B;AAAA,EACxC;AAAA,EACA,IAAI,KAAK;AACP,WAAO,IAAI,QAAQ;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM,wBAAC,QAAQ;AACb,QAAI,CAAC,IAAI,OAAO;AACd,UAAI,QAAQ,CAAC;AAAA,IACf;AACA,QAAI,MAAM,sBAAsB,IAAI;AAAA,EACtC,GALM;AAMR;",
|
||||
"names": []
|
||||
}
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/layout-algorithms/cose-bilkent/cytoscape-setup.ts
|
||||
import cytoscape from "cytoscape";
|
||||
import coseBilkent from "cytoscape-cose-bilkent";
|
||||
import { select } from "d3";
|
||||
cytoscape.use(coseBilkent);
|
||||
function addNodes(nodes, cy) {
|
||||
nodes.forEach((node) => {
|
||||
const nodeData = {
|
||||
id: node.id,
|
||||
labelText: node.label,
|
||||
height: node.height,
|
||||
width: node.width,
|
||||
padding: node.padding ?? 0
|
||||
};
|
||||
Object.keys(node).forEach((key) => {
|
||||
if (!["id", "label", "height", "width", "padding", "x", "y"].includes(key)) {
|
||||
nodeData[key] = node[key];
|
||||
}
|
||||
});
|
||||
cy.add({
|
||||
group: "nodes",
|
||||
data: nodeData,
|
||||
position: {
|
||||
x: node.x ?? 0,
|
||||
y: node.y ?? 0
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
__name(addNodes, "addNodes");
|
||||
function addEdges(edges, cy) {
|
||||
edges.forEach((edge) => {
|
||||
const edgeData = {
|
||||
id: edge.id,
|
||||
source: edge.start,
|
||||
target: edge.end
|
||||
};
|
||||
Object.keys(edge).forEach((key) => {
|
||||
if (!["id", "start", "end"].includes(key)) {
|
||||
edgeData[key] = edge[key];
|
||||
}
|
||||
});
|
||||
cy.add({
|
||||
group: "edges",
|
||||
data: edgeData
|
||||
});
|
||||
});
|
||||
}
|
||||
__name(addEdges, "addEdges");
|
||||
function createCytoscapeInstance(data) {
|
||||
return new Promise((resolve) => {
|
||||
const renderEl = select("body").append("div").attr("id", "cy").attr("style", "display:none");
|
||||
const cy = cytoscape({
|
||||
container: document.getElementById("cy"),
|
||||
// container to render in
|
||||
style: [
|
||||
{
|
||||
selector: "edge",
|
||||
style: {
|
||||
"curve-style": "bezier"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
renderEl.remove();
|
||||
addNodes(data.nodes, cy);
|
||||
addEdges(data.edges, cy);
|
||||
cy.nodes().forEach(function(n) {
|
||||
n.layoutDimensions = () => {
|
||||
const nodeData = n.data();
|
||||
return { w: nodeData.width, h: nodeData.height };
|
||||
};
|
||||
});
|
||||
const layoutConfig = {
|
||||
name: "cose-bilkent",
|
||||
// @ts-ignore Types for cose-bilkent are not correct?
|
||||
quality: "proof",
|
||||
styleEnabled: false,
|
||||
animate: false
|
||||
};
|
||||
cy.layout(layoutConfig).run();
|
||||
cy.ready((e) => {
|
||||
log.info("Cytoscape ready", e);
|
||||
resolve(cy);
|
||||
});
|
||||
});
|
||||
}
|
||||
__name(createCytoscapeInstance, "createCytoscapeInstance");
|
||||
function extractPositionedNodes(cy) {
|
||||
return cy.nodes().map((node) => {
|
||||
const data = node.data();
|
||||
const position = node.position();
|
||||
const positionedNode = {
|
||||
id: data.id,
|
||||
x: position.x,
|
||||
y: position.y
|
||||
};
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (key !== "id") {
|
||||
positionedNode[key] = data[key];
|
||||
}
|
||||
});
|
||||
return positionedNode;
|
||||
});
|
||||
}
|
||||
__name(extractPositionedNodes, "extractPositionedNodes");
|
||||
function extractPositionedEdges(cy) {
|
||||
return cy.edges().map((edge) => {
|
||||
const data = edge.data();
|
||||
const rscratch = edge._private.rscratch;
|
||||
const positionedEdge = {
|
||||
id: data.id,
|
||||
source: data.source,
|
||||
target: data.target,
|
||||
startX: rscratch.startX,
|
||||
startY: rscratch.startY,
|
||||
midX: rscratch.midX,
|
||||
midY: rscratch.midY,
|
||||
endX: rscratch.endX,
|
||||
endY: rscratch.endY
|
||||
};
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (!["id", "source", "target"].includes(key)) {
|
||||
positionedEdge[key] = data[key];
|
||||
}
|
||||
});
|
||||
return positionedEdge;
|
||||
});
|
||||
}
|
||||
__name(extractPositionedEdges, "extractPositionedEdges");
|
||||
|
||||
// src/rendering-util/layout-algorithms/cose-bilkent/layout.ts
|
||||
async function executeCoseBilkentLayout(data, _config) {
|
||||
log.debug("Starting cose-bilkent layout algorithm");
|
||||
try {
|
||||
validateLayoutData(data);
|
||||
const cy = await createCytoscapeInstance(data);
|
||||
const positionedNodes = extractPositionedNodes(cy);
|
||||
const positionedEdges = extractPositionedEdges(cy);
|
||||
log.debug(`Layout completed: ${positionedNodes.length} nodes, ${positionedEdges.length} edges`);
|
||||
return {
|
||||
nodes: positionedNodes,
|
||||
edges: positionedEdges
|
||||
};
|
||||
} catch (error) {
|
||||
log.error("Error in cose-bilkent layout algorithm:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
__name(executeCoseBilkentLayout, "executeCoseBilkentLayout");
|
||||
function validateLayoutData(data) {
|
||||
if (!data) {
|
||||
throw new Error("Layout data is required");
|
||||
}
|
||||
if (!data.config) {
|
||||
throw new Error("Configuration is required in layout data");
|
||||
}
|
||||
if (!data.rootNode) {
|
||||
throw new Error("Root node is required");
|
||||
}
|
||||
if (!data.nodes || !Array.isArray(data.nodes)) {
|
||||
throw new Error("No nodes found in layout data");
|
||||
}
|
||||
if (!Array.isArray(data.edges)) {
|
||||
throw new Error("Edges array is required in layout data");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
__name(validateLayoutData, "validateLayoutData");
|
||||
|
||||
// src/rendering-util/layout-algorithms/cose-bilkent/render.ts
|
||||
var render = /* @__PURE__ */ __name(async (data4Layout, svg, {
|
||||
insertCluster,
|
||||
insertEdge,
|
||||
insertEdgeLabel,
|
||||
insertMarkers,
|
||||
insertNode,
|
||||
log: log2,
|
||||
positionEdgeLabel
|
||||
}, { algorithm: _algorithm }) => {
|
||||
const nodeDb = {};
|
||||
const clusterDb = {};
|
||||
const element = svg.select("g");
|
||||
insertMarkers(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);
|
||||
const subGraphsEl = element.insert("g").attr("class", "subgraphs");
|
||||
const edgePaths = element.insert("g").attr("class", "edgePaths");
|
||||
const edgeLabels = element.insert("g").attr("class", "edgeLabels");
|
||||
const nodes = element.insert("g").attr("class", "nodes");
|
||||
log2.debug("Inserting nodes into DOM for dimension calculation");
|
||||
await Promise.all(
|
||||
data4Layout.nodes.map(async (node) => {
|
||||
if (node.isGroup) {
|
||||
const clusterNode = { ...node };
|
||||
clusterDb[node.id] = clusterNode;
|
||||
nodeDb[node.id] = clusterNode;
|
||||
await insertCluster(subGraphsEl, node);
|
||||
} else {
|
||||
const nodeWithPosition = { ...node };
|
||||
nodeDb[node.id] = nodeWithPosition;
|
||||
const nodeEl = await insertNode(nodes, node, {
|
||||
config: data4Layout.config,
|
||||
dir: data4Layout.direction || "TB"
|
||||
});
|
||||
const boundingBox = nodeEl.node().getBBox();
|
||||
nodeWithPosition.width = boundingBox.width;
|
||||
nodeWithPosition.height = boundingBox.height;
|
||||
nodeWithPosition.domId = nodeEl;
|
||||
log2.debug(`Node ${node.id} dimensions: ${boundingBox.width}x${boundingBox.height}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
log2.debug("Running cose-bilkent layout algorithm");
|
||||
const updatedLayoutData = {
|
||||
...data4Layout,
|
||||
nodes: data4Layout.nodes.map((node) => {
|
||||
const nodeWithDimensions = nodeDb[node.id];
|
||||
return {
|
||||
...node,
|
||||
width: nodeWithDimensions.width,
|
||||
height: nodeWithDimensions.height
|
||||
};
|
||||
})
|
||||
};
|
||||
const layoutResult = await executeCoseBilkentLayout(updatedLayoutData, data4Layout.config);
|
||||
log2.debug("Positioning nodes based on layout results");
|
||||
layoutResult.nodes.forEach((positionedNode) => {
|
||||
const node = nodeDb[positionedNode.id];
|
||||
if (node?.domId) {
|
||||
node.domId.attr(
|
||||
"transform",
|
||||
`translate(${positionedNode.x}, ${positionedNode.y})`
|
||||
);
|
||||
node.x = positionedNode.x;
|
||||
node.y = positionedNode.y;
|
||||
log2.debug(`Positioned node ${node.id} at center (${positionedNode.x}, ${positionedNode.y})`);
|
||||
}
|
||||
});
|
||||
layoutResult.edges.forEach((positionedEdge) => {
|
||||
const edge = data4Layout.edges.find((e) => e.id === positionedEdge.id);
|
||||
if (edge) {
|
||||
edge.points = [
|
||||
{ x: positionedEdge.startX, y: positionedEdge.startY },
|
||||
{ x: positionedEdge.midX, y: positionedEdge.midY },
|
||||
{ x: positionedEdge.endX, y: positionedEdge.endY }
|
||||
];
|
||||
}
|
||||
});
|
||||
log2.debug("Inserting and positioning edges");
|
||||
await Promise.all(
|
||||
data4Layout.edges.map(async (edge) => {
|
||||
const _edgeLabel = await insertEdgeLabel(edgeLabels, edge);
|
||||
const startNode = nodeDb[edge.start ?? ""];
|
||||
const endNode = nodeDb[edge.end ?? ""];
|
||||
if (startNode && endNode) {
|
||||
const positionedEdge = layoutResult.edges.find((e) => e.id === edge.id);
|
||||
if (positionedEdge) {
|
||||
log2.debug("APA01 positionedEdge", positionedEdge);
|
||||
const edgeWithPath = { ...edge };
|
||||
const paths = insertEdge(
|
||||
edgePaths,
|
||||
edgeWithPath,
|
||||
clusterDb,
|
||||
data4Layout.type,
|
||||
startNode,
|
||||
endNode,
|
||||
data4Layout.diagramId
|
||||
);
|
||||
positionEdgeLabel(edgeWithPath, paths);
|
||||
} else {
|
||||
const edgeWithPath = {
|
||||
...edge,
|
||||
points: [
|
||||
{ x: startNode.x || 0, y: startNode.y || 0 },
|
||||
{ x: endNode.x || 0, y: endNode.y || 0 }
|
||||
]
|
||||
};
|
||||
const paths = insertEdge(
|
||||
edgePaths,
|
||||
edgeWithPath,
|
||||
clusterDb,
|
||||
data4Layout.type,
|
||||
startNode,
|
||||
endNode,
|
||||
data4Layout.diagramId
|
||||
);
|
||||
positionEdgeLabel(edgeWithPath, paths);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
log2.debug("Cose-bilkent rendering completed");
|
||||
}, "render");
|
||||
|
||||
// src/rendering-util/layout-algorithms/cose-bilkent/index.ts
|
||||
var render2 = render;
|
||||
export {
|
||||
render2 as render
|
||||
};
|
||||
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+687
@@ -0,0 +1,687 @@
|
||||
import {
|
||||
clear as clear2,
|
||||
insertEdge,
|
||||
insertEdgeLabel,
|
||||
markers_default,
|
||||
positionEdgeLabel
|
||||
} from "./chunk-ENJZ2VHE.mjs";
|
||||
import "./chunk-BSJP7CBP.mjs";
|
||||
import {
|
||||
clear,
|
||||
clear2 as clear3,
|
||||
insertCluster,
|
||||
insertNode,
|
||||
positionNode,
|
||||
setNodeElem,
|
||||
updateNodeBounds
|
||||
} from "./chunk-5FUZZQ4R.mjs";
|
||||
import {
|
||||
getSubGraphTitleMargins
|
||||
} from "./chunk-ZZ45TVLE.mjs";
|
||||
import "./chunk-X2U36JSP.mjs";
|
||||
import "./chunk-U2HBQHQK.mjs";
|
||||
import "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
getConfig2 as getConfig
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/rendering-util/layout-algorithms/dagre/index.js
|
||||
import { layout as dagreLayout } from "dagre-d3-es/src/dagre/index.js";
|
||||
import * as graphlibJson2 from "dagre-d3-es/src/graphlib/json.js";
|
||||
import * as graphlib2 from "dagre-d3-es/src/graphlib/index.js";
|
||||
|
||||
// src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
|
||||
import * as graphlib from "dagre-d3-es/src/graphlib/index.js";
|
||||
import * as graphlibJson from "dagre-d3-es/src/graphlib/json.js";
|
||||
var clusterDb = /* @__PURE__ */ new Map();
|
||||
var descendants = /* @__PURE__ */ new Map();
|
||||
var parents = /* @__PURE__ */ new Map();
|
||||
var clear4 = /* @__PURE__ */ __name(() => {
|
||||
descendants.clear();
|
||||
parents.clear();
|
||||
clusterDb.clear();
|
||||
}, "clear");
|
||||
var isDescendant = /* @__PURE__ */ __name((id, ancestorId) => {
|
||||
const ancestorDescendants = descendants.get(ancestorId) || [];
|
||||
log.trace("In isDescendant", ancestorId, " ", id, " = ", ancestorDescendants.includes(id));
|
||||
return ancestorDescendants.includes(id);
|
||||
}, "isDescendant");
|
||||
var edgeInCluster = /* @__PURE__ */ __name((edge, clusterId) => {
|
||||
const clusterDescendants = descendants.get(clusterId) || [];
|
||||
log.info("Descendants of ", clusterId, " is ", clusterDescendants);
|
||||
log.info("Edge is ", edge);
|
||||
if (edge.v === clusterId || edge.w === clusterId) {
|
||||
return false;
|
||||
}
|
||||
if (!clusterDescendants) {
|
||||
log.debug("Tilt, ", clusterId, ",not in descendants");
|
||||
return false;
|
||||
}
|
||||
return clusterDescendants.includes(edge.v) || isDescendant(edge.v, clusterId) || isDescendant(edge.w, clusterId) || clusterDescendants.includes(edge.w);
|
||||
}, "edgeInCluster");
|
||||
var copy = /* @__PURE__ */ __name((clusterId, graph, newGraph, rootId) => {
|
||||
log.warn(
|
||||
"Copying children of ",
|
||||
clusterId,
|
||||
"root",
|
||||
rootId,
|
||||
"data",
|
||||
graph.node(clusterId),
|
||||
rootId
|
||||
);
|
||||
const nodes = graph.children(clusterId) || [];
|
||||
if (clusterId !== rootId) {
|
||||
nodes.push(clusterId);
|
||||
}
|
||||
log.warn("Copying (nodes) clusterId", clusterId, "nodes", nodes);
|
||||
nodes.forEach((node) => {
|
||||
if (graph.children(node).length > 0) {
|
||||
copy(node, graph, newGraph, rootId);
|
||||
} else {
|
||||
const data = graph.node(node);
|
||||
log.info("cp ", node, " to ", rootId, " with parent ", clusterId);
|
||||
newGraph.setNode(node, data);
|
||||
if (rootId !== graph.parent(node)) {
|
||||
log.warn("Setting parent", node, graph.parent(node));
|
||||
newGraph.setParent(node, graph.parent(node));
|
||||
}
|
||||
if (clusterId !== rootId && node !== clusterId) {
|
||||
log.debug("Setting parent", node, clusterId);
|
||||
newGraph.setParent(node, clusterId);
|
||||
} else {
|
||||
log.info("In copy ", clusterId, "root", rootId, "data", graph.node(clusterId), rootId);
|
||||
log.debug(
|
||||
"Not Setting parent for node=",
|
||||
node,
|
||||
"cluster!==rootId",
|
||||
clusterId !== rootId,
|
||||
"node!==clusterId",
|
||||
node !== clusterId
|
||||
);
|
||||
}
|
||||
const edges = graph.edges(node);
|
||||
log.debug("Copying Edges", edges);
|
||||
edges.forEach((edge) => {
|
||||
log.info("Edge", edge);
|
||||
const data2 = graph.edge(edge.v, edge.w, edge.name);
|
||||
log.info("Edge data", data2, rootId);
|
||||
try {
|
||||
if (edgeInCluster(edge, rootId)) {
|
||||
log.info("Copying as ", edge.v, edge.w, data2, edge.name);
|
||||
newGraph.setEdge(edge.v, edge.w, data2, edge.name);
|
||||
log.info("newGraph edges ", newGraph.edges(), newGraph.edge(newGraph.edges()[0]));
|
||||
} else {
|
||||
log.info(
|
||||
"Skipping copy of edge ",
|
||||
edge.v,
|
||||
"-->",
|
||||
edge.w,
|
||||
" rootId: ",
|
||||
rootId,
|
||||
" clusterId:",
|
||||
clusterId
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
log.debug("Removing node", node);
|
||||
graph.removeNode(node);
|
||||
});
|
||||
}, "copy");
|
||||
var extractDescendants = /* @__PURE__ */ __name((id, graph) => {
|
||||
const children = graph.children(id);
|
||||
let res = [...children];
|
||||
for (const child of children) {
|
||||
parents.set(child, id);
|
||||
res = [...res, ...extractDescendants(child, graph)];
|
||||
}
|
||||
return res;
|
||||
}, "extractDescendants");
|
||||
var findCommonEdges = /* @__PURE__ */ __name((graph, id1, id2) => {
|
||||
const edges1 = graph.edges().filter((edge) => edge.v === id1 || edge.w === id1);
|
||||
const edges2 = graph.edges().filter((edge) => edge.v === id2 || edge.w === id2);
|
||||
const edges1Prim = edges1.map((edge) => {
|
||||
return { v: edge.v === id1 ? id2 : edge.v, w: edge.w === id1 ? id1 : edge.w };
|
||||
});
|
||||
const edges2Prim = edges2.map((edge) => {
|
||||
return { v: edge.v, w: edge.w };
|
||||
});
|
||||
const result = edges1Prim.filter((edgeIn1) => {
|
||||
return edges2Prim.some((edge) => edgeIn1.v === edge.v && edgeIn1.w === edge.w);
|
||||
});
|
||||
return result;
|
||||
}, "findCommonEdges");
|
||||
var findNonClusterChild = /* @__PURE__ */ __name((id, graph, clusterId) => {
|
||||
const children = graph.children(id);
|
||||
log.trace("Searching children of id ", id, children);
|
||||
if (children.length < 1) {
|
||||
return id;
|
||||
}
|
||||
let reserve;
|
||||
for (const child of children) {
|
||||
const _id = findNonClusterChild(child, graph, clusterId);
|
||||
const commonEdges = findCommonEdges(graph, clusterId, _id);
|
||||
if (_id) {
|
||||
if (commonEdges.length > 0) {
|
||||
reserve = _id;
|
||||
} else {
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return reserve;
|
||||
}, "findNonClusterChild");
|
||||
var getAnchorId = /* @__PURE__ */ __name((id) => {
|
||||
if (!clusterDb.has(id)) {
|
||||
return id;
|
||||
}
|
||||
if (!clusterDb.get(id).externalConnections) {
|
||||
return id;
|
||||
}
|
||||
if (clusterDb.has(id)) {
|
||||
return clusterDb.get(id).id;
|
||||
}
|
||||
return id;
|
||||
}, "getAnchorId");
|
||||
var adjustClustersAndEdges = /* @__PURE__ */ __name((graph, depth) => {
|
||||
if (!graph || depth > 10) {
|
||||
log.debug("Opting out, no graph ");
|
||||
return;
|
||||
} else {
|
||||
log.debug("Opting in, graph ");
|
||||
}
|
||||
graph.nodes().forEach(function(id) {
|
||||
const children = graph.children(id);
|
||||
if (children.length > 0) {
|
||||
log.warn(
|
||||
"Cluster identified",
|
||||
id,
|
||||
" Replacement id in edges: ",
|
||||
findNonClusterChild(id, graph, id)
|
||||
);
|
||||
descendants.set(id, extractDescendants(id, graph));
|
||||
clusterDb.set(id, { id: findNonClusterChild(id, graph, id), clusterData: graph.node(id) });
|
||||
}
|
||||
});
|
||||
graph.nodes().forEach(function(id) {
|
||||
const children = graph.children(id);
|
||||
const edges = graph.edges();
|
||||
if (children.length > 0) {
|
||||
log.debug("Cluster identified", id, descendants);
|
||||
edges.forEach((edge) => {
|
||||
const d1 = isDescendant(edge.v, id);
|
||||
const d2 = isDescendant(edge.w, id);
|
||||
if (d1 ^ d2) {
|
||||
log.warn("Edge: ", edge, " leaves cluster ", id);
|
||||
log.warn("Descendants of XXX ", id, ": ", descendants.get(id));
|
||||
clusterDb.get(id).externalConnections = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.debug("Not a cluster ", id, descendants);
|
||||
}
|
||||
});
|
||||
for (let id of clusterDb.keys()) {
|
||||
const nonClusterChild = clusterDb.get(id).id;
|
||||
const parent = graph.parent(nonClusterChild);
|
||||
if (parent !== id && clusterDb.has(parent) && !clusterDb.get(parent).externalConnections) {
|
||||
clusterDb.get(id).id = parent;
|
||||
}
|
||||
}
|
||||
graph.edges().forEach(function(e) {
|
||||
const edge = graph.edge(e);
|
||||
log.warn("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(e));
|
||||
log.warn("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(graph.edge(e)));
|
||||
let v = e.v;
|
||||
let w = e.w;
|
||||
log.warn(
|
||||
"Fix XXX",
|
||||
clusterDb,
|
||||
"ids:",
|
||||
e.v,
|
||||
e.w,
|
||||
"Translating: ",
|
||||
clusterDb.get(e.v),
|
||||
" --- ",
|
||||
clusterDb.get(e.w)
|
||||
);
|
||||
if (clusterDb.get(e.v) || clusterDb.get(e.w)) {
|
||||
log.warn("Fixing and trying - removing XXX", e.v, e.w, e.name);
|
||||
v = getAnchorId(e.v);
|
||||
w = getAnchorId(e.w);
|
||||
graph.removeEdge(e.v, e.w, e.name);
|
||||
if (v !== e.v) {
|
||||
const parent = graph.parent(v);
|
||||
clusterDb.get(parent).externalConnections = true;
|
||||
edge.fromCluster = e.v;
|
||||
}
|
||||
if (w !== e.w) {
|
||||
const parent = graph.parent(w);
|
||||
clusterDb.get(parent).externalConnections = true;
|
||||
edge.toCluster = e.w;
|
||||
}
|
||||
log.warn("Fix Replacing with XXX", v, w, e.name);
|
||||
graph.setEdge(v, w, edge, e.name);
|
||||
}
|
||||
});
|
||||
log.warn("Adjusted Graph", graphlibJson.write(graph));
|
||||
extractor(graph, 0);
|
||||
log.trace(clusterDb);
|
||||
}, "adjustClustersAndEdges");
|
||||
var extractor = /* @__PURE__ */ __name((graph, depth) => {
|
||||
log.warn("extractor - ", depth, graphlibJson.write(graph), graph.children("D"));
|
||||
if (depth > 10) {
|
||||
log.error("Bailing out");
|
||||
return;
|
||||
}
|
||||
let nodes = graph.nodes();
|
||||
let hasChildren = false;
|
||||
for (const node of nodes) {
|
||||
const children = graph.children(node);
|
||||
hasChildren = hasChildren || children.length > 0;
|
||||
}
|
||||
if (!hasChildren) {
|
||||
log.debug("Done, no node has children", graph.nodes());
|
||||
return;
|
||||
}
|
||||
log.debug("Nodes = ", nodes, depth);
|
||||
for (const node of nodes) {
|
||||
log.debug(
|
||||
"Extracting node",
|
||||
node,
|
||||
clusterDb,
|
||||
clusterDb.has(node) && !clusterDb.get(node).externalConnections,
|
||||
!graph.parent(node),
|
||||
graph.node(node),
|
||||
graph.children("D"),
|
||||
" Depth ",
|
||||
depth
|
||||
);
|
||||
if (!clusterDb.has(node)) {
|
||||
log.debug("Not a cluster", node, depth);
|
||||
} else if (!clusterDb.get(node).externalConnections && graph.children(node) && graph.children(node).length > 0) {
|
||||
log.warn(
|
||||
"Cluster without external connections, without a parent and with children",
|
||||
node,
|
||||
depth
|
||||
);
|
||||
const graphSettings = graph.graph();
|
||||
let dir = graphSettings.rankdir === "TB" ? "LR" : "TB";
|
||||
if (clusterDb.get(node)?.clusterData?.dir) {
|
||||
dir = clusterDb.get(node).clusterData.dir;
|
||||
log.warn("Fixing dir", clusterDb.get(node).clusterData.dir, dir);
|
||||
}
|
||||
const clusterGraph = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
compound: true
|
||||
}).setGraph({
|
||||
rankdir: dir,
|
||||
nodesep: 50,
|
||||
ranksep: 50,
|
||||
marginx: 8,
|
||||
marginy: 8
|
||||
}).setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
log.warn("Old graph before copy", graphlibJson.write(graph));
|
||||
copy(node, graph, clusterGraph, node);
|
||||
graph.setNode(node, {
|
||||
clusterNode: true,
|
||||
id: node,
|
||||
clusterData: clusterDb.get(node).clusterData,
|
||||
label: clusterDb.get(node).label,
|
||||
graph: clusterGraph
|
||||
});
|
||||
log.warn("New graph after copy node: (", node, ")", graphlibJson.write(clusterGraph));
|
||||
log.debug("Old graph after copy", graphlibJson.write(graph));
|
||||
} else {
|
||||
log.warn(
|
||||
"Cluster ** ",
|
||||
node,
|
||||
" **not meeting the criteria !externalConnections:",
|
||||
!clusterDb.get(node).externalConnections,
|
||||
" no parent: ",
|
||||
!graph.parent(node),
|
||||
" children ",
|
||||
graph.children(node) && graph.children(node).length > 0,
|
||||
graph.children("D"),
|
||||
depth
|
||||
);
|
||||
log.debug(clusterDb);
|
||||
}
|
||||
}
|
||||
nodes = graph.nodes();
|
||||
log.warn("New list of nodes", nodes);
|
||||
for (const node of nodes) {
|
||||
const data = graph.node(node);
|
||||
log.warn(" Now next level", node, data);
|
||||
if (data?.clusterNode) {
|
||||
extractor(data.graph, depth + 1);
|
||||
}
|
||||
}
|
||||
}, "extractor");
|
||||
var sorter = /* @__PURE__ */ __name((graph, nodes) => {
|
||||
if (nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
let result = Object.assign([], nodes);
|
||||
nodes.forEach((node) => {
|
||||
const children = graph.children(node);
|
||||
const sorted = sorter(graph, children);
|
||||
result = [...result, ...sorted];
|
||||
});
|
||||
return result;
|
||||
}, "sorter");
|
||||
var sortNodesByHierarchy = /* @__PURE__ */ __name((graph) => sorter(graph, graph.children()), "sortNodesByHierarchy");
|
||||
|
||||
// src/rendering-util/layout-algorithms/dagre/index.js
|
||||
var recursiveRender = /* @__PURE__ */ __name(async (_elem, graph, diagramType, id, parentCluster, siteConfig) => {
|
||||
log.warn("Graph in recursive render:XAX", graphlibJson2.write(graph), parentCluster);
|
||||
const dir = graph.graph().rankdir;
|
||||
log.trace("Dir in recursive render - dir:", dir);
|
||||
const elem = _elem.insert("g").attr("class", "root");
|
||||
if (!graph.nodes()) {
|
||||
log.info("No nodes found for", graph);
|
||||
} else {
|
||||
log.info("Recursive render XXX", graph.nodes());
|
||||
}
|
||||
if (graph.edges().length > 0) {
|
||||
log.info("Recursive edges", graph.edge(graph.edges()[0]));
|
||||
}
|
||||
const clusters = elem.insert("g").attr("class", "clusters");
|
||||
const edgePaths = elem.insert("g").attr("class", "edgePaths");
|
||||
const edgeLabels = elem.insert("g").attr("class", "edgeLabels");
|
||||
const nodes = elem.insert("g").attr("class", "nodes");
|
||||
await Promise.all(
|
||||
graph.nodes().map(async function(v) {
|
||||
const node = graph.node(v);
|
||||
if (parentCluster !== void 0) {
|
||||
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
|
||||
log.trace(
|
||||
"Setting data for parent cluster XXX\n Node.id = ",
|
||||
v,
|
||||
"\n data=",
|
||||
data.height,
|
||||
"\nParent cluster",
|
||||
parentCluster.height
|
||||
);
|
||||
graph.setNode(parentCluster.id, data);
|
||||
if (!graph.parent(v)) {
|
||||
log.trace("Setting parent", v, parentCluster.id);
|
||||
graph.setParent(v, parentCluster.id, data);
|
||||
}
|
||||
}
|
||||
log.info("(Insert) Node XXX" + v + ": " + JSON.stringify(graph.node(v)));
|
||||
if (node?.clusterNode) {
|
||||
log.info("Cluster identified XBX", v, node.width, graph.node(v));
|
||||
const { ranksep, nodesep } = graph.graph();
|
||||
node.graph.setGraph({
|
||||
...node.graph.graph(),
|
||||
ranksep: ranksep + 25,
|
||||
nodesep
|
||||
});
|
||||
const o = await recursiveRender(
|
||||
nodes,
|
||||
node.graph,
|
||||
diagramType,
|
||||
id,
|
||||
graph.node(v),
|
||||
siteConfig
|
||||
);
|
||||
const newEl = o.elem;
|
||||
updateNodeBounds(node, newEl);
|
||||
node.diff = o.diff || 0;
|
||||
log.info(
|
||||
"New compound node after recursive render XAX",
|
||||
v,
|
||||
"width",
|
||||
// node,
|
||||
node.width,
|
||||
"height",
|
||||
node.height
|
||||
// node.x,
|
||||
// node.y
|
||||
);
|
||||
setNodeElem(newEl, node);
|
||||
} else {
|
||||
if (graph.children(v).length > 0) {
|
||||
log.trace(
|
||||
"Cluster - the non recursive path XBX",
|
||||
v,
|
||||
node.id,
|
||||
node,
|
||||
node.width,
|
||||
"Graph:",
|
||||
graph
|
||||
);
|
||||
log.trace(findNonClusterChild(node.id, graph));
|
||||
clusterDb.set(node.id, { id: findNonClusterChild(node.id, graph), node });
|
||||
} else {
|
||||
log.trace("Node - the non recursive path XAX", v, nodes, graph.node(v), dir);
|
||||
await insertNode(nodes, graph.node(v), { config: siteConfig, dir });
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
const processEdges = /* @__PURE__ */ __name(async () => {
|
||||
const edgePromises = graph.edges().map(async function(e) {
|
||||
const edge = graph.edge(e.v, e.w, e.name);
|
||||
log.info("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(e));
|
||||
log.info("Edge " + e.v + " -> " + e.w + ": ", e, " ", JSON.stringify(graph.edge(e)));
|
||||
log.info(
|
||||
"Fix",
|
||||
clusterDb,
|
||||
"ids:",
|
||||
e.v,
|
||||
e.w,
|
||||
"Translating: ",
|
||||
clusterDb.get(e.v),
|
||||
clusterDb.get(e.w)
|
||||
);
|
||||
await insertEdgeLabel(edgeLabels, edge);
|
||||
});
|
||||
await Promise.all(edgePromises);
|
||||
}, "processEdges");
|
||||
await processEdges();
|
||||
log.info("Graph before layout:", JSON.stringify(graphlibJson2.write(graph)));
|
||||
log.info("############################################# XXX");
|
||||
log.info("### Layout ### XXX");
|
||||
log.info("############################################# XXX");
|
||||
dagreLayout(graph);
|
||||
log.info("Graph after layout:", JSON.stringify(graphlibJson2.write(graph)));
|
||||
let diff = 0;
|
||||
let { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
|
||||
await Promise.all(
|
||||
sortNodesByHierarchy(graph).map(async function(v) {
|
||||
const node = graph.node(v);
|
||||
log.info(
|
||||
"Position XBX => " + v + ": (" + node.x,
|
||||
"," + node.y,
|
||||
") width: ",
|
||||
node.width,
|
||||
" height: ",
|
||||
node.height
|
||||
);
|
||||
if (node?.clusterNode) {
|
||||
node.y += subGraphTitleTotalMargin;
|
||||
log.info(
|
||||
"A tainted cluster node XBX1",
|
||||
v,
|
||||
node.id,
|
||||
node.width,
|
||||
node.height,
|
||||
node.x,
|
||||
node.y,
|
||||
graph.parent(v)
|
||||
);
|
||||
clusterDb.get(node.id).node = node;
|
||||
positionNode(node);
|
||||
} else {
|
||||
if (graph.children(v).length > 0) {
|
||||
log.info(
|
||||
"A pure cluster node XBX1",
|
||||
v,
|
||||
node.id,
|
||||
node.x,
|
||||
node.y,
|
||||
node.width,
|
||||
node.height,
|
||||
graph.parent(v)
|
||||
);
|
||||
node.height += subGraphTitleTotalMargin;
|
||||
graph.node(node.parentId);
|
||||
const halfPadding = node?.padding / 2 || 0;
|
||||
const labelHeight = node?.labelBBox?.height || 0;
|
||||
const offsetY = labelHeight - halfPadding || 0;
|
||||
log.debug("OffsetY", offsetY, "labelHeight", labelHeight, "halfPadding", halfPadding);
|
||||
await insertCluster(clusters, node);
|
||||
clusterDb.get(node.id).node = node;
|
||||
} else {
|
||||
const parent = graph.node(node.parentId);
|
||||
node.y += subGraphTitleTotalMargin / 2;
|
||||
log.info(
|
||||
"A regular node XBX1 - using the padding",
|
||||
node.id,
|
||||
"parent",
|
||||
node.parentId,
|
||||
node.width,
|
||||
node.height,
|
||||
node.x,
|
||||
node.y,
|
||||
"offsetY",
|
||||
node.offsetY,
|
||||
"parent",
|
||||
parent,
|
||||
parent?.offsetY,
|
||||
node
|
||||
);
|
||||
positionNode(node);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
graph.edges().forEach(function(e) {
|
||||
const edge = graph.edge(e);
|
||||
log.info("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(edge), edge);
|
||||
edge.points.forEach((point) => point.y += subGraphTitleTotalMargin / 2);
|
||||
const startNode = graph.node(e.v);
|
||||
var endNode = graph.node(e.w);
|
||||
const paths = insertEdge(edgePaths, edge, clusterDb, diagramType, startNode, endNode, id);
|
||||
positionEdgeLabel(edge, paths);
|
||||
});
|
||||
graph.nodes().forEach(function(v) {
|
||||
const n = graph.node(v);
|
||||
log.info(v, n.type, n.diff);
|
||||
if (n.isGroup) {
|
||||
diff = n.diff;
|
||||
}
|
||||
});
|
||||
log.warn("Returning from recursive render XAX", elem, diff);
|
||||
return { elem, diff };
|
||||
}, "recursiveRender");
|
||||
var render = /* @__PURE__ */ __name(async (data4Layout, svg) => {
|
||||
const graph = new graphlib2.Graph({
|
||||
multigraph: true,
|
||||
compound: true
|
||||
}).setGraph({
|
||||
rankdir: data4Layout.direction,
|
||||
nodesep: data4Layout.config?.nodeSpacing || data4Layout.config?.flowchart?.nodeSpacing || data4Layout.nodeSpacing,
|
||||
ranksep: data4Layout.config?.rankSpacing || data4Layout.config?.flowchart?.rankSpacing || data4Layout.rankSpacing,
|
||||
marginx: 8,
|
||||
marginy: 8
|
||||
}).setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
const element = svg.select("g");
|
||||
markers_default(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);
|
||||
clear3();
|
||||
clear2();
|
||||
clear();
|
||||
clear4();
|
||||
data4Layout.nodes.forEach((node) => {
|
||||
graph.setNode(node.id, { ...node });
|
||||
if (node.parentId) {
|
||||
graph.setParent(node.id, node.parentId);
|
||||
}
|
||||
});
|
||||
log.debug("Edges:", data4Layout.edges);
|
||||
data4Layout.edges.forEach((edge) => {
|
||||
if (edge.start === edge.end) {
|
||||
const nodeId = edge.start;
|
||||
const specialId1 = nodeId + "---" + nodeId + "---1";
|
||||
const specialId2 = nodeId + "---" + nodeId + "---2";
|
||||
const node = graph.node(nodeId);
|
||||
graph.setNode(specialId1, {
|
||||
domId: specialId1,
|
||||
id: specialId1,
|
||||
parentId: node.parentId,
|
||||
labelStyle: "",
|
||||
label: "",
|
||||
padding: 0,
|
||||
shape: "labelRect",
|
||||
// shape: 'rect',
|
||||
style: "",
|
||||
width: 10,
|
||||
height: 10
|
||||
});
|
||||
graph.setParent(specialId1, node.parentId);
|
||||
graph.setNode(specialId2, {
|
||||
domId: specialId2,
|
||||
id: specialId2,
|
||||
parentId: node.parentId,
|
||||
labelStyle: "",
|
||||
padding: 0,
|
||||
// shape: 'rect',
|
||||
shape: "labelRect",
|
||||
label: "",
|
||||
style: "",
|
||||
width: 10,
|
||||
height: 10
|
||||
});
|
||||
graph.setParent(specialId2, node.parentId);
|
||||
const edge1 = structuredClone(edge);
|
||||
const edgeMid = structuredClone(edge);
|
||||
const edge2 = structuredClone(edge);
|
||||
edge1.label = "";
|
||||
edge1.arrowTypeEnd = "none";
|
||||
edge1.id = nodeId + "-cyclic-special-1";
|
||||
edgeMid.arrowTypeStart = "none";
|
||||
edgeMid.arrowTypeEnd = "none";
|
||||
edgeMid.id = nodeId + "-cyclic-special-mid";
|
||||
edge2.label = "";
|
||||
if (node.isGroup) {
|
||||
edge1.fromCluster = nodeId;
|
||||
edge2.toCluster = nodeId;
|
||||
}
|
||||
edge2.id = nodeId + "-cyclic-special-2";
|
||||
edge2.arrowTypeStart = "none";
|
||||
graph.setEdge(nodeId, specialId1, edge1, nodeId + "-cyclic-special-0");
|
||||
graph.setEdge(specialId1, specialId2, edgeMid, nodeId + "-cyclic-special-1");
|
||||
graph.setEdge(specialId2, nodeId, edge2, nodeId + "-cyc<lic-special-2");
|
||||
} else {
|
||||
graph.setEdge(edge.start, edge.end, { ...edge }, edge.id);
|
||||
}
|
||||
});
|
||||
log.warn("Graph at first:", JSON.stringify(graphlibJson2.write(graph)));
|
||||
adjustClustersAndEdges(graph);
|
||||
log.warn("Graph after XAX:", JSON.stringify(graphlibJson2.write(graph)));
|
||||
const siteConfig = getConfig();
|
||||
await recursiveRender(
|
||||
element,
|
||||
graph,
|
||||
data4Layout.type,
|
||||
data4Layout.diagramId,
|
||||
void 0,
|
||||
siteConfig
|
||||
);
|
||||
}, "render");
|
||||
export {
|
||||
render
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+204
@@ -0,0 +1,204 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
ImperativeState
|
||||
} from "./chunk-QZHKN3VN.mjs";
|
||||
import {
|
||||
cleanAndMerge
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
defaultConfig_default,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig,
|
||||
getDiagramTitle,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/treeView/db.ts
|
||||
var state = new ImperativeState(() => ({
|
||||
cnt: 1,
|
||||
stack: [
|
||||
{
|
||||
id: 0,
|
||||
level: -1,
|
||||
name: "/",
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}));
|
||||
var clear2 = /* @__PURE__ */ __name(() => {
|
||||
state.reset();
|
||||
clear();
|
||||
}, "clear");
|
||||
var getRoot = /* @__PURE__ */ __name(() => {
|
||||
return state.records.stack[0];
|
||||
}, "getRoot");
|
||||
var getCount = /* @__PURE__ */ __name(() => state.records.cnt, "getCount");
|
||||
var defaultConfig = defaultConfig_default.treeView;
|
||||
var getConfig2 = /* @__PURE__ */ __name(() => {
|
||||
return cleanAndMerge(defaultConfig, getConfig().treeView);
|
||||
}, "getConfig");
|
||||
var addNode = /* @__PURE__ */ __name((level, name) => {
|
||||
while (level <= state.records.stack[state.records.stack.length - 1].level) {
|
||||
state.records.stack.pop();
|
||||
}
|
||||
const node = {
|
||||
id: state.records.cnt++,
|
||||
level,
|
||||
name,
|
||||
children: []
|
||||
};
|
||||
state.records.stack[state.records.stack.length - 1].children.push(node);
|
||||
state.records.stack.push(node);
|
||||
}, "addNode");
|
||||
var db = {
|
||||
clear: clear2,
|
||||
addNode,
|
||||
getRoot,
|
||||
getCount,
|
||||
getConfig: getConfig2,
|
||||
getAccTitle,
|
||||
getAccDescription,
|
||||
getDiagramTitle,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
};
|
||||
var db_default = db;
|
||||
|
||||
// src/diagrams/treeView/parser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
var populate = /* @__PURE__ */ __name((ast) => {
|
||||
populateCommonDb(ast, db_default);
|
||||
ast.nodes.map((node) => db_default.addNode(node.indent ? parseInt(node.indent) : 0, node.name));
|
||||
}, "populate");
|
||||
var parser = {
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("treeView", input);
|
||||
log.debug(ast);
|
||||
populate(ast);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/treeView/renderer.ts
|
||||
var positionLabel = /* @__PURE__ */ __name((x, y, node, domElem, config) => {
|
||||
const label = domElem.append("text").text(node.name).attr("dominant-baseline", "middle").attr("class", "treeView-node-label");
|
||||
const { height: labelHeight, width: labelWidth } = label.node().getBBox();
|
||||
const height = labelHeight + config.paddingY * 2;
|
||||
const width = labelWidth + config.paddingX * 2;
|
||||
label.attr("x", x + config.paddingX);
|
||||
label.attr("y", y + height / 2);
|
||||
node.BBox = {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height
|
||||
};
|
||||
}, "positionLabel");
|
||||
var positionLine = /* @__PURE__ */ __name((domElem, x1, y1, x2, y2, lineThickness) => {
|
||||
return domElem.append("line").attr("x1", x1).attr("y1", y1).attr("x2", x2).attr("y2", y2).attr("stroke-width", lineThickness).attr("class", "treeView-node-line");
|
||||
}, "positionLine");
|
||||
var drawTree = /* @__PURE__ */ __name((elem, root, config) => {
|
||||
let totalHeight = 0;
|
||||
let totalWidth = 0;
|
||||
const drawNode = /* @__PURE__ */ __name((elem2, node, config2, depth) => {
|
||||
const indent = depth * (config2.rowIndent + config2.paddingX);
|
||||
positionLabel(indent, totalHeight, node, elem2, config2);
|
||||
const { height, width } = node.BBox;
|
||||
positionLine(
|
||||
elem2,
|
||||
indent - config2.rowIndent,
|
||||
totalHeight + height / 2,
|
||||
indent,
|
||||
totalHeight + height / 2,
|
||||
config2.lineThickness
|
||||
);
|
||||
totalWidth = Math.max(totalWidth, indent + width);
|
||||
totalHeight += height;
|
||||
}, "drawNode");
|
||||
const processNode = /* @__PURE__ */ __name((node, depth = 0) => {
|
||||
drawNode(elem, node, config, depth);
|
||||
node.children.forEach((child) => {
|
||||
processNode(child, depth + 1);
|
||||
});
|
||||
const { x, y, height } = node.BBox;
|
||||
if (node.children.length) {
|
||||
const { y: endY, height: endHeight } = node.children[node.children.length - 1].BBox;
|
||||
positionLine(
|
||||
elem,
|
||||
x + config.paddingX,
|
||||
y + height,
|
||||
x + config.paddingX,
|
||||
endY + endHeight / 2 + config.lineThickness / 2,
|
||||
config.lineThickness
|
||||
);
|
||||
}
|
||||
}, "processNode");
|
||||
processNode(root);
|
||||
return { totalHeight, totalWidth };
|
||||
}, "drawTree");
|
||||
var draw = /* @__PURE__ */ __name((text, id, _ver, diagObj) => {
|
||||
log.debug("Rendering treeView diagram\n" + text);
|
||||
const db2 = diagObj.db;
|
||||
const root = db2.getRoot();
|
||||
const config = db2.getConfig();
|
||||
const svg = selectSvgElement(id);
|
||||
const treeElem = svg.append("g");
|
||||
treeElem.attr("class", "tree-view");
|
||||
const { totalHeight, totalWidth } = drawTree(treeElem, root, config);
|
||||
svg.attr("viewBox", `-${config.lineThickness / 2} 0 ${totalWidth} ${totalHeight}`);
|
||||
configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth);
|
||||
}, "draw");
|
||||
var renderer = {
|
||||
draw
|
||||
};
|
||||
var renderer_default = renderer;
|
||||
|
||||
// src/diagrams/treeView/styles.ts
|
||||
var defaultTreeViewDiagramStyles = {
|
||||
labelFontSize: "16px",
|
||||
labelColor: "black",
|
||||
lineColor: "black"
|
||||
};
|
||||
var styles = /* @__PURE__ */ __name(({
|
||||
treeView
|
||||
}) => {
|
||||
const { labelFontSize, labelColor, lineColor } = cleanAndMerge(
|
||||
defaultTreeViewDiagramStyles,
|
||||
treeView
|
||||
);
|
||||
return `
|
||||
.treeView-node-label {
|
||||
font-size: ${labelFontSize};
|
||||
fill: ${labelColor};
|
||||
}
|
||||
.treeView-node-line {
|
||||
stroke: ${lineColor};
|
||||
}
|
||||
`;
|
||||
}, "styles");
|
||||
var styles_default = styles;
|
||||
|
||||
// src/diagrams/treeView/diagram.ts
|
||||
var diagram = {
|
||||
db: db_default,
|
||||
renderer: renderer_default,
|
||||
parser,
|
||||
styles: styles_default
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+568
@@ -0,0 +1,568 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
setupViewPortForSVG
|
||||
} from "./chunk-EDXVE4YY.mjs";
|
||||
import {
|
||||
isLabelStyle,
|
||||
styles2String
|
||||
} from "./chunk-X2U36JSP.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
cleanAndMerge
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
defaultConfig_default,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig,
|
||||
getDiagramTitle,
|
||||
getThemeVariables,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/treemap/db.ts
|
||||
var TreeMapDB = class {
|
||||
constructor() {
|
||||
this.nodes = [];
|
||||
this.levels = /* @__PURE__ */ new Map();
|
||||
this.outerNodes = [];
|
||||
this.classes = /* @__PURE__ */ new Map();
|
||||
this.setAccTitle = setAccTitle;
|
||||
this.getAccTitle = getAccTitle;
|
||||
this.setDiagramTitle = setDiagramTitle;
|
||||
this.getDiagramTitle = getDiagramTitle;
|
||||
this.getAccDescription = getAccDescription;
|
||||
this.setAccDescription = setAccDescription;
|
||||
}
|
||||
static {
|
||||
__name(this, "TreeMapDB");
|
||||
}
|
||||
getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
getConfig() {
|
||||
const defaultConfig = defaultConfig_default;
|
||||
const userConfig = getConfig();
|
||||
return cleanAndMerge({
|
||||
...defaultConfig.treemap,
|
||||
...userConfig.treemap ?? {}
|
||||
});
|
||||
}
|
||||
addNode(node, level) {
|
||||
this.nodes.push(node);
|
||||
this.levels.set(node, level);
|
||||
if (level === 0) {
|
||||
this.outerNodes.push(node);
|
||||
this.root ??= node;
|
||||
}
|
||||
}
|
||||
getRoot() {
|
||||
return { name: "", children: this.outerNodes };
|
||||
}
|
||||
addClass(id, _style) {
|
||||
const styleClass = this.classes.get(id) ?? { id, styles: [], textStyles: [] };
|
||||
const styles = _style.replace(/\\,/g, "\xA7\xA7\xA7").replace(/,/g, ";").replace(/§§§/g, ",").split(";");
|
||||
if (styles) {
|
||||
styles.forEach((s) => {
|
||||
if (isLabelStyle(s)) {
|
||||
if (styleClass?.textStyles) {
|
||||
styleClass.textStyles.push(s);
|
||||
} else {
|
||||
styleClass.textStyles = [s];
|
||||
}
|
||||
}
|
||||
if (styleClass?.styles) {
|
||||
styleClass.styles.push(s);
|
||||
} else {
|
||||
styleClass.styles = [s];
|
||||
}
|
||||
});
|
||||
}
|
||||
this.classes.set(id, styleClass);
|
||||
}
|
||||
getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
getStylesForClass(classSelector) {
|
||||
return this.classes.get(classSelector)?.styles ?? [];
|
||||
}
|
||||
clear() {
|
||||
clear();
|
||||
this.nodes = [];
|
||||
this.levels = /* @__PURE__ */ new Map();
|
||||
this.outerNodes = [];
|
||||
this.classes = /* @__PURE__ */ new Map();
|
||||
this.root = void 0;
|
||||
}
|
||||
};
|
||||
|
||||
// src/diagrams/treemap/parser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
|
||||
// src/diagrams/treemap/utils.ts
|
||||
function buildHierarchy(items) {
|
||||
if (!items.length) {
|
||||
return [];
|
||||
}
|
||||
const root = [];
|
||||
const stack = [];
|
||||
items.forEach((item) => {
|
||||
const node = {
|
||||
name: item.name,
|
||||
children: item.type === "Leaf" ? void 0 : []
|
||||
};
|
||||
node.classSelector = item?.classSelector;
|
||||
if (item?.cssCompiledStyles) {
|
||||
node.cssCompiledStyles = item.cssCompiledStyles;
|
||||
}
|
||||
if (item.type === "Leaf" && item.value !== void 0) {
|
||||
node.value = item.value;
|
||||
}
|
||||
while (stack.length > 0 && stack[stack.length - 1].level >= item.level) {
|
||||
stack.pop();
|
||||
}
|
||||
if (stack.length === 0) {
|
||||
root.push(node);
|
||||
} else {
|
||||
const parent = stack[stack.length - 1].node;
|
||||
if (parent.children) {
|
||||
parent.children.push(node);
|
||||
} else {
|
||||
parent.children = [node];
|
||||
}
|
||||
}
|
||||
if (item.type !== "Leaf") {
|
||||
stack.push({ node, level: item.level });
|
||||
}
|
||||
});
|
||||
return root;
|
||||
}
|
||||
__name(buildHierarchy, "buildHierarchy");
|
||||
|
||||
// src/diagrams/treemap/parser.ts
|
||||
var populate = /* @__PURE__ */ __name((ast, db) => {
|
||||
populateCommonDb(ast, db);
|
||||
const items = [];
|
||||
for (const row of ast.TreemapRows ?? []) {
|
||||
if (row.$type === "ClassDefStatement") {
|
||||
db.addClass(row.className ?? "", row.styleText ?? "");
|
||||
}
|
||||
}
|
||||
for (const row of ast.TreemapRows ?? []) {
|
||||
const item = row.item;
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
const level = row.indent ? parseInt(row.indent) : 0;
|
||||
const name = getItemName(item);
|
||||
const styles = item.classSelector ? db.getStylesForClass(item.classSelector) : [];
|
||||
const cssCompiledStyles = styles.length > 0 ? styles : void 0;
|
||||
const itemData = {
|
||||
level,
|
||||
name,
|
||||
type: item.$type,
|
||||
value: item.value,
|
||||
classSelector: item.classSelector,
|
||||
cssCompiledStyles
|
||||
};
|
||||
items.push(itemData);
|
||||
}
|
||||
const hierarchyNodes = buildHierarchy(items);
|
||||
const addNodesRecursively = /* @__PURE__ */ __name((nodes, level) => {
|
||||
for (const node of nodes) {
|
||||
db.addNode(node, level);
|
||||
if (node.children && node.children.length > 0) {
|
||||
addNodesRecursively(node.children, level + 1);
|
||||
}
|
||||
}
|
||||
}, "addNodesRecursively");
|
||||
addNodesRecursively(hierarchyNodes, 0);
|
||||
}, "populate");
|
||||
var getItemName = /* @__PURE__ */ __name((item) => {
|
||||
return item.name ? String(item.name) : "";
|
||||
}, "getItemName");
|
||||
var parser = {
|
||||
// @ts-expect-error - TreeMapDB is not assignable to DiagramDB
|
||||
parser: { yy: void 0 },
|
||||
parse: /* @__PURE__ */ __name(async (text) => {
|
||||
try {
|
||||
const parseFunc = parse;
|
||||
const ast = await parseFunc("treemap", text);
|
||||
log.debug("Treemap AST:", ast);
|
||||
const db = parser.parser?.yy;
|
||||
if (!(db instanceof TreeMapDB)) {
|
||||
throw new Error(
|
||||
"parser.parser?.yy was not a TreemapDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues."
|
||||
);
|
||||
}
|
||||
populate(ast, db);
|
||||
} catch (error) {
|
||||
log.error("Error parsing treemap:", error);
|
||||
throw error;
|
||||
}
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/treemap/renderer.ts
|
||||
import { scaleOrdinal, treemap, hierarchy, format, select } from "d3";
|
||||
var DEFAULT_INNER_PADDING = 10;
|
||||
var SECTION_INNER_PADDING = 10;
|
||||
var SECTION_HEADER_HEIGHT = 25;
|
||||
var draw = /* @__PURE__ */ __name((_text, id, _version, diagram2) => {
|
||||
const treemapDb = diagram2.db;
|
||||
const config = treemapDb.getConfig();
|
||||
const treemapInnerPadding = config.padding ?? DEFAULT_INNER_PADDING;
|
||||
const title = treemapDb.getDiagramTitle();
|
||||
const root = treemapDb.getRoot();
|
||||
const { themeVariables } = getConfig();
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
const titleHeight = title ? 30 : 0;
|
||||
const svg = selectSvgElement(id);
|
||||
const width = config.nodeWidth ? config.nodeWidth * SECTION_INNER_PADDING : 960;
|
||||
const height = config.nodeHeight ? config.nodeHeight * SECTION_INNER_PADDING : 500;
|
||||
const svgWidth = width;
|
||||
const svgHeight = height + titleHeight;
|
||||
svg.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth);
|
||||
let valueFormat;
|
||||
try {
|
||||
const formatStr = config.valueFormat || ",";
|
||||
if (formatStr === "$0,0") {
|
||||
valueFormat = /* @__PURE__ */ __name((value) => "$" + format(",")(value), "valueFormat");
|
||||
} else if (formatStr.startsWith("$") && formatStr.includes(",")) {
|
||||
const precision = /\.\d+/.exec(formatStr);
|
||||
const precisionStr = precision ? precision[0] : "";
|
||||
valueFormat = /* @__PURE__ */ __name((value) => "$" + format("," + precisionStr)(value), "valueFormat");
|
||||
} else if (formatStr.startsWith("$")) {
|
||||
const restOfFormat = formatStr.substring(1);
|
||||
valueFormat = /* @__PURE__ */ __name((value) => "$" + format(restOfFormat || "")(value), "valueFormat");
|
||||
} else {
|
||||
valueFormat = format(formatStr);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error("Error creating format function:", error);
|
||||
valueFormat = format(",");
|
||||
}
|
||||
const colorScale = scaleOrdinal().range([
|
||||
"transparent",
|
||||
themeVariables.cScale0,
|
||||
themeVariables.cScale1,
|
||||
themeVariables.cScale2,
|
||||
themeVariables.cScale3,
|
||||
themeVariables.cScale4,
|
||||
themeVariables.cScale5,
|
||||
themeVariables.cScale6,
|
||||
themeVariables.cScale7,
|
||||
themeVariables.cScale8,
|
||||
themeVariables.cScale9,
|
||||
themeVariables.cScale10,
|
||||
themeVariables.cScale11
|
||||
]);
|
||||
const colorScalePeer = scaleOrdinal().range([
|
||||
"transparent",
|
||||
themeVariables.cScalePeer0,
|
||||
themeVariables.cScalePeer1,
|
||||
themeVariables.cScalePeer2,
|
||||
themeVariables.cScalePeer3,
|
||||
themeVariables.cScalePeer4,
|
||||
themeVariables.cScalePeer5,
|
||||
themeVariables.cScalePeer6,
|
||||
themeVariables.cScalePeer7,
|
||||
themeVariables.cScalePeer8,
|
||||
themeVariables.cScalePeer9,
|
||||
themeVariables.cScalePeer10,
|
||||
themeVariables.cScalePeer11
|
||||
]);
|
||||
const colorScaleLabel = scaleOrdinal().range([
|
||||
themeVariables.cScaleLabel0,
|
||||
themeVariables.cScaleLabel1,
|
||||
themeVariables.cScaleLabel2,
|
||||
themeVariables.cScaleLabel3,
|
||||
themeVariables.cScaleLabel4,
|
||||
themeVariables.cScaleLabel5,
|
||||
themeVariables.cScaleLabel6,
|
||||
themeVariables.cScaleLabel7,
|
||||
themeVariables.cScaleLabel8,
|
||||
themeVariables.cScaleLabel9,
|
||||
themeVariables.cScaleLabel10,
|
||||
themeVariables.cScaleLabel11
|
||||
]);
|
||||
if (title) {
|
||||
svg.append("text").attr("x", svgWidth / 2).attr("y", titleHeight / 2).attr("class", "treemapTitle").attr("text-anchor", "middle").attr("dominant-baseline", "middle").text(title);
|
||||
}
|
||||
const g = svg.append("g").attr("transform", `translate(0, ${titleHeight})`).attr("class", "treemapContainer");
|
||||
const hierarchyRoot = hierarchy(root).sum((d) => d.value ?? 0).sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
|
||||
const treemapLayout = treemap().size([width, height]).paddingTop(
|
||||
(d) => d.children && d.children.length > 0 ? SECTION_HEADER_HEIGHT + SECTION_INNER_PADDING : 0
|
||||
).paddingInner(treemapInnerPadding).paddingLeft((d) => d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0).paddingRight((d) => d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0).paddingBottom((d) => d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0).round(true);
|
||||
const treemapData = treemapLayout(hierarchyRoot);
|
||||
const branchNodes = treemapData.descendants().filter((d) => d.children && d.children.length > 0);
|
||||
const sections = g.selectAll(".treemapSection").data(branchNodes).enter().append("g").attr("class", "treemapSection").attr("transform", (d) => `translate(${d.x0},${d.y0})`);
|
||||
sections.append("rect").attr("width", (d) => d.x1 - d.x0).attr("height", SECTION_HEADER_HEIGHT).attr("class", "treemapSectionHeader").attr("fill", "none").attr("fill-opacity", 0.6).attr("stroke-width", 0.6).attr("style", (d) => {
|
||||
if (d.depth === 0) {
|
||||
return "display: none;";
|
||||
}
|
||||
return "";
|
||||
});
|
||||
sections.append("clipPath").attr("id", (_d, i) => `clip-section-${id}-${i}`).append("rect").attr("width", (d) => Math.max(0, d.x1 - d.x0 - 12)).attr("height", SECTION_HEADER_HEIGHT);
|
||||
sections.append("rect").attr("width", (d) => d.x1 - d.x0).attr("height", (d) => d.y1 - d.y0).attr("class", (_d, i) => {
|
||||
return `treemapSection section${i}`;
|
||||
}).attr("fill", (d) => colorScale(d.data.name)).attr("fill-opacity", 0.6).attr("stroke", (d) => colorScalePeer(d.data.name)).attr("stroke-width", 2).attr("stroke-opacity", 0.4).attr("style", (d) => {
|
||||
if (d.depth === 0) {
|
||||
return "display: none;";
|
||||
}
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return styles.nodeStyles + ";" + styles.borderStyles.join(";");
|
||||
});
|
||||
sections.append("text").attr("class", "treemapSectionLabel").attr("x", 6).attr("y", SECTION_HEADER_HEIGHT / 2).attr("dominant-baseline", "middle").text((d) => d.depth === 0 ? "" : d.data.name).attr("font-weight", "bold").attr("style", (d) => {
|
||||
if (d.depth === 0) {
|
||||
return "display: none;";
|
||||
}
|
||||
const labelStyles = "dominant-baseline: middle; font-size: 12px; fill:" + colorScaleLabel(d.data.name) + "; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return labelStyles + styles.labelStyles.replace("color:", "fill:");
|
||||
}).each(function(d) {
|
||||
if (d.depth === 0) {
|
||||
return;
|
||||
}
|
||||
const self = select(this);
|
||||
const originalText = d.data.name;
|
||||
self.text(originalText);
|
||||
const totalHeaderWidth = d.x1 - d.x0;
|
||||
const labelXPosition = 6;
|
||||
let spaceForTextContent;
|
||||
if (config.showValues !== false && d.value) {
|
||||
const valueEndsAtXRelative = totalHeaderWidth - 10;
|
||||
const estimatedValueTextActualWidth = 30;
|
||||
const gapBetweenLabelAndValue = 10;
|
||||
const labelMustEndBeforeX = valueEndsAtXRelative - estimatedValueTextActualWidth - gapBetweenLabelAndValue;
|
||||
spaceForTextContent = labelMustEndBeforeX - labelXPosition;
|
||||
} else {
|
||||
const labelOwnRightPadding = 6;
|
||||
spaceForTextContent = totalHeaderWidth - labelXPosition - labelOwnRightPadding;
|
||||
}
|
||||
const minimumWidthToDisplay = 15;
|
||||
const actualAvailableWidth = Math.max(minimumWidthToDisplay, spaceForTextContent);
|
||||
const textNode = self.node();
|
||||
const currentTextContentLength = textNode.getComputedTextLength();
|
||||
if (currentTextContentLength > actualAvailableWidth) {
|
||||
const ellipsis = "...";
|
||||
let currentTruncatedText = originalText;
|
||||
while (currentTruncatedText.length > 0) {
|
||||
currentTruncatedText = originalText.substring(0, currentTruncatedText.length - 1);
|
||||
if (currentTruncatedText.length === 0) {
|
||||
self.text(ellipsis);
|
||||
if (textNode.getComputedTextLength() > actualAvailableWidth) {
|
||||
self.text("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
self.text(currentTruncatedText + ellipsis);
|
||||
if (textNode.getComputedTextLength() <= actualAvailableWidth) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (config.showValues !== false) {
|
||||
sections.append("text").attr("class", "treemapSectionValue").attr("x", (d) => d.x1 - d.x0 - 10).attr("y", SECTION_HEADER_HEIGHT / 2).attr("text-anchor", "end").attr("dominant-baseline", "middle").text((d) => d.value ? valueFormat(d.value) : "").attr("font-style", "italic").attr("style", (d) => {
|
||||
if (d.depth === 0) {
|
||||
return "display: none;";
|
||||
}
|
||||
const labelStyles = "text-anchor: end; dominant-baseline: middle; font-size: 10px; fill:" + colorScaleLabel(d.data.name) + "; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;";
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return labelStyles + styles.labelStyles.replace("color:", "fill:");
|
||||
});
|
||||
}
|
||||
const leafNodes = treemapData.leaves();
|
||||
const cell = g.selectAll(".treemapLeafGroup").data(leafNodes).enter().append("g").attr("class", (d, i) => {
|
||||
return `treemapNode treemapLeafGroup leaf${i}${d.data.classSelector ? ` ${d.data.classSelector}` : ""}x`;
|
||||
}).attr("transform", (d) => `translate(${d.x0},${d.y0})`);
|
||||
cell.append("rect").attr("width", (d) => d.x1 - d.x0).attr("height", (d) => d.y1 - d.y0).attr("class", "treemapLeaf").attr("fill", (d) => {
|
||||
return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
|
||||
}).attr("style", (d) => {
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return styles.nodeStyles;
|
||||
}).attr("fill-opacity", 0.3).attr("stroke", (d) => {
|
||||
return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
|
||||
}).attr("stroke-width", 3);
|
||||
cell.append("clipPath").attr("id", (_d, i) => `clip-${id}-${i}`).append("rect").attr("width", (d) => Math.max(0, d.x1 - d.x0 - 4)).attr("height", (d) => Math.max(0, d.y1 - d.y0 - 4));
|
||||
const leafLabels = cell.append("text").attr("class", "treemapLabel").attr("x", (d) => (d.x1 - d.x0) / 2).attr("y", (d) => (d.y1 - d.y0) / 2).attr("style", (d) => {
|
||||
const labelStyles = "text-anchor: middle; dominant-baseline: middle; font-size: 38px;fill:" + colorScaleLabel(d.data.name) + ";";
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return labelStyles + styles.labelStyles.replace("color:", "fill:");
|
||||
}).attr("clip-path", (_d, i) => `url(#clip-${id}-${i})`).text((d) => d.data.name);
|
||||
leafLabels.each(function(d) {
|
||||
const self = select(this);
|
||||
const nodeWidth = d.x1 - d.x0;
|
||||
const nodeHeight = d.y1 - d.y0;
|
||||
const textNode = self.node();
|
||||
const padding = 4;
|
||||
const availableWidth = nodeWidth - 2 * padding;
|
||||
const availableHeight = nodeHeight - 2 * padding;
|
||||
if (availableWidth < 10 || availableHeight < 10) {
|
||||
self.style("display", "none");
|
||||
return;
|
||||
}
|
||||
let currentLabelFontSize = parseInt(self.style("font-size"), 10);
|
||||
const minLabelFontSize = 8;
|
||||
const originalValueRelFontSize = 28;
|
||||
const valueScaleFactor = 0.6;
|
||||
const minValueFontSize = 6;
|
||||
const spacingBetweenLabelAndValue = 2;
|
||||
while (textNode.getComputedTextLength() > availableWidth && currentLabelFontSize > minLabelFontSize) {
|
||||
currentLabelFontSize--;
|
||||
self.style("font-size", `${currentLabelFontSize}px`);
|
||||
}
|
||||
let prospectiveValueFontSize = Math.max(
|
||||
minValueFontSize,
|
||||
Math.min(originalValueRelFontSize, Math.round(currentLabelFontSize * valueScaleFactor))
|
||||
);
|
||||
let combinedHeight = currentLabelFontSize + spacingBetweenLabelAndValue + prospectiveValueFontSize;
|
||||
while (combinedHeight > availableHeight && currentLabelFontSize > minLabelFontSize) {
|
||||
currentLabelFontSize--;
|
||||
prospectiveValueFontSize = Math.max(
|
||||
minValueFontSize,
|
||||
Math.min(originalValueRelFontSize, Math.round(currentLabelFontSize * valueScaleFactor))
|
||||
);
|
||||
if (prospectiveValueFontSize < minValueFontSize && currentLabelFontSize === minLabelFontSize) {
|
||||
break;
|
||||
}
|
||||
self.style("font-size", `${currentLabelFontSize}px`);
|
||||
combinedHeight = currentLabelFontSize + spacingBetweenLabelAndValue + prospectiveValueFontSize;
|
||||
if (prospectiveValueFontSize <= minValueFontSize && combinedHeight > availableHeight) {
|
||||
}
|
||||
}
|
||||
self.style("font-size", `${currentLabelFontSize}px`);
|
||||
if (textNode.getComputedTextLength() > availableWidth || currentLabelFontSize < minLabelFontSize || availableHeight < currentLabelFontSize) {
|
||||
self.style("display", "none");
|
||||
}
|
||||
});
|
||||
if (config.showValues !== false) {
|
||||
const leafValues = cell.append("text").attr("class", "treemapValue").attr("x", (d) => (d.x1 - d.x0) / 2).attr("y", function(d) {
|
||||
return (d.y1 - d.y0) / 2;
|
||||
}).attr("style", (d) => {
|
||||
const labelStyles = "text-anchor: middle; dominant-baseline: hanging; font-size: 28px;fill:" + colorScaleLabel(d.data.name) + ";";
|
||||
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles });
|
||||
return labelStyles + styles.labelStyles.replace("color:", "fill:");
|
||||
}).attr("clip-path", (_d, i) => `url(#clip-${id}-${i})`).text((d) => d.value ? valueFormat(d.value) : "");
|
||||
leafValues.each(function(d) {
|
||||
const valueTextElement = select(this);
|
||||
const parentCellNode = this.parentNode;
|
||||
if (!parentCellNode) {
|
||||
valueTextElement.style("display", "none");
|
||||
return;
|
||||
}
|
||||
const labelElement = select(parentCellNode).select(".treemapLabel");
|
||||
if (labelElement.empty() || labelElement.style("display") === "none") {
|
||||
valueTextElement.style("display", "none");
|
||||
return;
|
||||
}
|
||||
const finalLabelFontSize = parseFloat(labelElement.style("font-size"));
|
||||
const originalValueFontSize = 28;
|
||||
const valueScaleFactor = 0.6;
|
||||
const minValueFontSize = 6;
|
||||
const spacingBetweenLabelAndValue = 2;
|
||||
const actualValueFontSize = Math.max(
|
||||
minValueFontSize,
|
||||
Math.min(originalValueFontSize, Math.round(finalLabelFontSize * valueScaleFactor))
|
||||
);
|
||||
valueTextElement.style("font-size", `${actualValueFontSize}px`);
|
||||
const labelCenterY = (d.y1 - d.y0) / 2;
|
||||
const valueTopActualY = labelCenterY + finalLabelFontSize / 2 + spacingBetweenLabelAndValue;
|
||||
valueTextElement.attr("y", valueTopActualY);
|
||||
const nodeWidth = d.x1 - d.x0;
|
||||
const nodeTotalHeight = d.y1 - d.y0;
|
||||
const cellBottomPadding = 4;
|
||||
const maxValueBottomY = nodeTotalHeight - cellBottomPadding;
|
||||
const availableWidthForValue = nodeWidth - 2 * 4;
|
||||
if (valueTextElement.node().getComputedTextLength() > availableWidthForValue || valueTopActualY + actualValueFontSize > maxValueBottomY || actualValueFontSize < minValueFontSize) {
|
||||
valueTextElement.style("display", "none");
|
||||
} else {
|
||||
valueTextElement.style("display", null);
|
||||
}
|
||||
});
|
||||
}
|
||||
const diagramPadding = config.diagramPadding ?? 8;
|
||||
setupViewPortForSVG(svg, diagramPadding, "flowchart", config?.useMaxWidth || false);
|
||||
}, "draw");
|
||||
var getClasses = /* @__PURE__ */ __name(function(_text, diagramObj) {
|
||||
return diagramObj.db.getClasses();
|
||||
}, "getClasses");
|
||||
var renderer = { draw, getClasses };
|
||||
|
||||
// src/diagrams/treemap/styles.ts
|
||||
var defaultTreemapStyleOptions = {
|
||||
sectionStrokeColor: "black",
|
||||
sectionStrokeWidth: "1",
|
||||
sectionFillColor: "#efefef",
|
||||
leafStrokeColor: "black",
|
||||
leafStrokeWidth: "1",
|
||||
leafFillColor: "#efefef",
|
||||
labelFontSize: "12px",
|
||||
valueFontSize: "10px",
|
||||
titleFontSize: "14px"
|
||||
};
|
||||
var getStyles = /* @__PURE__ */ __name(({
|
||||
treemap: treemap2
|
||||
} = {}) => {
|
||||
const defaultThemeVariables = getThemeVariables();
|
||||
const currentConfig = getConfig();
|
||||
const themeVariables = cleanAndMerge(defaultThemeVariables, currentConfig.themeVariables);
|
||||
const options = cleanAndMerge(defaultTreemapStyleOptions, treemap2);
|
||||
const titleColor = options.titleColor ?? themeVariables.titleColor;
|
||||
const labelColor = options.labelColor ?? themeVariables.textColor;
|
||||
const valueColor = options.valueColor ?? themeVariables.textColor;
|
||||
return `
|
||||
.treemapNode.section {
|
||||
stroke: ${options.sectionStrokeColor};
|
||||
stroke-width: ${options.sectionStrokeWidth};
|
||||
fill: ${options.sectionFillColor};
|
||||
}
|
||||
.treemapNode.leaf {
|
||||
stroke: ${options.leafStrokeColor};
|
||||
stroke-width: ${options.leafStrokeWidth};
|
||||
fill: ${options.leafFillColor};
|
||||
}
|
||||
.treemapLabel {
|
||||
fill: ${labelColor};
|
||||
font-size: ${options.labelFontSize};
|
||||
}
|
||||
.treemapValue {
|
||||
fill: ${valueColor};
|
||||
font-size: ${options.valueFontSize};
|
||||
}
|
||||
.treemapTitle {
|
||||
fill: ${titleColor};
|
||||
font-size: ${options.titleFontSize};
|
||||
}
|
||||
`;
|
||||
}, "getStyles");
|
||||
var styles_default = getStyles;
|
||||
|
||||
// src/diagrams/treemap/diagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
get db() {
|
||||
return new TreeMapDB();
|
||||
},
|
||||
renderer,
|
||||
styles: styles_default
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+335
@@ -0,0 +1,335 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
cleanAndMerge
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
defaultConfig_default,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig,
|
||||
getDiagramTitle,
|
||||
getThemeVariables,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/radar/db.ts
|
||||
var defaultOptions = {
|
||||
showLegend: true,
|
||||
ticks: 5,
|
||||
max: null,
|
||||
min: 0,
|
||||
graticule: "circle"
|
||||
};
|
||||
var defaultRadarData = {
|
||||
axes: [],
|
||||
curves: [],
|
||||
options: defaultOptions
|
||||
};
|
||||
var data = structuredClone(defaultRadarData);
|
||||
var DEFAULT_RADAR_CONFIG = defaultConfig_default.radar;
|
||||
var getConfig2 = /* @__PURE__ */ __name(() => {
|
||||
const config = cleanAndMerge({
|
||||
...DEFAULT_RADAR_CONFIG,
|
||||
...getConfig().radar
|
||||
});
|
||||
return config;
|
||||
}, "getConfig");
|
||||
var getAxes = /* @__PURE__ */ __name(() => data.axes, "getAxes");
|
||||
var getCurves = /* @__PURE__ */ __name(() => data.curves, "getCurves");
|
||||
var getOptions = /* @__PURE__ */ __name(() => data.options, "getOptions");
|
||||
var setAxes = /* @__PURE__ */ __name((axes) => {
|
||||
data.axes = axes.map((axis) => {
|
||||
return {
|
||||
name: axis.name,
|
||||
label: axis.label ?? axis.name
|
||||
};
|
||||
});
|
||||
}, "setAxes");
|
||||
var setCurves = /* @__PURE__ */ __name((curves) => {
|
||||
data.curves = curves.map((curve) => {
|
||||
return {
|
||||
name: curve.name,
|
||||
label: curve.label ?? curve.name,
|
||||
entries: computeCurveEntries(curve.entries)
|
||||
};
|
||||
});
|
||||
}, "setCurves");
|
||||
var computeCurveEntries = /* @__PURE__ */ __name((entries) => {
|
||||
if (entries[0].axis == void 0) {
|
||||
return entries.map((entry) => entry.value);
|
||||
}
|
||||
const axes = getAxes();
|
||||
if (axes.length === 0) {
|
||||
throw new Error("Axes must be populated before curves for reference entries");
|
||||
}
|
||||
return axes.map((axis) => {
|
||||
const entry = entries.find((entry2) => entry2.axis?.$refText === axis.name);
|
||||
if (entry === void 0) {
|
||||
throw new Error("Missing entry for axis " + axis.label);
|
||||
}
|
||||
return entry.value;
|
||||
});
|
||||
}, "computeCurveEntries");
|
||||
var setOptions = /* @__PURE__ */ __name((options) => {
|
||||
const optionMap = options.reduce(
|
||||
(acc, option) => {
|
||||
acc[option.name] = option;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
data.options = {
|
||||
showLegend: optionMap.showLegend?.value ?? defaultOptions.showLegend,
|
||||
ticks: optionMap.ticks?.value ?? defaultOptions.ticks,
|
||||
max: optionMap.max?.value ?? defaultOptions.max,
|
||||
min: optionMap.min?.value ?? defaultOptions.min,
|
||||
graticule: optionMap.graticule?.value ?? defaultOptions.graticule
|
||||
};
|
||||
}, "setOptions");
|
||||
var clear2 = /* @__PURE__ */ __name(() => {
|
||||
clear();
|
||||
data = structuredClone(defaultRadarData);
|
||||
}, "clear");
|
||||
var db = {
|
||||
getAxes,
|
||||
getCurves,
|
||||
getOptions,
|
||||
setAxes,
|
||||
setCurves,
|
||||
setOptions,
|
||||
getConfig: getConfig2,
|
||||
clear: clear2,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription
|
||||
};
|
||||
|
||||
// src/diagrams/radar/parser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
var populate = /* @__PURE__ */ __name((ast) => {
|
||||
populateCommonDb(ast, db);
|
||||
const { axes, curves, options } = ast;
|
||||
db.setAxes(axes);
|
||||
db.setCurves(curves);
|
||||
db.setOptions(options);
|
||||
}, "populate");
|
||||
var parser = {
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("radar", input);
|
||||
log.debug(ast);
|
||||
populate(ast);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/radar/renderer.ts
|
||||
var draw = /* @__PURE__ */ __name((_text, id, _version, diagram2) => {
|
||||
const db2 = diagram2.db;
|
||||
const axes = db2.getAxes();
|
||||
const curves = db2.getCurves();
|
||||
const options = db2.getOptions();
|
||||
const config = db2.getConfig();
|
||||
const title = db2.getDiagramTitle();
|
||||
const svg = selectSvgElement(id);
|
||||
const g = drawFrame(svg, config);
|
||||
const maxValue = options.max ?? Math.max(...curves.map((curve) => Math.max(...curve.entries)));
|
||||
const minValue = options.min;
|
||||
const radius = Math.min(config.width, config.height) / 2;
|
||||
drawGraticule(g, axes, radius, options.ticks, options.graticule);
|
||||
drawAxes(g, axes, radius, config);
|
||||
drawCurves(g, axes, curves, minValue, maxValue, options.graticule, config);
|
||||
drawLegend(g, curves, options.showLegend, config);
|
||||
g.append("text").attr("class", "radarTitle").text(title).attr("x", 0).attr("y", -config.height / 2 - config.marginTop);
|
||||
}, "draw");
|
||||
var drawFrame = /* @__PURE__ */ __name((svg, config) => {
|
||||
const totalWidth = config.width + config.marginLeft + config.marginRight;
|
||||
const totalHeight = config.height + config.marginTop + config.marginBottom;
|
||||
const center = {
|
||||
x: config.marginLeft + config.width / 2,
|
||||
y: config.marginTop + config.height / 2
|
||||
};
|
||||
configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth ?? true);
|
||||
svg.attr("viewBox", `0 0 ${totalWidth} ${totalHeight}`);
|
||||
return svg.append("g").attr("transform", `translate(${center.x}, ${center.y})`);
|
||||
}, "drawFrame");
|
||||
var drawGraticule = /* @__PURE__ */ __name((g, axes, radius, ticks, graticule) => {
|
||||
if (graticule === "circle") {
|
||||
for (let i = 0; i < ticks; i++) {
|
||||
const r = radius * (i + 1) / ticks;
|
||||
g.append("circle").attr("r", r).attr("class", "radarGraticule");
|
||||
}
|
||||
} else if (graticule === "polygon") {
|
||||
const numAxes = axes.length;
|
||||
for (let i = 0; i < ticks; i++) {
|
||||
const r = radius * (i + 1) / ticks;
|
||||
const points = axes.map((_, j) => {
|
||||
const angle = 2 * j * Math.PI / numAxes - Math.PI / 2;
|
||||
const x = r * Math.cos(angle);
|
||||
const y = r * Math.sin(angle);
|
||||
return `${x},${y}`;
|
||||
}).join(" ");
|
||||
g.append("polygon").attr("points", points).attr("class", "radarGraticule");
|
||||
}
|
||||
}
|
||||
}, "drawGraticule");
|
||||
var drawAxes = /* @__PURE__ */ __name((g, axes, radius, config) => {
|
||||
const numAxes = axes.length;
|
||||
for (let i = 0; i < numAxes; i++) {
|
||||
const label = axes[i].label;
|
||||
const angle = 2 * i * Math.PI / numAxes - Math.PI / 2;
|
||||
g.append("line").attr("x1", 0).attr("y1", 0).attr("x2", radius * config.axisScaleFactor * Math.cos(angle)).attr("y2", radius * config.axisScaleFactor * Math.sin(angle)).attr("class", "radarAxisLine");
|
||||
g.append("text").text(label).attr("x", radius * config.axisLabelFactor * Math.cos(angle)).attr("y", radius * config.axisLabelFactor * Math.sin(angle)).attr("class", "radarAxisLabel");
|
||||
}
|
||||
}, "drawAxes");
|
||||
function drawCurves(g, axes, curves, minValue, maxValue, graticule, config) {
|
||||
const numAxes = axes.length;
|
||||
const radius = Math.min(config.width, config.height) / 2;
|
||||
curves.forEach((curve, index) => {
|
||||
if (curve.entries.length !== numAxes) {
|
||||
return;
|
||||
}
|
||||
const points = curve.entries.map((entry, i) => {
|
||||
const angle = 2 * Math.PI * i / numAxes - Math.PI / 2;
|
||||
const r = relativeRadius(entry, minValue, maxValue, radius);
|
||||
const x = r * Math.cos(angle);
|
||||
const y = r * Math.sin(angle);
|
||||
return { x, y };
|
||||
});
|
||||
if (graticule === "circle") {
|
||||
g.append("path").attr("d", closedRoundCurve(points, config.curveTension)).attr("class", `radarCurve-${index}`);
|
||||
} else if (graticule === "polygon") {
|
||||
g.append("polygon").attr("points", points.map((p) => `${p.x},${p.y}`).join(" ")).attr("class", `radarCurve-${index}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
__name(drawCurves, "drawCurves");
|
||||
function relativeRadius(value, minValue, maxValue, radius) {
|
||||
const clippedValue = Math.min(Math.max(value, minValue), maxValue);
|
||||
return radius * (clippedValue - minValue) / (maxValue - minValue);
|
||||
}
|
||||
__name(relativeRadius, "relativeRadius");
|
||||
function closedRoundCurve(points, tension) {
|
||||
const numPoints = points.length;
|
||||
let d = `M${points[0].x},${points[0].y}`;
|
||||
for (let i = 0; i < numPoints; i++) {
|
||||
const p0 = points[(i - 1 + numPoints) % numPoints];
|
||||
const p1 = points[i];
|
||||
const p2 = points[(i + 1) % numPoints];
|
||||
const p3 = points[(i + 2) % numPoints];
|
||||
const cp1 = {
|
||||
x: p1.x + (p2.x - p0.x) * tension,
|
||||
y: p1.y + (p2.y - p0.y) * tension
|
||||
};
|
||||
const cp2 = {
|
||||
x: p2.x - (p3.x - p1.x) * tension,
|
||||
y: p2.y - (p3.y - p1.y) * tension
|
||||
};
|
||||
d += ` C${cp1.x},${cp1.y} ${cp2.x},${cp2.y} ${p2.x},${p2.y}`;
|
||||
}
|
||||
return `${d} Z`;
|
||||
}
|
||||
__name(closedRoundCurve, "closedRoundCurve");
|
||||
function drawLegend(g, curves, showLegend, config) {
|
||||
if (!showLegend) {
|
||||
return;
|
||||
}
|
||||
const legendX = (config.width / 2 + config.marginRight) * 3 / 4;
|
||||
const legendY = -(config.height / 2 + config.marginTop) * 3 / 4;
|
||||
const lineHeight = 20;
|
||||
curves.forEach((curve, index) => {
|
||||
const itemGroup = g.append("g").attr("transform", `translate(${legendX}, ${legendY + index * lineHeight})`);
|
||||
itemGroup.append("rect").attr("width", 12).attr("height", 12).attr("class", `radarLegendBox-${index}`);
|
||||
itemGroup.append("text").attr("x", 16).attr("y", 0).attr("class", "radarLegendText").text(curve.label);
|
||||
});
|
||||
}
|
||||
__name(drawLegend, "drawLegend");
|
||||
var renderer = { draw };
|
||||
|
||||
// src/diagrams/radar/styles.ts
|
||||
var genIndexStyles = /* @__PURE__ */ __name((themeVariables, radarOptions) => {
|
||||
let sections = "";
|
||||
for (let i = 0; i < themeVariables.THEME_COLOR_LIMIT; i++) {
|
||||
const indexColor = themeVariables[`cScale${i}`];
|
||||
sections += `
|
||||
.radarCurve-${i} {
|
||||
color: ${indexColor};
|
||||
fill: ${indexColor};
|
||||
fill-opacity: ${radarOptions.curveOpacity};
|
||||
stroke: ${indexColor};
|
||||
stroke-width: ${radarOptions.curveStrokeWidth};
|
||||
}
|
||||
.radarLegendBox-${i} {
|
||||
fill: ${indexColor};
|
||||
fill-opacity: ${radarOptions.curveOpacity};
|
||||
stroke: ${indexColor};
|
||||
}
|
||||
`;
|
||||
}
|
||||
return sections;
|
||||
}, "genIndexStyles");
|
||||
var buildRadarStyleOptions = /* @__PURE__ */ __name((radar) => {
|
||||
const defaultThemeVariables = getThemeVariables();
|
||||
const currentConfig = getConfig();
|
||||
const themeVariables = cleanAndMerge(defaultThemeVariables, currentConfig.themeVariables);
|
||||
const radarOptions = cleanAndMerge(themeVariables.radar, radar);
|
||||
return { themeVariables, radarOptions };
|
||||
}, "buildRadarStyleOptions");
|
||||
var styles = /* @__PURE__ */ __name(({ radar } = {}) => {
|
||||
const { themeVariables, radarOptions } = buildRadarStyleOptions(radar);
|
||||
return `
|
||||
.radarTitle {
|
||||
font-size: ${themeVariables.fontSize};
|
||||
color: ${themeVariables.titleColor};
|
||||
dominant-baseline: hanging;
|
||||
text-anchor: middle;
|
||||
}
|
||||
.radarAxisLine {
|
||||
stroke: ${radarOptions.axisColor};
|
||||
stroke-width: ${radarOptions.axisStrokeWidth};
|
||||
}
|
||||
.radarAxisLabel {
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
font-size: ${radarOptions.axisLabelFontSize}px;
|
||||
color: ${radarOptions.axisColor};
|
||||
}
|
||||
.radarGraticule {
|
||||
fill: ${radarOptions.graticuleColor};
|
||||
fill-opacity: ${radarOptions.graticuleOpacity};
|
||||
stroke: ${radarOptions.graticuleColor};
|
||||
stroke-width: ${radarOptions.graticuleStrokeWidth};
|
||||
}
|
||||
.radarLegendText {
|
||||
text-anchor: start;
|
||||
font-size: ${radarOptions.legendFontSize}px;
|
||||
dominant-baseline: hanging;
|
||||
}
|
||||
${genIndexStyles(themeVariables, radarOptions)}
|
||||
`;
|
||||
}, "styles");
|
||||
|
||||
// src/diagrams/radar/diagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+245
@@ -0,0 +1,245 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
cleanAndMerge
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
defaultConfig_default,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig,
|
||||
getDiagramTitle,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/packet/db.ts
|
||||
var DEFAULT_PACKET_CONFIG = defaultConfig_default.packet;
|
||||
var PacketDB = class {
|
||||
constructor() {
|
||||
this.packet = [];
|
||||
this.setAccTitle = setAccTitle;
|
||||
this.getAccTitle = getAccTitle;
|
||||
this.setDiagramTitle = setDiagramTitle;
|
||||
this.getDiagramTitle = getDiagramTitle;
|
||||
this.getAccDescription = getAccDescription;
|
||||
this.setAccDescription = setAccDescription;
|
||||
}
|
||||
static {
|
||||
__name(this, "PacketDB");
|
||||
}
|
||||
getConfig() {
|
||||
const config = cleanAndMerge({
|
||||
...DEFAULT_PACKET_CONFIG,
|
||||
...getConfig().packet
|
||||
});
|
||||
if (config.showBits) {
|
||||
config.paddingY += 10;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
getPacket() {
|
||||
return this.packet;
|
||||
}
|
||||
pushWord(word) {
|
||||
if (word.length > 0) {
|
||||
this.packet.push(word);
|
||||
}
|
||||
}
|
||||
clear() {
|
||||
clear();
|
||||
this.packet = [];
|
||||
}
|
||||
};
|
||||
|
||||
// src/diagrams/packet/parser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
var maxPacketSize = 1e4;
|
||||
var populate = /* @__PURE__ */ __name((ast, db) => {
|
||||
populateCommonDb(ast, db);
|
||||
let lastBit = -1;
|
||||
let word = [];
|
||||
let row = 1;
|
||||
const { bitsPerRow } = db.getConfig();
|
||||
for (let { start, end, bits, label } of ast.blocks) {
|
||||
if (start !== void 0 && end !== void 0 && end < start) {
|
||||
throw new Error(`Packet block ${start} - ${end} is invalid. End must be greater than start.`);
|
||||
}
|
||||
start ??= lastBit + 1;
|
||||
if (start !== lastBit + 1) {
|
||||
throw new Error(
|
||||
`Packet block ${start} - ${end ?? start} is not contiguous. It should start from ${lastBit + 1}.`
|
||||
);
|
||||
}
|
||||
if (bits === 0) {
|
||||
throw new Error(`Packet block ${start} is invalid. Cannot have a zero bit field.`);
|
||||
}
|
||||
end ??= start + (bits ?? 1) - 1;
|
||||
bits ??= end - start + 1;
|
||||
lastBit = end;
|
||||
log.debug(`Packet block ${start} - ${lastBit} with label ${label}`);
|
||||
while (word.length <= bitsPerRow + 1 && db.getPacket().length < maxPacketSize) {
|
||||
const [block, nextBlock] = getNextFittingBlock({ start, end, bits, label }, row, bitsPerRow);
|
||||
word.push(block);
|
||||
if (block.end + 1 === row * bitsPerRow) {
|
||||
db.pushWord(word);
|
||||
word = [];
|
||||
row++;
|
||||
}
|
||||
if (!nextBlock) {
|
||||
break;
|
||||
}
|
||||
({ start, end, bits, label } = nextBlock);
|
||||
}
|
||||
}
|
||||
db.pushWord(word);
|
||||
}, "populate");
|
||||
var getNextFittingBlock = /* @__PURE__ */ __name((block, row, bitsPerRow) => {
|
||||
if (block.start === void 0) {
|
||||
throw new Error("start should have been set during first phase");
|
||||
}
|
||||
if (block.end === void 0) {
|
||||
throw new Error("end should have been set during first phase");
|
||||
}
|
||||
if (block.start > block.end) {
|
||||
throw new Error(`Block start ${block.start} is greater than block end ${block.end}.`);
|
||||
}
|
||||
if (block.end + 1 <= row * bitsPerRow) {
|
||||
return [block, void 0];
|
||||
}
|
||||
const rowEnd = row * bitsPerRow - 1;
|
||||
const rowStart = row * bitsPerRow;
|
||||
return [
|
||||
{
|
||||
start: block.start,
|
||||
end: rowEnd,
|
||||
label: block.label,
|
||||
bits: rowEnd - block.start
|
||||
},
|
||||
{
|
||||
start: rowStart,
|
||||
end: block.end,
|
||||
label: block.label,
|
||||
bits: block.end - rowStart
|
||||
}
|
||||
];
|
||||
}, "getNextFittingBlock");
|
||||
var parser = {
|
||||
// @ts-expect-error - PacketDB is not assignable to DiagramDB
|
||||
parser: { yy: void 0 },
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("packet", input);
|
||||
const db = parser.parser?.yy;
|
||||
if (!(db instanceof PacketDB)) {
|
||||
throw new Error(
|
||||
"parser.parser?.yy was not a PacketDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues."
|
||||
);
|
||||
}
|
||||
log.debug(ast);
|
||||
populate(ast, db);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/packet/renderer.ts
|
||||
var draw = /* @__PURE__ */ __name((_text, id, _version, diagram2) => {
|
||||
const db = diagram2.db;
|
||||
const config = db.getConfig();
|
||||
const { rowHeight, paddingY, bitWidth, bitsPerRow } = config;
|
||||
const words = db.getPacket();
|
||||
const title = db.getDiagramTitle();
|
||||
const totalRowHeight = rowHeight + paddingY;
|
||||
const svgHeight = totalRowHeight * (words.length + 1) - (title ? 0 : rowHeight);
|
||||
const svgWidth = bitWidth * bitsPerRow + 2;
|
||||
const svg = selectSvgElement(id);
|
||||
svg.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth);
|
||||
for (const [word, packet] of words.entries()) {
|
||||
drawWord(svg, packet, word, config);
|
||||
}
|
||||
svg.append("text").text(title).attr("x", svgWidth / 2).attr("y", svgHeight - totalRowHeight / 2).attr("dominant-baseline", "middle").attr("text-anchor", "middle").attr("class", "packetTitle");
|
||||
}, "draw");
|
||||
var drawWord = /* @__PURE__ */ __name((svg, word, rowNumber, { rowHeight, paddingX, paddingY, bitWidth, bitsPerRow, showBits }) => {
|
||||
const group = svg.append("g");
|
||||
const wordY = rowNumber * (rowHeight + paddingY) + paddingY;
|
||||
for (const block of word) {
|
||||
const blockX = block.start % bitsPerRow * bitWidth + 1;
|
||||
const width = (block.end - block.start + 1) * bitWidth - paddingX;
|
||||
group.append("rect").attr("x", blockX).attr("y", wordY).attr("width", width).attr("height", rowHeight).attr("class", "packetBlock");
|
||||
group.append("text").attr("x", blockX + width / 2).attr("y", wordY + rowHeight / 2).attr("class", "packetLabel").attr("dominant-baseline", "middle").attr("text-anchor", "middle").text(block.label);
|
||||
if (!showBits) {
|
||||
continue;
|
||||
}
|
||||
const isSingleBlock = block.end === block.start;
|
||||
const bitNumberY = wordY - 2;
|
||||
group.append("text").attr("x", blockX + (isSingleBlock ? width / 2 : 0)).attr("y", bitNumberY).attr("class", "packetByte start").attr("dominant-baseline", "auto").attr("text-anchor", isSingleBlock ? "middle" : "start").text(block.start);
|
||||
if (!isSingleBlock) {
|
||||
group.append("text").attr("x", blockX + width).attr("y", bitNumberY).attr("class", "packetByte end").attr("dominant-baseline", "auto").attr("text-anchor", "end").text(block.end);
|
||||
}
|
||||
}
|
||||
}, "drawWord");
|
||||
var renderer = { draw };
|
||||
|
||||
// src/diagrams/packet/styles.ts
|
||||
var defaultPacketStyleOptions = {
|
||||
byteFontSize: "10px",
|
||||
startByteColor: "black",
|
||||
endByteColor: "black",
|
||||
labelColor: "black",
|
||||
labelFontSize: "12px",
|
||||
titleColor: "black",
|
||||
titleFontSize: "14px",
|
||||
blockStrokeColor: "black",
|
||||
blockStrokeWidth: "1",
|
||||
blockFillColor: "#efefef"
|
||||
};
|
||||
var styles = /* @__PURE__ */ __name(({ packet } = {}) => {
|
||||
const options = cleanAndMerge(defaultPacketStyleOptions, packet);
|
||||
return `
|
||||
.packetByte {
|
||||
font-size: ${options.byteFontSize};
|
||||
}
|
||||
.packetByte.start {
|
||||
fill: ${options.startByteColor};
|
||||
}
|
||||
.packetByte.end {
|
||||
fill: ${options.endByteColor};
|
||||
}
|
||||
.packetLabel {
|
||||
fill: ${options.labelColor};
|
||||
font-size: ${options.labelFontSize};
|
||||
}
|
||||
.packetTitle {
|
||||
fill: ${options.titleColor};
|
||||
font-size: ${options.titleFontSize};
|
||||
}
|
||||
.packetBlock {
|
||||
stroke: ${options.blockStrokeColor};
|
||||
stroke-width: ${options.blockStrokeWidth};
|
||||
fill: ${options.blockFillColor};
|
||||
}
|
||||
`;
|
||||
}, "styles");
|
||||
|
||||
// src/diagrams/packet/diagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
get db() {
|
||||
return new PacketDB();
|
||||
},
|
||||
renderer,
|
||||
styles
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
+1351
File diff suppressed because it is too large
Load Diff
+7
File diff suppressed because one or more lines are too long
+2507
File diff suppressed because one or more lines are too long
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+2310
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+1940
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+48
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
configureSvgSize
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/info/infoParser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
var parser = {
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("info", input);
|
||||
log.debug(ast);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/info/infoDb.ts
|
||||
var DEFAULT_INFO_DB = {
|
||||
version: "11.14.0" + (true ? "" : "-tiny")
|
||||
};
|
||||
var getVersion = /* @__PURE__ */ __name(() => DEFAULT_INFO_DB.version, "getVersion");
|
||||
var db = {
|
||||
getVersion
|
||||
};
|
||||
|
||||
// src/diagrams/info/infoRenderer.ts
|
||||
var draw = /* @__PURE__ */ __name((text, id, version) => {
|
||||
log.debug("rendering info diagram\n" + text);
|
||||
const svg = selectSvgElement(id);
|
||||
configureSvgSize(svg, 100, 400, true);
|
||||
const group = svg.append("g");
|
||||
group.append("text").attr("x", 100).attr("y", 40).attr("class", "version").attr("font-size", 32).style("text-anchor", "middle").text(`v${version}`);
|
||||
}, "draw");
|
||||
var renderer = { draw };
|
||||
|
||||
// src/diagrams/info/infoDiagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
db,
|
||||
renderer
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/info/infoParser.ts", "../../../src/diagrams/info/infoDb.ts", "../../../src/diagrams/info/infoRenderer.ts", "../../../src/diagrams/info/infoDiagram.ts"],
|
||||
"sourcesContent": ["import type { Info } from '@mermaid-js/parser';\nimport { parse } from '@mermaid-js/parser';\nimport type { ParserDefinition } from '../../diagram-api/types.js';\nimport { log } from '../../logger.js';\n\nexport const parser: ParserDefinition = {\n parse: async (input: string): Promise<void> => {\n const ast: Info = await parse('info', input);\n log.debug(ast);\n },\n};\n", "import type { InfoFields, InfoDB } from './infoTypes.js';\n\nexport const DEFAULT_INFO_DB: InfoFields = {\n version: injected.version + (injected.includeLargeFeatures ? '' : '-tiny'),\n} as const;\n\nexport const getVersion = (): string => DEFAULT_INFO_DB.version;\n\nexport const db: InfoDB = {\n getVersion,\n};\n", "import type { DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js';\nimport { log } from '../../logger.js';\nimport { selectSvgElement } from '../../rendering-util/selectSvgElement.js';\nimport { configureSvgSize } from '../../setupGraphViewbox.js';\n\n/**\n * Draws an info picture in the tag with id: id based on the graph definition in text.\n *\n * @param text - The text of the diagram.\n * @param id - The id of the diagram which will be used as a DOM element id.\n * @param version - MermaidJS version.\n */\nconst draw: DrawDefinition = (text, id, version) => {\n log.debug('rendering info diagram\\n' + text);\n\n const svg: SVG = selectSvgElement(id);\n configureSvgSize(svg, 100, 400, true);\n\n const group: SVGGroup = svg.append('g');\n group\n .append('text')\n .attr('x', 100)\n .attr('y', 40)\n .attr('class', 'version')\n .attr('font-size', 32)\n .style('text-anchor', 'middle')\n .text(`v${version}`);\n};\n\nexport const renderer = { draw };\n", "import type { DiagramDefinition } from '../../diagram-api/types.js';\nimport { parser } from './infoParser.js';\nimport { db } from './infoDb.js';\nimport { renderer } from './infoRenderer.js';\n\nexport const diagram: DiagramDefinition = {\n parser,\n db,\n renderer,\n};\n"],
|
||||
"mappings": ";;;;;;;;;;;;AACA,SAAS,aAAa;AAIf,IAAM,SAA2B;AAAA,EACtC,OAAO,8BAAO,UAAiC;AAC7C,UAAM,MAAY,MAAM,MAAM,QAAQ,KAAK;AAC3C,QAAI,MAAM,GAAG;AAAA,EACf,GAHO;AAIT;;;ACRO,IAAM,kBAA8B;AAAA,EACzC,SAAS,aAAoB,OAAgC,KAAK;AACpE;AAEO,IAAM,aAAa,6BAAc,gBAAgB,SAA9B;AAEnB,IAAM,KAAa;AAAA,EACxB;AACF;;;ACEA,IAAM,OAAuB,wBAAC,MAAM,IAAI,YAAY;AAClD,MAAI,MAAM,6BAA6B,IAAI;AAE3C,QAAM,MAAW,iBAAiB,EAAE;AACpC,mBAAiB,KAAK,KAAK,KAAK,IAAI;AAEpC,QAAM,QAAkB,IAAI,OAAO,GAAG;AACtC,QACG,OAAO,MAAM,EACb,KAAK,KAAK,GAAG,EACb,KAAK,KAAK,EAAE,EACZ,KAAK,SAAS,SAAS,EACvB,KAAK,aAAa,EAAE,EACpB,MAAM,eAAe,QAAQ,EAC7B,KAAK,IAAI,OAAO,EAAE;AACvB,GAf6B;AAiBtB,IAAM,WAAW,EAAE,KAAK;;;ACxBxB,IAAM,UAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF;",
|
||||
"names": []
|
||||
}
|
||||
Generated
Vendored
+1014
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+1312
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+1132
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+1231
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+228
@@ -0,0 +1,228 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
cleanAndMerge,
|
||||
parseFontSize
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
defaultConfig_default,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig2 as getConfig,
|
||||
getDiagramTitle,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/pie/pieParser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
|
||||
// src/diagrams/pie/pieDb.ts
|
||||
var DEFAULT_PIE_CONFIG = defaultConfig_default.pie;
|
||||
var DEFAULT_PIE_DB = {
|
||||
sections: /* @__PURE__ */ new Map(),
|
||||
showData: false,
|
||||
config: DEFAULT_PIE_CONFIG
|
||||
};
|
||||
var sections = DEFAULT_PIE_DB.sections;
|
||||
var showData = DEFAULT_PIE_DB.showData;
|
||||
var config = structuredClone(DEFAULT_PIE_CONFIG);
|
||||
var getConfig2 = /* @__PURE__ */ __name(() => structuredClone(config), "getConfig");
|
||||
var clear2 = /* @__PURE__ */ __name(() => {
|
||||
sections = /* @__PURE__ */ new Map();
|
||||
showData = DEFAULT_PIE_DB.showData;
|
||||
clear();
|
||||
}, "clear");
|
||||
var addSection = /* @__PURE__ */ __name(({ label, value }) => {
|
||||
if (value < 0) {
|
||||
throw new Error(
|
||||
`"${label}" has invalid value: ${value}. Negative values are not allowed in pie charts. All slice values must be >= 0.`
|
||||
);
|
||||
}
|
||||
if (!sections.has(label)) {
|
||||
sections.set(label, value);
|
||||
log.debug(`added new section: ${label}, with value: ${value}`);
|
||||
}
|
||||
}, "addSection");
|
||||
var getSections = /* @__PURE__ */ __name(() => sections, "getSections");
|
||||
var setShowData = /* @__PURE__ */ __name((toggle) => {
|
||||
showData = toggle;
|
||||
}, "setShowData");
|
||||
var getShowData = /* @__PURE__ */ __name(() => showData, "getShowData");
|
||||
var db = {
|
||||
getConfig: getConfig2,
|
||||
clear: clear2,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setAccDescription,
|
||||
getAccDescription,
|
||||
addSection,
|
||||
getSections,
|
||||
setShowData,
|
||||
getShowData
|
||||
};
|
||||
|
||||
// src/diagrams/pie/pieParser.ts
|
||||
var populateDb = /* @__PURE__ */ __name((ast, db2) => {
|
||||
populateCommonDb(ast, db2);
|
||||
db2.setShowData(ast.showData);
|
||||
ast.sections.map(db2.addSection);
|
||||
}, "populateDb");
|
||||
var parser = {
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("pie", input);
|
||||
log.debug(ast);
|
||||
populateDb(ast, db);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/pie/pieStyles.ts
|
||||
var getStyles = /* @__PURE__ */ __name((options) => `
|
||||
.pieCircle{
|
||||
stroke: ${options.pieStrokeColor};
|
||||
stroke-width : ${options.pieStrokeWidth};
|
||||
opacity : ${options.pieOpacity};
|
||||
}
|
||||
.pieOuterCircle{
|
||||
stroke: ${options.pieOuterStrokeColor};
|
||||
stroke-width: ${options.pieOuterStrokeWidth};
|
||||
fill: none;
|
||||
}
|
||||
.pieTitleText {
|
||||
text-anchor: middle;
|
||||
font-size: ${options.pieTitleTextSize};
|
||||
fill: ${options.pieTitleTextColor};
|
||||
font-family: ${options.fontFamily};
|
||||
}
|
||||
.slice {
|
||||
font-family: ${options.fontFamily};
|
||||
fill: ${options.pieSectionTextColor};
|
||||
font-size:${options.pieSectionTextSize};
|
||||
// fill: white;
|
||||
}
|
||||
.legend text {
|
||||
fill: ${options.pieLegendTextColor};
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: ${options.pieLegendTextSize};
|
||||
}
|
||||
`, "getStyles");
|
||||
var pieStyles_default = getStyles;
|
||||
|
||||
// src/diagrams/pie/pieRenderer.ts
|
||||
import { arc, pie as d3pie, scaleOrdinal } from "d3";
|
||||
var createPieArcs = /* @__PURE__ */ __name((sections2) => {
|
||||
const sum = [...sections2.values()].reduce((acc, val) => acc + val, 0);
|
||||
const pieData = [...sections2.entries()].map(([label, value]) => ({ label, value })).filter((d) => d.value / sum * 100 >= 1);
|
||||
const pie = d3pie().value((d) => d.value).sort(null);
|
||||
return pie(pieData);
|
||||
}, "createPieArcs");
|
||||
var draw = /* @__PURE__ */ __name((text, id, _version, diagObj) => {
|
||||
log.debug("rendering pie chart\n" + text);
|
||||
const db2 = diagObj.db;
|
||||
const globalConfig = getConfig();
|
||||
const pieConfig = cleanAndMerge(db2.getConfig(), globalConfig.pie);
|
||||
const MARGIN = 40;
|
||||
const LEGEND_RECT_SIZE = 18;
|
||||
const LEGEND_SPACING = 4;
|
||||
const height = 450;
|
||||
const pieWidth = height;
|
||||
const svg = selectSvgElement(id);
|
||||
const group = svg.append("g");
|
||||
group.attr("transform", "translate(" + pieWidth / 2 + "," + height / 2 + ")");
|
||||
const { themeVariables } = globalConfig;
|
||||
let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth);
|
||||
outerStrokeWidth ??= 2;
|
||||
const textPosition = pieConfig.textPosition;
|
||||
const radius = Math.min(pieWidth, height) / 2 - MARGIN;
|
||||
const arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
||||
const labelArcGenerator = arc().innerRadius(radius * textPosition).outerRadius(radius * textPosition);
|
||||
group.append("circle").attr("cx", 0).attr("cy", 0).attr("r", radius + outerStrokeWidth / 2).attr("class", "pieOuterCircle");
|
||||
const sections2 = db2.getSections();
|
||||
const arcs = createPieArcs(sections2);
|
||||
const myGeneratedColors = [
|
||||
themeVariables.pie1,
|
||||
themeVariables.pie2,
|
||||
themeVariables.pie3,
|
||||
themeVariables.pie4,
|
||||
themeVariables.pie5,
|
||||
themeVariables.pie6,
|
||||
themeVariables.pie7,
|
||||
themeVariables.pie8,
|
||||
themeVariables.pie9,
|
||||
themeVariables.pie10,
|
||||
themeVariables.pie11,
|
||||
themeVariables.pie12
|
||||
];
|
||||
let sum = 0;
|
||||
sections2.forEach((section) => {
|
||||
sum += section;
|
||||
});
|
||||
const filteredArcs = arcs.filter((datum) => (datum.data.value / sum * 100).toFixed(0) !== "0");
|
||||
const color = scaleOrdinal(myGeneratedColors).domain([
|
||||
...sections2.keys()
|
||||
]);
|
||||
group.selectAll("mySlices").data(filteredArcs).enter().append("path").attr("d", arcGenerator).attr("fill", (datum) => {
|
||||
return color(datum.data.label);
|
||||
}).attr("class", "pieCircle");
|
||||
group.selectAll("mySlices").data(filteredArcs).enter().append("text").text((datum) => {
|
||||
return (datum.data.value / sum * 100).toFixed(0) + "%";
|
||||
}).attr("transform", (datum) => {
|
||||
return "translate(" + labelArcGenerator.centroid(datum) + ")";
|
||||
}).style("text-anchor", "middle").attr("class", "slice");
|
||||
const titleText = group.append("text").text(db2.getDiagramTitle()).attr("x", 0).attr("y", -(height - 50) / 2).attr("class", "pieTitleText");
|
||||
const allSectionData = [...sections2.entries()].map(([label, value]) => ({
|
||||
label,
|
||||
value
|
||||
}));
|
||||
const legend = group.selectAll(".legend").data(allSectionData).enter().append("g").attr("class", "legend").attr("transform", (_datum, index) => {
|
||||
const height2 = LEGEND_RECT_SIZE + LEGEND_SPACING;
|
||||
const offset = height2 * allSectionData.length / 2;
|
||||
const horizontal = 12 * LEGEND_RECT_SIZE;
|
||||
const vertical = index * height2 - offset;
|
||||
return "translate(" + horizontal + "," + vertical + ")";
|
||||
});
|
||||
legend.append("rect").attr("width", LEGEND_RECT_SIZE).attr("height", LEGEND_RECT_SIZE).style("fill", (d) => color(d.label)).style("stroke", (d) => color(d.label));
|
||||
legend.append("text").attr("x", LEGEND_RECT_SIZE + LEGEND_SPACING).attr("y", LEGEND_RECT_SIZE - LEGEND_SPACING).text((d) => {
|
||||
if (db2.getShowData()) {
|
||||
return `${d.label} [${d.value}]`;
|
||||
}
|
||||
return d.label;
|
||||
});
|
||||
const longestTextWidth = Math.max(
|
||||
...legend.selectAll("text").nodes().map((node) => node?.getBoundingClientRect().width ?? 0)
|
||||
);
|
||||
const chartAndLegendWidth = pieWidth + MARGIN + LEGEND_RECT_SIZE + LEGEND_SPACING + longestTextWidth;
|
||||
const titleWidth = titleText.node()?.getBoundingClientRect().width ?? 0;
|
||||
const titleLeft = pieWidth / 2 - titleWidth / 2;
|
||||
const titleRight = pieWidth / 2 + titleWidth / 2;
|
||||
const viewBoxX = Math.min(0, titleLeft);
|
||||
const viewBoxRight = Math.max(chartAndLegendWidth, titleRight);
|
||||
const totalWidth = viewBoxRight - viewBoxX;
|
||||
svg.attr("viewBox", `${viewBoxX} 0 ${totalWidth} ${height}`);
|
||||
configureSvgSize(svg, height, totalWidth, pieConfig.useMaxWidth);
|
||||
}, "draw");
|
||||
var renderer = { draw };
|
||||
|
||||
// src/diagrams/pie/pieDiagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles: pieStyles_default
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+1417
File diff suppressed because one or more lines are too long
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+1314
File diff suppressed because one or more lines are too long
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+736
@@ -0,0 +1,736 @@
|
||||
import {
|
||||
clear,
|
||||
common_default,
|
||||
defaultConfig2 as defaultConfig,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig2 as getConfig,
|
||||
getDiagramTitle,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle,
|
||||
setupGraphViewbox
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/sankey/parser/sankey.jison
|
||||
var parser = (function() {
|
||||
var o = /* @__PURE__ */ __name(function(k, v, o2, l) {
|
||||
for (o2 = o2 || {}, l = k.length; l--; o2[k[l]] = v) ;
|
||||
return o2;
|
||||
}, "o"), $V0 = [1, 9], $V1 = [1, 10], $V2 = [1, 5, 10, 12];
|
||||
var parser2 = {
|
||||
trace: /* @__PURE__ */ __name(function trace() {
|
||||
}, "trace"),
|
||||
yy: {},
|
||||
symbols_: { "error": 2, "start": 3, "SANKEY": 4, "NEWLINE": 5, "csv": 6, "opt_eof": 7, "record": 8, "csv_tail": 9, "EOF": 10, "field[source]": 11, "COMMA": 12, "field[target]": 13, "field[value]": 14, "field": 15, "escaped": 16, "non_escaped": 17, "DQUOTE": 18, "ESCAPED_TEXT": 19, "NON_ESCAPED_TEXT": 20, "$accept": 0, "$end": 1 },
|
||||
terminals_: { 2: "error", 4: "SANKEY", 5: "NEWLINE", 10: "EOF", 11: "field[source]", 12: "COMMA", 13: "field[target]", 14: "field[value]", 18: "DQUOTE", 19: "ESCAPED_TEXT", 20: "NON_ESCAPED_TEXT" },
|
||||
productions_: [0, [3, 4], [6, 2], [9, 2], [9, 0], [7, 1], [7, 0], [8, 5], [15, 1], [15, 1], [16, 3], [17, 1]],
|
||||
performAction: /* @__PURE__ */ __name(function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 7:
|
||||
const source = yy.findOrCreateNode($$[$0 - 4].trim().replaceAll('""', '"'));
|
||||
const target = yy.findOrCreateNode($$[$0 - 2].trim().replaceAll('""', '"'));
|
||||
const value = parseFloat($$[$0].trim());
|
||||
yy.addLink(source, target, value);
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 11:
|
||||
this.$ = $$[$0];
|
||||
break;
|
||||
case 10:
|
||||
this.$ = $$[$0 - 1];
|
||||
break;
|
||||
}
|
||||
}, "anonymous"),
|
||||
table: [{ 3: 1, 4: [1, 2] }, { 1: [3] }, { 5: [1, 3] }, { 6: 4, 8: 5, 15: 6, 16: 7, 17: 8, 18: $V0, 20: $V1 }, { 1: [2, 6], 7: 11, 10: [1, 12] }, o($V1, [2, 4], { 9: 13, 5: [1, 14] }), { 12: [1, 15] }, o($V2, [2, 8]), o($V2, [2, 9]), { 19: [1, 16] }, o($V2, [2, 11]), { 1: [2, 1] }, { 1: [2, 5] }, o($V1, [2, 2]), { 6: 17, 8: 5, 15: 6, 16: 7, 17: 8, 18: $V0, 20: $V1 }, { 15: 18, 16: 7, 17: 8, 18: $V0, 20: $V1 }, { 18: [1, 19] }, o($V1, [2, 3]), { 12: [1, 20] }, o($V2, [2, 10]), { 15: 21, 16: 7, 17: 8, 18: $V0, 20: $V1 }, o([1, 5, 10], [2, 7])],
|
||||
defaultActions: { 11: [2, 1], 12: [2, 5] },
|
||||
parseError: /* @__PURE__ */ __name(function parseError(str, hash) {
|
||||
if (hash.recoverable) {
|
||||
this.trace(str);
|
||||
} else {
|
||||
var error = new Error(str);
|
||||
error.hash = hash;
|
||||
throw error;
|
||||
}
|
||||
}, "parseError"),
|
||||
parse: /* @__PURE__ */ __name(function parse(input) {
|
||||
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
||||
var args = lstack.slice.call(arguments, 1);
|
||||
var lexer2 = Object.create(this.lexer);
|
||||
var sharedState = { yy: {} };
|
||||
for (var k in this.yy) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
|
||||
sharedState.yy[k] = this.yy[k];
|
||||
}
|
||||
}
|
||||
lexer2.setInput(input, sharedState.yy);
|
||||
sharedState.yy.lexer = lexer2;
|
||||
sharedState.yy.parser = this;
|
||||
if (typeof lexer2.yylloc == "undefined") {
|
||||
lexer2.yylloc = {};
|
||||
}
|
||||
var yyloc = lexer2.yylloc;
|
||||
lstack.push(yyloc);
|
||||
var ranges = lexer2.options && lexer2.options.ranges;
|
||||
if (typeof sharedState.yy.parseError === "function") {
|
||||
this.parseError = sharedState.yy.parseError;
|
||||
} else {
|
||||
this.parseError = Object.getPrototypeOf(this).parseError;
|
||||
}
|
||||
function popStack(n) {
|
||||
stack.length = stack.length - 2 * n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
__name(popStack, "popStack");
|
||||
function lex() {
|
||||
var token;
|
||||
token = tstack.pop() || lexer2.lex() || EOF;
|
||||
if (typeof token !== "number") {
|
||||
if (token instanceof Array) {
|
||||
tstack = token;
|
||||
token = tstack.pop();
|
||||
}
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
__name(lex, "lex");
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
||||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol === null || typeof symbol == "undefined") {
|
||||
symbol = lex();
|
||||
}
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
if (typeof action === "undefined" || !action.length || !action[0]) {
|
||||
var errStr = "";
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p > TERROR) {
|
||||
expected.push("'" + this.terminals_[p] + "'");
|
||||
}
|
||||
}
|
||||
if (lexer2.showPosition) {
|
||||
errStr = "Parse error on line " + (yylineno + 1) + ":\n" + lexer2.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
|
||||
} else {
|
||||
errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == EOF ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
|
||||
}
|
||||
this.parseError(errStr, {
|
||||
text: lexer2.match,
|
||||
token: this.terminals_[symbol] || symbol,
|
||||
line: lexer2.yylineno,
|
||||
loc: yyloc,
|
||||
expected
|
||||
});
|
||||
}
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
||||
}
|
||||
switch (action[0]) {
|
||||
case 1:
|
||||
stack.push(symbol);
|
||||
vstack.push(lexer2.yytext);
|
||||
lstack.push(lexer2.yylloc);
|
||||
stack.push(action[1]);
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) {
|
||||
yyleng = lexer2.yyleng;
|
||||
yytext = lexer2.yytext;
|
||||
yylineno = lexer2.yylineno;
|
||||
yyloc = lexer2.yylloc;
|
||||
if (recovering > 0) {
|
||||
recovering--;
|
||||
}
|
||||
} else {
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
len = this.productions_[action[1]][1];
|
||||
yyval.$ = vstack[vstack.length - len];
|
||||
yyval._$ = {
|
||||
first_line: lstack[lstack.length - (len || 1)].first_line,
|
||||
last_line: lstack[lstack.length - 1].last_line,
|
||||
first_column: lstack[lstack.length - (len || 1)].first_column,
|
||||
last_column: lstack[lstack.length - 1].last_column
|
||||
};
|
||||
if (ranges) {
|
||||
yyval._$.range = [
|
||||
lstack[lstack.length - (len || 1)].range[0],
|
||||
lstack[lstack.length - 1].range[1]
|
||||
];
|
||||
}
|
||||
r = this.performAction.apply(yyval, [
|
||||
yytext,
|
||||
yyleng,
|
||||
yylineno,
|
||||
sharedState.yy,
|
||||
action[1],
|
||||
vstack,
|
||||
lstack
|
||||
].concat(args));
|
||||
if (typeof r !== "undefined") {
|
||||
return r;
|
||||
}
|
||||
if (len) {
|
||||
stack = stack.slice(0, -1 * len * 2);
|
||||
vstack = vstack.slice(0, -1 * len);
|
||||
lstack = lstack.slice(0, -1 * len);
|
||||
}
|
||||
stack.push(this.productions_[action[1]][0]);
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
case 3:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, "parse")
|
||||
};
|
||||
var lexer = /* @__PURE__ */ (function() {
|
||||
var lexer2 = {
|
||||
EOF: 1,
|
||||
parseError: /* @__PURE__ */ __name(function parseError(str, hash) {
|
||||
if (this.yy.parser) {
|
||||
this.yy.parser.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
}, "parseError"),
|
||||
// resets the lexer, sets new input
|
||||
setInput: /* @__PURE__ */ __name(function(input, yy) {
|
||||
this.yy = yy || this.yy || {};
|
||||
this._input = input;
|
||||
this._more = this._backtrack = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = "";
|
||||
this.conditionStack = ["INITIAL"];
|
||||
this.yylloc = {
|
||||
first_line: 1,
|
||||
first_column: 0,
|
||||
last_line: 1,
|
||||
last_column: 0
|
||||
};
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [0, 0];
|
||||
}
|
||||
this.offset = 0;
|
||||
return this;
|
||||
}, "setInput"),
|
||||
// consumes and returns one char from the input
|
||||
input: /* @__PURE__ */ __name(function() {
|
||||
var ch = this._input[0];
|
||||
this.yytext += ch;
|
||||
this.yyleng++;
|
||||
this.offset++;
|
||||
this.match += ch;
|
||||
this.matched += ch;
|
||||
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) {
|
||||
this.yylineno++;
|
||||
this.yylloc.last_line++;
|
||||
} else {
|
||||
this.yylloc.last_column++;
|
||||
}
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range[1]++;
|
||||
}
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
}, "input"),
|
||||
// unshifts one char (or a string) into the input
|
||||
unput: /* @__PURE__ */ __name(function(ch) {
|
||||
var len = ch.length;
|
||||
var lines = ch.split(/(?:\r\n?|\n)/g);
|
||||
this._input = ch + this._input;
|
||||
this.yytext = this.yytext.substr(0, this.yytext.length - len);
|
||||
this.offset -= len;
|
||||
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
||||
this.match = this.match.substr(0, this.match.length - 1);
|
||||
this.matched = this.matched.substr(0, this.matched.length - 1);
|
||||
if (lines.length - 1) {
|
||||
this.yylineno -= lines.length - 1;
|
||||
}
|
||||
var r = this.yylloc.range;
|
||||
this.yylloc = {
|
||||
first_line: this.yylloc.first_line,
|
||||
last_line: this.yylineno + 1,
|
||||
first_column: this.yylloc.first_column,
|
||||
last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
|
||||
};
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
||||
}
|
||||
this.yyleng = this.yytext.length;
|
||||
return this;
|
||||
}, "unput"),
|
||||
// When called from action, caches matched text and appends it on next action
|
||||
more: /* @__PURE__ */ __name(function() {
|
||||
this._more = true;
|
||||
return this;
|
||||
}, "more"),
|
||||
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
||||
reject: /* @__PURE__ */ __name(function() {
|
||||
if (this.options.backtrack_lexer) {
|
||||
this._backtrack = true;
|
||||
} else {
|
||||
return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n" + this.showPosition(), {
|
||||
text: "",
|
||||
token: null,
|
||||
line: this.yylineno
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}, "reject"),
|
||||
// retain first n characters of the match
|
||||
less: /* @__PURE__ */ __name(function(n) {
|
||||
this.unput(this.match.slice(n));
|
||||
}, "less"),
|
||||
// displays already matched input, i.e. for error messages
|
||||
pastInput: /* @__PURE__ */ __name(function() {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
|
||||
}, "pastInput"),
|
||||
// displays upcoming input, i.e. for error messages
|
||||
upcomingInput: /* @__PURE__ */ __name(function() {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20 - next.length);
|
||||
}
|
||||
return (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
|
||||
}, "upcomingInput"),
|
||||
// displays the character position where the lexing error occurred, i.e. for error messages
|
||||
showPosition: /* @__PURE__ */ __name(function() {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c + "^";
|
||||
}, "showPosition"),
|
||||
// test the lexed token: return FALSE when not a match, otherwise return token
|
||||
test_match: /* @__PURE__ */ __name(function(match, indexed_rule) {
|
||||
var token, lines, backup;
|
||||
if (this.options.backtrack_lexer) {
|
||||
backup = {
|
||||
yylineno: this.yylineno,
|
||||
yylloc: {
|
||||
first_line: this.yylloc.first_line,
|
||||
last_line: this.last_line,
|
||||
first_column: this.yylloc.first_column,
|
||||
last_column: this.yylloc.last_column
|
||||
},
|
||||
yytext: this.yytext,
|
||||
match: this.match,
|
||||
matches: this.matches,
|
||||
matched: this.matched,
|
||||
yyleng: this.yyleng,
|
||||
offset: this.offset,
|
||||
_more: this._more,
|
||||
_input: this._input,
|
||||
yy: this.yy,
|
||||
conditionStack: this.conditionStack.slice(0),
|
||||
done: this.done
|
||||
};
|
||||
if (this.options.ranges) {
|
||||
backup.yylloc.range = this.yylloc.range.slice(0);
|
||||
}
|
||||
}
|
||||
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) {
|
||||
this.yylineno += lines.length;
|
||||
}
|
||||
this.yylloc = {
|
||||
first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno + 1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length
|
||||
};
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.matches = match;
|
||||
this.yyleng = this.yytext.length;
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
||||
}
|
||||
this._more = false;
|
||||
this._backtrack = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
|
||||
if (this.done && this._input) {
|
||||
this.done = false;
|
||||
}
|
||||
if (token) {
|
||||
return token;
|
||||
} else if (this._backtrack) {
|
||||
for (var k in backup) {
|
||||
this[k] = backup[k];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}, "test_match"),
|
||||
// return next match in input
|
||||
next: /* @__PURE__ */ __name(function() {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) {
|
||||
this.done = true;
|
||||
}
|
||||
var token, match, tempMatch, index;
|
||||
if (!this._more) {
|
||||
this.yytext = "";
|
||||
this.match = "";
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (this.options.backtrack_lexer) {
|
||||
token = this.test_match(tempMatch, rules[i]);
|
||||
if (token !== false) {
|
||||
return token;
|
||||
} else if (this._backtrack) {
|
||||
match = false;
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (!this.options.flex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
token = this.test_match(match, rules[index]);
|
||||
if (token !== false) {
|
||||
return token;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), {
|
||||
text: "",
|
||||
token: null,
|
||||
line: this.yylineno
|
||||
});
|
||||
}
|
||||
}, "next"),
|
||||
// return next match that has a token
|
||||
lex: /* @__PURE__ */ __name(function lex() {
|
||||
var r = this.next();
|
||||
if (r) {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
}, "lex"),
|
||||
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
|
||||
begin: /* @__PURE__ */ __name(function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
}, "begin"),
|
||||
// pop the previously active lexer condition state off the condition stack
|
||||
popState: /* @__PURE__ */ __name(function popState() {
|
||||
var n = this.conditionStack.length - 1;
|
||||
if (n > 0) {
|
||||
return this.conditionStack.pop();
|
||||
} else {
|
||||
return this.conditionStack[0];
|
||||
}
|
||||
}, "popState"),
|
||||
// produce the lexer rule set which is active for the currently active lexer condition state
|
||||
_currentRules: /* @__PURE__ */ __name(function _currentRules() {
|
||||
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
|
||||
} else {
|
||||
return this.conditions["INITIAL"].rules;
|
||||
}
|
||||
}, "_currentRules"),
|
||||
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
|
||||
topState: /* @__PURE__ */ __name(function topState(n) {
|
||||
n = this.conditionStack.length - 1 - Math.abs(n || 0);
|
||||
if (n >= 0) {
|
||||
return this.conditionStack[n];
|
||||
} else {
|
||||
return "INITIAL";
|
||||
}
|
||||
}, "topState"),
|
||||
// alias for begin(condition)
|
||||
pushState: /* @__PURE__ */ __name(function pushState(condition) {
|
||||
this.begin(condition);
|
||||
}, "pushState"),
|
||||
// return the number of states currently on the stack
|
||||
stateStackSize: /* @__PURE__ */ __name(function stateStackSize() {
|
||||
return this.conditionStack.length;
|
||||
}, "stateStackSize"),
|
||||
options: { "case-insensitive": true },
|
||||
performAction: /* @__PURE__ */ __name(function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
|
||||
var YYSTATE = YY_START;
|
||||
switch ($avoiding_name_collisions) {
|
||||
case 0:
|
||||
this.pushState("csv");
|
||||
return 4;
|
||||
break;
|
||||
case 1:
|
||||
this.pushState("csv");
|
||||
return 4;
|
||||
break;
|
||||
case 2:
|
||||
return 10;
|
||||
break;
|
||||
case 3:
|
||||
return 5;
|
||||
break;
|
||||
case 4:
|
||||
return 12;
|
||||
break;
|
||||
case 5:
|
||||
this.pushState("escaped_text");
|
||||
return 18;
|
||||
break;
|
||||
case 6:
|
||||
return 20;
|
||||
break;
|
||||
case 7:
|
||||
this.popState("escaped_text");
|
||||
return 18;
|
||||
break;
|
||||
case 8:
|
||||
return 19;
|
||||
break;
|
||||
}
|
||||
}, "anonymous"),
|
||||
rules: [/^(?:sankey-beta\b)/i, /^(?:sankey\b)/i, /^(?:$)/i, /^(?:((\u000D\u000A)|(\u000A)))/i, /^(?:(\u002C))/i, /^(?:(\u0022))/i, /^(?:([\u0020-\u0021\u0023-\u002B\u002D-\u007E])*)/i, /^(?:(\u0022)(?!(\u0022)))/i, /^(?:(([\u0020-\u0021\u0023-\u002B\u002D-\u007E])|(\u002C)|(\u000D)|(\u000A)|(\u0022)(\u0022))*)/i],
|
||||
conditions: { "csv": { "rules": [2, 3, 4, 5, 6, 7, 8], "inclusive": false }, "escaped_text": { "rules": [7, 8], "inclusive": false }, "INITIAL": { "rules": [0, 1, 2, 3, 4, 5, 6, 7, 8], "inclusive": true } }
|
||||
};
|
||||
return lexer2;
|
||||
})();
|
||||
parser2.lexer = lexer;
|
||||
function Parser() {
|
||||
this.yy = {};
|
||||
}
|
||||
__name(Parser, "Parser");
|
||||
Parser.prototype = parser2;
|
||||
parser2.Parser = Parser;
|
||||
return new Parser();
|
||||
})();
|
||||
parser.parser = parser;
|
||||
var sankey_default = parser;
|
||||
|
||||
// src/diagrams/sankey/sankeyDB.ts
|
||||
var links = [];
|
||||
var nodes = [];
|
||||
var nodesMap = /* @__PURE__ */ new Map();
|
||||
var clear2 = /* @__PURE__ */ __name(() => {
|
||||
links = [];
|
||||
nodes = [];
|
||||
nodesMap = /* @__PURE__ */ new Map();
|
||||
clear();
|
||||
}, "clear");
|
||||
var SankeyLink = class {
|
||||
constructor(source, target, value = 0) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.value = value;
|
||||
}
|
||||
static {
|
||||
__name(this, "SankeyLink");
|
||||
}
|
||||
};
|
||||
var addLink = /* @__PURE__ */ __name((source, target, value) => {
|
||||
links.push(new SankeyLink(source, target, value));
|
||||
}, "addLink");
|
||||
var SankeyNode = class {
|
||||
constructor(ID) {
|
||||
this.ID = ID;
|
||||
}
|
||||
static {
|
||||
__name(this, "SankeyNode");
|
||||
}
|
||||
};
|
||||
var findOrCreateNode = /* @__PURE__ */ __name((ID) => {
|
||||
ID = common_default.sanitizeText(ID, getConfig());
|
||||
let node = nodesMap.get(ID);
|
||||
if (node === void 0) {
|
||||
node = new SankeyNode(ID);
|
||||
nodesMap.set(ID, node);
|
||||
nodes.push(node);
|
||||
}
|
||||
return node;
|
||||
}, "findOrCreateNode");
|
||||
var getNodes = /* @__PURE__ */ __name(() => nodes, "getNodes");
|
||||
var getLinks = /* @__PURE__ */ __name(() => links, "getLinks");
|
||||
var getGraph = /* @__PURE__ */ __name(() => ({
|
||||
nodes: nodes.map((node) => ({ id: node.ID })),
|
||||
links: links.map((link) => ({
|
||||
source: link.source.ID,
|
||||
target: link.target.ID,
|
||||
value: link.value
|
||||
}))
|
||||
}), "getGraph");
|
||||
var sankeyDB_default = {
|
||||
nodesMap,
|
||||
getConfig: /* @__PURE__ */ __name(() => getConfig().sankey, "getConfig"),
|
||||
getNodes,
|
||||
getLinks,
|
||||
getGraph,
|
||||
addLink,
|
||||
findOrCreateNode,
|
||||
getAccTitle,
|
||||
setAccTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
getDiagramTitle,
|
||||
setDiagramTitle,
|
||||
clear: clear2
|
||||
};
|
||||
|
||||
// src/diagrams/sankey/sankeyRenderer.ts
|
||||
import {
|
||||
select as d3select,
|
||||
scaleOrdinal as d3scaleOrdinal,
|
||||
schemeTableau10 as d3schemeTableau10
|
||||
} from "d3";
|
||||
import {
|
||||
sankey as d3Sankey,
|
||||
sankeyLinkHorizontal as d3SankeyLinkHorizontal,
|
||||
sankeyLeft as d3SankeyLeft,
|
||||
sankeyRight as d3SankeyRight,
|
||||
sankeyCenter as d3SankeyCenter,
|
||||
sankeyJustify as d3SankeyJustify
|
||||
} from "d3-sankey";
|
||||
|
||||
// src/rendering-util/uid.ts
|
||||
var Uid = class _Uid {
|
||||
static {
|
||||
__name(this, "Uid");
|
||||
}
|
||||
static {
|
||||
this.count = 0;
|
||||
}
|
||||
static next(name) {
|
||||
return new _Uid(name + ++_Uid.count);
|
||||
}
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
this.href = `#${id}`;
|
||||
}
|
||||
toString() {
|
||||
return "url(" + this.href + ")";
|
||||
}
|
||||
};
|
||||
|
||||
// src/diagrams/sankey/sankeyRenderer.ts
|
||||
var alignmentsMap = {
|
||||
left: d3SankeyLeft,
|
||||
right: d3SankeyRight,
|
||||
center: d3SankeyCenter,
|
||||
justify: d3SankeyJustify
|
||||
};
|
||||
var draw = /* @__PURE__ */ __name(function(text, id, _version, diagObj) {
|
||||
const { securityLevel, sankey: conf } = getConfig();
|
||||
const defaultSankeyConfig = defaultConfig.sankey;
|
||||
let sandboxElement;
|
||||
if (securityLevel === "sandbox") {
|
||||
sandboxElement = d3select("#i" + id);
|
||||
}
|
||||
const root = securityLevel === "sandbox" ? d3select(sandboxElement.nodes()[0].contentDocument.body) : d3select("body");
|
||||
const svg = securityLevel === "sandbox" ? root.select(`[id="${id}"]`) : d3select(`[id="${id}"]`);
|
||||
const width = conf?.width ?? defaultSankeyConfig.width;
|
||||
const height = conf?.height ?? defaultSankeyConfig.width;
|
||||
const useMaxWidth = conf?.useMaxWidth ?? defaultSankeyConfig.useMaxWidth;
|
||||
const nodeAlignment = conf?.nodeAlignment ?? defaultSankeyConfig.nodeAlignment;
|
||||
const prefix = conf?.prefix ?? defaultSankeyConfig.prefix;
|
||||
const suffix = conf?.suffix ?? defaultSankeyConfig.suffix;
|
||||
const showValues = conf?.showValues ?? defaultSankeyConfig.showValues;
|
||||
const graph = diagObj.db.getGraph();
|
||||
const nodeAlign = alignmentsMap[nodeAlignment];
|
||||
const nodeWidth = 10;
|
||||
const sankey = d3Sankey().nodeId((d) => d.id).nodeWidth(nodeWidth).nodePadding(10 + (showValues ? 15 : 0)).nodeAlign(nodeAlign).extent([
|
||||
[0, 0],
|
||||
[width, height]
|
||||
]);
|
||||
sankey(graph);
|
||||
const colorScheme = d3scaleOrdinal(d3schemeTableau10);
|
||||
svg.append("g").attr("class", "nodes").selectAll(".node").data(graph.nodes).join("g").attr("class", "node").attr("id", (d) => (d.uid = Uid.next("node-")).id).attr("transform", function(d) {
|
||||
return "translate(" + d.x0 + "," + d.y0 + ")";
|
||||
}).attr("x", (d) => d.x0).attr("y", (d) => d.y0).append("rect").attr("height", (d) => {
|
||||
return d.y1 - d.y0;
|
||||
}).attr("width", (d) => d.x1 - d.x0).attr("fill", (d) => colorScheme(d.id));
|
||||
const getText = /* @__PURE__ */ __name(({ id: id2, value }) => {
|
||||
if (!showValues) {
|
||||
return id2;
|
||||
}
|
||||
return `${id2}
|
||||
${prefix}${Math.round(value * 100) / 100}${suffix}`;
|
||||
}, "getText");
|
||||
svg.append("g").attr("class", "node-labels").attr("font-size", 14).selectAll("text").data(graph.nodes).join("text").attr("x", (d) => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6).attr("y", (d) => (d.y1 + d.y0) / 2).attr("dy", `${showValues ? "0" : "0.35"}em`).attr("text-anchor", (d) => d.x0 < width / 2 ? "start" : "end").text(getText);
|
||||
const link = svg.append("g").attr("class", "links").attr("fill", "none").attr("stroke-opacity", 0.5).selectAll(".link").data(graph.links).join("g").attr("class", "link").style("mix-blend-mode", "multiply");
|
||||
const linkColor = conf?.linkColor ?? "gradient";
|
||||
if (linkColor === "gradient") {
|
||||
const gradient = link.append("linearGradient").attr("id", (d) => (d.uid = Uid.next("linearGradient-")).id).attr("gradientUnits", "userSpaceOnUse").attr("x1", (d) => d.source.x1).attr("x2", (d) => d.target.x0);
|
||||
gradient.append("stop").attr("offset", "0%").attr("stop-color", (d) => colorScheme(d.source.id));
|
||||
gradient.append("stop").attr("offset", "100%").attr("stop-color", (d) => colorScheme(d.target.id));
|
||||
}
|
||||
let coloring;
|
||||
switch (linkColor) {
|
||||
case "gradient":
|
||||
coloring = /* @__PURE__ */ __name((d) => d.uid, "coloring");
|
||||
break;
|
||||
case "source":
|
||||
coloring = /* @__PURE__ */ __name((d) => colorScheme(d.source.id), "coloring");
|
||||
break;
|
||||
case "target":
|
||||
coloring = /* @__PURE__ */ __name((d) => colorScheme(d.target.id), "coloring");
|
||||
break;
|
||||
default:
|
||||
coloring = linkColor;
|
||||
}
|
||||
link.append("path").attr("d", d3SankeyLinkHorizontal()).attr("stroke", coloring).attr("stroke-width", (d) => Math.max(1, d.width));
|
||||
setupGraphViewbox(void 0, svg, 0, useMaxWidth);
|
||||
}, "draw");
|
||||
var sankeyRenderer_default = {
|
||||
draw
|
||||
};
|
||||
|
||||
// src/diagrams/sankey/sankeyUtils.ts
|
||||
var prepareTextForParsing = /* @__PURE__ */ __name((text) => {
|
||||
const textToParse = text.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g, "").replaceAll(/([\n\r])+/g, "\n").trim();
|
||||
return textToParse;
|
||||
}, "prepareTextForParsing");
|
||||
|
||||
// src/diagrams/sankey/styles.js
|
||||
var getStyles = /* @__PURE__ */ __name((options) => `.label {
|
||||
font-family: ${options.fontFamily};
|
||||
}`, "getStyles");
|
||||
var styles_default = getStyles;
|
||||
|
||||
// src/diagrams/sankey/sankeyDiagram.ts
|
||||
var originalParse = sankey_default.parse.bind(sankey_default);
|
||||
sankey_default.parse = (text) => originalParse(prepareTextForParsing(text));
|
||||
var diagram = {
|
||||
styles: styles_default,
|
||||
parser: sankey_default,
|
||||
db: sankeyDB_default,
|
||||
renderer: sankeyRenderer_default
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+4659
File diff suppressed because one or more lines are too long
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+489
@@ -0,0 +1,489 @@
|
||||
import {
|
||||
StateDB,
|
||||
stateDiagram_default,
|
||||
styles_default
|
||||
} from "./chunk-OYMX7WX6.mjs";
|
||||
import "./chunk-55IACEB6.mjs";
|
||||
import "./chunk-EDXVE4YY.mjs";
|
||||
import "./chunk-336JU56O.mjs";
|
||||
import "./chunk-ENJZ2VHE.mjs";
|
||||
import "./chunk-BSJP7CBP.mjs";
|
||||
import "./chunk-5FUZZQ4R.mjs";
|
||||
import "./chunk-ZZ45TVLE.mjs";
|
||||
import "./chunk-X2U36JSP.mjs";
|
||||
import "./chunk-U2HBQHQK.mjs";
|
||||
import {
|
||||
utils_default
|
||||
} from "./chunk-5PVQY5BW.mjs";
|
||||
import {
|
||||
common_default,
|
||||
configureSvgSize,
|
||||
getConfig2 as getConfig,
|
||||
getUrl
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/state/stateRenderer.js
|
||||
import { select } from "d3";
|
||||
import { layout as dagreLayout } from "dagre-d3-es/src/dagre/index.js";
|
||||
import * as graphlib from "dagre-d3-es/src/graphlib/index.js";
|
||||
|
||||
// src/diagrams/state/shapes.js
|
||||
import { line, curveBasis } from "d3";
|
||||
var drawStartState = /* @__PURE__ */ __name((g) => g.append("circle").attr("class", "start-state").attr("r", getConfig().state.sizeUnit).attr("cx", getConfig().state.padding + getConfig().state.sizeUnit).attr("cy", getConfig().state.padding + getConfig().state.sizeUnit), "drawStartState");
|
||||
var drawDivider = /* @__PURE__ */ __name((g) => g.append("line").style("stroke", "grey").style("stroke-dasharray", "3").attr("x1", getConfig().state.textHeight).attr("class", "divider").attr("x2", getConfig().state.textHeight * 2).attr("y1", 0).attr("y2", 0), "drawDivider");
|
||||
var drawSimpleState = /* @__PURE__ */ __name((g, stateDef) => {
|
||||
const state = g.append("text").attr("x", 2 * getConfig().state.padding).attr("y", getConfig().state.textHeight + 2 * getConfig().state.padding).attr("font-size", getConfig().state.fontSize).attr("class", "state-title").text(stateDef.id);
|
||||
const classBox = state.node().getBBox();
|
||||
g.insert("rect", ":first-child").attr("x", getConfig().state.padding).attr("y", getConfig().state.padding).attr("width", classBox.width + 2 * getConfig().state.padding).attr("height", classBox.height + 2 * getConfig().state.padding).attr("rx", getConfig().state.radius);
|
||||
return state;
|
||||
}, "drawSimpleState");
|
||||
var drawDescrState = /* @__PURE__ */ __name((g, stateDef) => {
|
||||
const addTspan = /* @__PURE__ */ __name(function(textEl, txt, isFirst2) {
|
||||
const tSpan = textEl.append("tspan").attr("x", 2 * getConfig().state.padding).text(txt);
|
||||
if (!isFirst2) {
|
||||
tSpan.attr("dy", getConfig().state.textHeight);
|
||||
}
|
||||
}, "addTspan");
|
||||
const title = g.append("text").attr("x", 2 * getConfig().state.padding).attr("y", getConfig().state.textHeight + 1.3 * getConfig().state.padding).attr("font-size", getConfig().state.fontSize).attr("class", "state-title").text(stateDef.descriptions[0]);
|
||||
const titleBox = title.node().getBBox();
|
||||
const titleHeight = titleBox.height;
|
||||
const description = g.append("text").attr("x", getConfig().state.padding).attr(
|
||||
"y",
|
||||
titleHeight + getConfig().state.padding * 0.4 + getConfig().state.dividerMargin + getConfig().state.textHeight
|
||||
).attr("class", "state-description");
|
||||
let isFirst = true;
|
||||
let isSecond = true;
|
||||
stateDef.descriptions.forEach(function(descr) {
|
||||
if (!isFirst) {
|
||||
addTspan(description, descr, isSecond);
|
||||
isSecond = false;
|
||||
}
|
||||
isFirst = false;
|
||||
});
|
||||
const descrLine = g.append("line").attr("x1", getConfig().state.padding).attr("y1", getConfig().state.padding + titleHeight + getConfig().state.dividerMargin / 2).attr("y2", getConfig().state.padding + titleHeight + getConfig().state.dividerMargin / 2).attr("class", "descr-divider");
|
||||
const descrBox = description.node().getBBox();
|
||||
const width = Math.max(descrBox.width, titleBox.width);
|
||||
descrLine.attr("x2", width + 3 * getConfig().state.padding);
|
||||
g.insert("rect", ":first-child").attr("x", getConfig().state.padding).attr("y", getConfig().state.padding).attr("width", width + 2 * getConfig().state.padding).attr("height", descrBox.height + titleHeight + 2 * getConfig().state.padding).attr("rx", getConfig().state.radius);
|
||||
return g;
|
||||
}, "drawDescrState");
|
||||
var addTitleAndBox = /* @__PURE__ */ __name((g, stateDef, altBkg) => {
|
||||
const pad = getConfig().state.padding;
|
||||
const dblPad = 2 * getConfig().state.padding;
|
||||
const orgBox = g.node().getBBox();
|
||||
const orgWidth = orgBox.width;
|
||||
const orgX = orgBox.x;
|
||||
const title = g.append("text").attr("x", 0).attr("y", getConfig().state.titleShift).attr("font-size", getConfig().state.fontSize).attr("class", "state-title").text(stateDef.id);
|
||||
const titleBox = title.node().getBBox();
|
||||
const titleWidth = titleBox.width + dblPad;
|
||||
let width = Math.max(titleWidth, orgWidth);
|
||||
if (width === orgWidth) {
|
||||
width = width + dblPad;
|
||||
}
|
||||
let startX;
|
||||
const graphBox = g.node().getBBox();
|
||||
if (stateDef.doc) {
|
||||
}
|
||||
startX = orgX - pad;
|
||||
if (titleWidth > orgWidth) {
|
||||
startX = (orgWidth - width) / 2 + pad;
|
||||
}
|
||||
if (Math.abs(orgX - graphBox.x) < pad && titleWidth > orgWidth) {
|
||||
startX = orgX - (titleWidth - orgWidth) / 2;
|
||||
}
|
||||
const lineY = 1 - getConfig().state.textHeight;
|
||||
g.insert("rect", ":first-child").attr("x", startX).attr("y", lineY).attr("class", altBkg ? "alt-composit" : "composit").attr("width", width).attr(
|
||||
"height",
|
||||
graphBox.height + getConfig().state.textHeight + getConfig().state.titleShift + 1
|
||||
).attr("rx", "0");
|
||||
title.attr("x", startX + pad);
|
||||
if (titleWidth <= orgWidth) {
|
||||
title.attr("x", orgX + (width - dblPad) / 2 - titleWidth / 2 + pad);
|
||||
}
|
||||
g.insert("rect", ":first-child").attr("x", startX).attr(
|
||||
"y",
|
||||
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
|
||||
).attr("width", width).attr("height", getConfig().state.textHeight * 3).attr("rx", getConfig().state.radius);
|
||||
g.insert("rect", ":first-child").attr("x", startX).attr(
|
||||
"y",
|
||||
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
|
||||
).attr("width", width).attr("height", graphBox.height + 3 + 2 * getConfig().state.textHeight).attr("rx", getConfig().state.radius);
|
||||
return g;
|
||||
}, "addTitleAndBox");
|
||||
var drawEndState = /* @__PURE__ */ __name((g) => {
|
||||
g.append("circle").attr("class", "end-state-outer").attr("r", getConfig().state.sizeUnit + getConfig().state.miniPadding).attr(
|
||||
"cx",
|
||||
getConfig().state.padding + getConfig().state.sizeUnit + getConfig().state.miniPadding
|
||||
).attr(
|
||||
"cy",
|
||||
getConfig().state.padding + getConfig().state.sizeUnit + getConfig().state.miniPadding
|
||||
);
|
||||
return g.append("circle").attr("class", "end-state-inner").attr("r", getConfig().state.sizeUnit).attr("cx", getConfig().state.padding + getConfig().state.sizeUnit + 2).attr("cy", getConfig().state.padding + getConfig().state.sizeUnit + 2);
|
||||
}, "drawEndState");
|
||||
var drawForkJoinState = /* @__PURE__ */ __name((g, stateDef) => {
|
||||
let width = getConfig().state.forkWidth;
|
||||
let height = getConfig().state.forkHeight;
|
||||
if (stateDef.parentId) {
|
||||
let tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
return g.append("rect").style("stroke", "black").style("fill", "black").attr("width", width).attr("height", height).attr("x", getConfig().state.padding).attr("y", getConfig().state.padding);
|
||||
}, "drawForkJoinState");
|
||||
var _drawLongText = /* @__PURE__ */ __name((_text, x, y, g) => {
|
||||
let textHeight = 0;
|
||||
const textElem = g.append("text");
|
||||
textElem.style("text-anchor", "start");
|
||||
textElem.attr("class", "noteText");
|
||||
let text = _text.replace(/\r\n/g, "<br/>");
|
||||
text = text.replace(/\n/g, "<br/>");
|
||||
const lines = text.split(common_default.lineBreakRegex);
|
||||
let tHeight = 1.25 * getConfig().state.noteMargin;
|
||||
for (const line2 of lines) {
|
||||
const txt = line2.trim();
|
||||
if (txt.length > 0) {
|
||||
const span = textElem.append("tspan");
|
||||
span.text(txt);
|
||||
if (tHeight === 0) {
|
||||
const textBounds = span.node().getBBox();
|
||||
tHeight += textBounds.height;
|
||||
}
|
||||
textHeight += tHeight;
|
||||
span.attr("x", x + getConfig().state.noteMargin);
|
||||
span.attr("y", y + textHeight + 1.25 * getConfig().state.noteMargin);
|
||||
}
|
||||
}
|
||||
return { textWidth: textElem.node().getBBox().width, textHeight };
|
||||
}, "_drawLongText");
|
||||
var drawNote = /* @__PURE__ */ __name((text, g) => {
|
||||
g.attr("class", "state-note");
|
||||
const note = g.append("rect").attr("x", 0).attr("y", getConfig().state.padding);
|
||||
const rectElem = g.append("g");
|
||||
const { textWidth, textHeight } = _drawLongText(text, 0, 0, rectElem);
|
||||
note.attr("height", textHeight + 2 * getConfig().state.noteMargin);
|
||||
note.attr("width", textWidth + getConfig().state.noteMargin * 2);
|
||||
return note;
|
||||
}, "drawNote");
|
||||
var drawState = /* @__PURE__ */ __name(function(elem, stateDef) {
|
||||
const id = stateDef.id;
|
||||
const stateInfo = {
|
||||
id,
|
||||
label: stateDef.id,
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
const g = elem.append("g").attr("id", id).attr("class", "stateGroup");
|
||||
if (stateDef.type === "start") {
|
||||
drawStartState(g);
|
||||
}
|
||||
if (stateDef.type === "end") {
|
||||
drawEndState(g);
|
||||
}
|
||||
if (stateDef.type === "fork" || stateDef.type === "join") {
|
||||
drawForkJoinState(g, stateDef);
|
||||
}
|
||||
if (stateDef.type === "note") {
|
||||
drawNote(stateDef.note.text, g);
|
||||
}
|
||||
if (stateDef.type === "divider") {
|
||||
drawDivider(g);
|
||||
}
|
||||
if (stateDef.type === "default" && stateDef.descriptions.length === 0) {
|
||||
drawSimpleState(g, stateDef);
|
||||
}
|
||||
if (stateDef.type === "default" && stateDef.descriptions.length > 0) {
|
||||
drawDescrState(g, stateDef);
|
||||
}
|
||||
const stateBox = g.node().getBBox();
|
||||
stateInfo.width = stateBox.width + 2 * getConfig().state.padding;
|
||||
stateInfo.height = stateBox.height + 2 * getConfig().state.padding;
|
||||
return stateInfo;
|
||||
}, "drawState");
|
||||
var edgeCount = 0;
|
||||
var drawEdge = /* @__PURE__ */ __name(function(elem, path, relation) {
|
||||
const getRelationType = /* @__PURE__ */ __name(function(type) {
|
||||
switch (type) {
|
||||
case StateDB.relationType.AGGREGATION:
|
||||
return "aggregation";
|
||||
case StateDB.relationType.EXTENSION:
|
||||
return "extension";
|
||||
case StateDB.relationType.COMPOSITION:
|
||||
return "composition";
|
||||
case StateDB.relationType.DEPENDENCY:
|
||||
return "dependency";
|
||||
}
|
||||
}, "getRelationType");
|
||||
path.points = path.points.filter((p) => !Number.isNaN(p.y));
|
||||
const lineData = path.points;
|
||||
const lineFunction = line().x(function(d) {
|
||||
return d.x;
|
||||
}).y(function(d) {
|
||||
return d.y;
|
||||
}).curve(curveBasis);
|
||||
const svgPath = elem.append("path").attr("d", lineFunction(lineData)).attr("id", "edge" + edgeCount).attr("class", "transition");
|
||||
let url = "";
|
||||
if (getConfig().state.arrowMarkerAbsolute) {
|
||||
url = getUrl(true);
|
||||
}
|
||||
svgPath.attr(
|
||||
"marker-end",
|
||||
"url(" + url + "#" + getRelationType(StateDB.relationType.DEPENDENCY) + "End)"
|
||||
);
|
||||
if (relation.title !== void 0) {
|
||||
const label = elem.append("g").attr("class", "stateLabel");
|
||||
const { x, y } = utils_default.calcLabelPosition(path.points);
|
||||
const rows = common_default.getRows(relation.title);
|
||||
let titleHeight = 0;
|
||||
const titleRows = [];
|
||||
let maxWidth = 0;
|
||||
let minX = 0;
|
||||
for (let i = 0; i <= rows.length; i++) {
|
||||
const title = label.append("text").attr("text-anchor", "middle").text(rows[i]).attr("x", x).attr("y", y + titleHeight);
|
||||
const boundsTmp = title.node().getBBox();
|
||||
maxWidth = Math.max(maxWidth, boundsTmp.width);
|
||||
minX = Math.min(minX, boundsTmp.x);
|
||||
log.info(boundsTmp.x, x, y + titleHeight);
|
||||
if (titleHeight === 0) {
|
||||
const titleBox = title.node().getBBox();
|
||||
titleHeight = titleBox.height;
|
||||
log.info("Title height", titleHeight, y);
|
||||
}
|
||||
titleRows.push(title);
|
||||
}
|
||||
let boxHeight = titleHeight * rows.length;
|
||||
if (rows.length > 1) {
|
||||
const heightAdj = (rows.length - 1) * titleHeight * 0.5;
|
||||
titleRows.forEach((title, i) => title.attr("y", y + i * titleHeight - heightAdj));
|
||||
boxHeight = titleHeight * rows.length;
|
||||
}
|
||||
const bounds = label.node().getBBox();
|
||||
label.insert("rect", ":first-child").attr("class", "box").attr("x", x - maxWidth / 2 - getConfig().state.padding / 2).attr("y", y - boxHeight / 2 - getConfig().state.padding / 2 - 3.5).attr("width", maxWidth + getConfig().state.padding).attr("height", boxHeight + getConfig().state.padding);
|
||||
log.info(bounds);
|
||||
}
|
||||
edgeCount++;
|
||||
}, "drawEdge");
|
||||
|
||||
// src/diagrams/state/stateRenderer.js
|
||||
var conf;
|
||||
var transformationLog = {};
|
||||
var setConf = /* @__PURE__ */ __name(function() {
|
||||
}, "setConf");
|
||||
var insertMarkers = /* @__PURE__ */ __name(function(elem) {
|
||||
elem.append("defs").append("marker").attr("id", "dependencyEnd").attr("refX", 19).attr("refY", 7).attr("markerWidth", 20).attr("markerHeight", 28).attr("orient", "auto").append("path").attr("d", "M 19,7 L9,13 L14,7 L9,1 Z");
|
||||
}, "insertMarkers");
|
||||
var draw = /* @__PURE__ */ __name(function(text, id, _version, diagObj) {
|
||||
conf = getConfig().state;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
let sandboxElement;
|
||||
if (securityLevel === "sandbox") {
|
||||
sandboxElement = select("#i" + id);
|
||||
}
|
||||
const root = securityLevel === "sandbox" ? select(sandboxElement.nodes()[0].contentDocument.body) : select("body");
|
||||
const doc = securityLevel === "sandbox" ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
log.debug("Rendering diagram " + text);
|
||||
const diagram2 = root.select(`[id='${id}']`);
|
||||
insertMarkers(diagram2);
|
||||
const rootDoc = diagObj.db.getRootDoc();
|
||||
const rootG = diagram2.append("g").attr("id", id + "-root");
|
||||
renderDoc(rootDoc, rootG, void 0, false, root, doc, diagObj);
|
||||
const padding = conf.padding;
|
||||
const bounds = diagram2.node().getBBox();
|
||||
const width = bounds.width + padding * 2;
|
||||
const height = bounds.height + padding * 2;
|
||||
const svgWidth = width * 1.75;
|
||||
configureSvgSize(diagram2, height, svgWidth, conf.useMaxWidth);
|
||||
diagram2.attr(
|
||||
"viewBox",
|
||||
`${bounds.x - conf.padding} ${bounds.y - conf.padding} ` + width + " " + height
|
||||
);
|
||||
}, "draw");
|
||||
var getLabelWidth = /* @__PURE__ */ __name((text) => {
|
||||
return text ? text.length * conf.fontSizeFactor : 1;
|
||||
}, "getLabelWidth");
|
||||
var renderDoc = /* @__PURE__ */ __name((doc, diagram2, parentId, altBkg, root, domDocument, diagObj) => {
|
||||
const graph = new graphlib.Graph({
|
||||
compound: true,
|
||||
multigraph: true
|
||||
});
|
||||
let i;
|
||||
let edgeFreeDoc = true;
|
||||
for (i = 0; i < doc.length; i++) {
|
||||
if (doc[i].stmt === "relation") {
|
||||
edgeFreeDoc = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parentId) {
|
||||
graph.setGraph({
|
||||
rankdir: "LR",
|
||||
multigraph: true,
|
||||
compound: true,
|
||||
// acyclicer: 'greedy',
|
||||
ranker: "tight-tree",
|
||||
ranksep: edgeFreeDoc ? 1 : conf.edgeLengthFactor,
|
||||
nodeSep: edgeFreeDoc ? 1 : 50,
|
||||
isMultiGraph: true
|
||||
// ranksep: 5,
|
||||
// nodesep: 1
|
||||
});
|
||||
} else {
|
||||
graph.setGraph({
|
||||
rankdir: "TB",
|
||||
multigraph: true,
|
||||
compound: true,
|
||||
// isCompound: true,
|
||||
// acyclicer: 'greedy',
|
||||
// ranker: 'longest-path'
|
||||
ranksep: edgeFreeDoc ? 1 : conf.edgeLengthFactor,
|
||||
nodeSep: edgeFreeDoc ? 1 : 50,
|
||||
ranker: "tight-tree",
|
||||
// ranker: 'network-simplex'
|
||||
isMultiGraph: true
|
||||
});
|
||||
}
|
||||
graph.setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
const states = diagObj.db.getStates();
|
||||
const relations = diagObj.db.getRelations();
|
||||
const keys = Object.keys(states);
|
||||
let first = true;
|
||||
for (const key of keys) {
|
||||
const stateDef = states[key];
|
||||
if (parentId) {
|
||||
stateDef.parentId = parentId;
|
||||
}
|
||||
let node;
|
||||
if (stateDef.doc) {
|
||||
let sub = diagram2.append("g").attr("id", stateDef.id).attr("class", "stateGroup");
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg, root, domDocument, diagObj);
|
||||
if (first) {
|
||||
sub = addTitleAndBox(sub, stateDef, altBkg);
|
||||
let boxBounds = sub.node().getBBox();
|
||||
node.width = boxBounds.width;
|
||||
node.height = boxBounds.height + conf.padding / 2;
|
||||
transformationLog[stateDef.id] = { y: conf.compositTitleSize };
|
||||
} else {
|
||||
let boxBounds = sub.node().getBBox();
|
||||
node.width = boxBounds.width;
|
||||
node.height = boxBounds.height;
|
||||
}
|
||||
} else {
|
||||
node = drawState(diagram2, stateDef, graph);
|
||||
}
|
||||
if (stateDef.note) {
|
||||
const noteDef = {
|
||||
descriptions: [],
|
||||
id: stateDef.id + "-note",
|
||||
note: stateDef.note,
|
||||
type: "note"
|
||||
};
|
||||
const note = drawState(diagram2, noteDef, graph);
|
||||
if (stateDef.note.position === "left of") {
|
||||
graph.setNode(node.id + "-note", note);
|
||||
graph.setNode(node.id, node);
|
||||
} else {
|
||||
graph.setNode(node.id, node);
|
||||
graph.setNode(node.id + "-note", note);
|
||||
}
|
||||
graph.setParent(node.id, node.id + "-group");
|
||||
graph.setParent(node.id + "-note", node.id + "-group");
|
||||
} else {
|
||||
graph.setNode(node.id, node);
|
||||
}
|
||||
}
|
||||
log.debug("Count=", graph.nodeCount(), graph);
|
||||
let cnt = 0;
|
||||
relations.forEach(function(relation) {
|
||||
cnt++;
|
||||
log.debug("Setting edge", relation);
|
||||
graph.setEdge(
|
||||
relation.id1,
|
||||
relation.id2,
|
||||
{
|
||||
relation,
|
||||
width: getLabelWidth(relation.title),
|
||||
height: conf.labelHeight * common_default.getRows(relation.title).length,
|
||||
labelpos: "c"
|
||||
},
|
||||
"id" + cnt
|
||||
);
|
||||
});
|
||||
dagreLayout(graph);
|
||||
log.debug("Graph after layout", graph.nodes());
|
||||
const svgElem = diagram2.node();
|
||||
graph.nodes().forEach(function(v) {
|
||||
if (v !== void 0 && graph.node(v) !== void 0) {
|
||||
log.warn("Node " + v + ": " + JSON.stringify(graph.node(v)));
|
||||
root.select("#" + svgElem.id + " #" + v).attr(
|
||||
"transform",
|
||||
"translate(" + (graph.node(v).x - graph.node(v).width / 2) + "," + (graph.node(v).y + (transformationLog[v] ? transformationLog[v].y : 0) - graph.node(v).height / 2) + " )"
|
||||
);
|
||||
root.select("#" + svgElem.id + " #" + v).attr("data-x-shift", graph.node(v).x - graph.node(v).width / 2);
|
||||
const dividers = domDocument.querySelectorAll("#" + svgElem.id + " #" + v + " .divider");
|
||||
dividers.forEach((divider) => {
|
||||
const parent = divider.parentElement;
|
||||
let pWidth = 0;
|
||||
let pShift = 0;
|
||||
if (parent) {
|
||||
if (parent.parentElement) {
|
||||
pWidth = parent.parentElement.getBBox().width;
|
||||
}
|
||||
pShift = parseInt(parent.getAttribute("data-x-shift"), 10);
|
||||
if (Number.isNaN(pShift)) {
|
||||
pShift = 0;
|
||||
}
|
||||
}
|
||||
divider.setAttribute("x1", 0 - pShift + 8);
|
||||
divider.setAttribute("x2", pWidth - pShift - 8);
|
||||
});
|
||||
} else {
|
||||
log.debug("No Node " + v + ": " + JSON.stringify(graph.node(v)));
|
||||
}
|
||||
});
|
||||
let stateBox = svgElem.getBBox();
|
||||
graph.edges().forEach(function(e) {
|
||||
if (e !== void 0 && graph.edge(e) !== void 0) {
|
||||
log.debug("Edge " + e.v + " -> " + e.w + ": " + JSON.stringify(graph.edge(e)));
|
||||
drawEdge(diagram2, graph.edge(e), graph.edge(e).relation);
|
||||
}
|
||||
});
|
||||
stateBox = svgElem.getBBox();
|
||||
const stateInfo = {
|
||||
id: parentId ? parentId : "root",
|
||||
label: parentId ? parentId : "root",
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
stateInfo.width = stateBox.width + 2 * conf.padding;
|
||||
stateInfo.height = stateBox.height + 2 * conf.padding;
|
||||
log.debug("Doc rendered", stateInfo, graph);
|
||||
return stateInfo;
|
||||
}, "renderDoc");
|
||||
var stateRenderer_default = {
|
||||
setConf,
|
||||
draw
|
||||
};
|
||||
|
||||
// src/diagrams/state/stateDiagram.ts
|
||||
var diagram = {
|
||||
parser: stateDiagram_default,
|
||||
get db() {
|
||||
return new StateDB(1);
|
||||
},
|
||||
renderer: stateRenderer_default,
|
||||
styles: styles_default,
|
||||
init: /* @__PURE__ */ __name((cnf) => {
|
||||
if (!cnf.state) {
|
||||
cnf.state = {};
|
||||
}
|
||||
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
}, "init")
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Generated
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
StateDB,
|
||||
stateDiagram_default,
|
||||
stateRenderer_v3_unified_default,
|
||||
styles_default
|
||||
} from "./chunk-OYMX7WX6.mjs";
|
||||
import "./chunk-55IACEB6.mjs";
|
||||
import "./chunk-EDXVE4YY.mjs";
|
||||
import "./chunk-336JU56O.mjs";
|
||||
import "./chunk-ENJZ2VHE.mjs";
|
||||
import "./chunk-BSJP7CBP.mjs";
|
||||
import "./chunk-5FUZZQ4R.mjs";
|
||||
import "./chunk-ZZ45TVLE.mjs";
|
||||
import "./chunk-X2U36JSP.mjs";
|
||||
import "./chunk-U2HBQHQK.mjs";
|
||||
import "./chunk-5PVQY5BW.mjs";
|
||||
import "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/state/stateDiagram-v2.ts
|
||||
var diagram = {
|
||||
parser: stateDiagram_default,
|
||||
get db() {
|
||||
return new StateDB(2);
|
||||
},
|
||||
renderer: stateRenderer_v3_unified_default,
|
||||
styles: styles_default,
|
||||
init: /* @__PURE__ */ __name((cnf) => {
|
||||
if (!cnf.state) {
|
||||
cnf.state = {};
|
||||
}
|
||||
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
}, "init")
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../src/diagrams/state/stateDiagram-v2.ts"],
|
||||
"sourcesContent": ["import type { DiagramDefinition } from '../../diagram-api/types.js';\n// @ts-ignore: JISON doesn't support types\nimport parser from './parser/stateDiagram.jison';\nimport { StateDB } from './stateDb.js';\nimport styles from './styles.js';\nimport renderer from './stateRenderer-v3-unified.js';\n\nexport const diagram: DiagramDefinition = {\n parser,\n get db() {\n return new StateDB(2);\n },\n renderer,\n styles,\n init: (cnf) => {\n if (!cnf.state) {\n cnf.state = {};\n }\n cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;\n },\n};\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAOO,IAAM,UAA6B;AAAA,EACxC;AAAA,EACA,IAAI,KAAK;AACP,WAAO,IAAI,QAAQ,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM,wBAAC,QAAQ;AACb,QAAI,CAAC,IAAI,OAAO;AACd,UAAI,QAAQ,CAAC;AAAA,IACf;AACA,QAAI,MAAM,sBAAsB,IAAI;AAAA,EACtC,GALM;AAMR;",
|
||||
"names": []
|
||||
}
|
||||
Generated
Vendored
+1654
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+1101
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
+929
@@ -0,0 +1,929 @@
|
||||
import {
|
||||
selectSvgElement
|
||||
} from "./chunk-426QAEUC.mjs";
|
||||
import {
|
||||
populateCommonDb
|
||||
} from "./chunk-4BX2VUAB.mjs";
|
||||
import {
|
||||
clear,
|
||||
configureSvgSize,
|
||||
getAccDescription,
|
||||
getAccTitle,
|
||||
getConfig2 as getConfig,
|
||||
getDiagramTitle,
|
||||
sanitizeText,
|
||||
setAccDescription,
|
||||
setAccTitle,
|
||||
setDiagramTitle
|
||||
} from "./chunk-ICPOFSXX.mjs";
|
||||
import {
|
||||
__name,
|
||||
log
|
||||
} from "./chunk-AGHRB4JF.mjs";
|
||||
|
||||
// src/diagrams/wardley/wardleyParser.ts
|
||||
import { parse } from "@mermaid-js/parser";
|
||||
var toPercent = /* @__PURE__ */ __name((value, context) => {
|
||||
const normalized = value <= 1 ? value * 100 : value;
|
||||
if (normalized < 0 || normalized > 100) {
|
||||
throw new Error(
|
||||
`${context} must be between 0-1 (decimal) or 0-100 (percentage). Received: ${value}`
|
||||
);
|
||||
}
|
||||
return normalized;
|
||||
}, "toPercent");
|
||||
var toCoordinates = /* @__PURE__ */ __name((visibility, evolution, context) => {
|
||||
return {
|
||||
x: toPercent(evolution, `${context} evolution`),
|
||||
y: toPercent(visibility, `${context} visibility`)
|
||||
};
|
||||
}, "toCoordinates");
|
||||
var getFlowFromPort = /* @__PURE__ */ __name((port) => {
|
||||
if (!port) {
|
||||
return void 0;
|
||||
}
|
||||
if (port === "+<>") {
|
||||
return "bidirectional";
|
||||
}
|
||||
if (port === "+<") {
|
||||
return "backward";
|
||||
}
|
||||
if (port === "+>") {
|
||||
return "forward";
|
||||
}
|
||||
return void 0;
|
||||
}, "getFlowFromPort");
|
||||
var extractFlowFromArrow = /* @__PURE__ */ __name((arrow) => {
|
||||
if (!arrow?.startsWith("+")) {
|
||||
return {};
|
||||
}
|
||||
const labelMatch = /^\+'([^']*)'/.exec(arrow);
|
||||
const flowLabel = labelMatch?.[1];
|
||||
if (arrow.includes("<>")) {
|
||||
return { flow: "bidirectional", label: flowLabel };
|
||||
}
|
||||
if (arrow.includes("<")) {
|
||||
return { flow: "backward", label: flowLabel };
|
||||
}
|
||||
if (arrow.includes(">")) {
|
||||
return { flow: "forward", label: flowLabel };
|
||||
}
|
||||
return { label: flowLabel };
|
||||
}, "extractFlowFromArrow");
|
||||
var populateDb = /* @__PURE__ */ __name((ast, db) => {
|
||||
populateCommonDb(ast, db);
|
||||
if (ast.size) {
|
||||
db.setSize(ast.size.width, ast.size.height);
|
||||
}
|
||||
if (ast.evolution) {
|
||||
const stages = ast.evolution.stages.map((stage) => {
|
||||
if (stage.secondName) {
|
||||
return `${stage.name.trim()} / ${stage.secondName.trim()}`;
|
||||
}
|
||||
return stage.name.trim();
|
||||
});
|
||||
const stageBoundaries = ast.evolution.stages.filter((stage) => stage.boundary !== void 0).map((stage) => stage.boundary);
|
||||
db.updateAxes({ stages, stageBoundaries });
|
||||
}
|
||||
ast.anchors.forEach((anchor) => {
|
||||
const coords = toCoordinates(anchor.visibility, anchor.evolution, `Anchor "${anchor.name}"`);
|
||||
db.addNode(anchor.name, anchor.name, coords.x, coords.y, "anchor");
|
||||
});
|
||||
ast.components.forEach((component) => {
|
||||
const coords = toCoordinates(
|
||||
component.visibility,
|
||||
component.evolution,
|
||||
`Component "${component.name}"`
|
||||
);
|
||||
const labelOffsetX = component.label ? (component.label.negX ? -1 : 1) * component.label.offsetX : void 0;
|
||||
const labelOffsetY = component.label ? (component.label.negY ? -1 : 1) * component.label.offsetY : void 0;
|
||||
const sourceStrategy = component.decorator?.strategy;
|
||||
db.addNode(
|
||||
component.name,
|
||||
component.name,
|
||||
coords.x,
|
||||
coords.y,
|
||||
"component",
|
||||
labelOffsetX,
|
||||
labelOffsetY,
|
||||
component.inertia,
|
||||
sourceStrategy
|
||||
);
|
||||
});
|
||||
ast.notes.forEach((note) => {
|
||||
const coords = toCoordinates(note.visibility, note.evolution, `Note "${note.text}"`);
|
||||
db.addNote(note.text, coords.x, coords.y);
|
||||
});
|
||||
ast.pipelines.forEach((pipeline) => {
|
||||
const parentNode = db.getNode(pipeline.parent);
|
||||
if (!parentNode || typeof parentNode.y !== "number") {
|
||||
throw new Error(
|
||||
`Pipeline "${pipeline.parent}" must reference an existing component with coordinates.`
|
||||
);
|
||||
}
|
||||
const parentY = parentNode.y;
|
||||
db.startPipeline(pipeline.parent);
|
||||
pipeline.components.forEach((component) => {
|
||||
const componentId = `${pipeline.parent}_${component.name}`;
|
||||
const labelOffsetX = component.label ? (component.label.negX ? -1 : 1) * component.label.offsetX : void 0;
|
||||
const labelOffsetY = component.label ? (component.label.negY ? -1 : 1) * component.label.offsetY : void 0;
|
||||
const x = toPercent(component.evolution, `Pipeline component "${component.name}" evolution`);
|
||||
db.addNode(
|
||||
componentId,
|
||||
component.name,
|
||||
x,
|
||||
parentY,
|
||||
"pipeline-component",
|
||||
labelOffsetX,
|
||||
labelOffsetY
|
||||
);
|
||||
db.addPipelineComponent(pipeline.parent, componentId);
|
||||
});
|
||||
});
|
||||
ast.links.forEach((link) => {
|
||||
const isDashed = !!link.arrow && (link.arrow.includes("-.->") || link.arrow.includes(".-."));
|
||||
let flow = getFlowFromPort(link.fromPort) ?? getFlowFromPort(link.toPort);
|
||||
const { flow: arrowFlow, label: flowLabel } = extractFlowFromArrow(link.arrow);
|
||||
if (!flow && arrowFlow) {
|
||||
flow = arrowFlow;
|
||||
}
|
||||
const annotation = link.linkLabel;
|
||||
const label = flowLabel ?? annotation;
|
||||
db.addLink(link.from, link.to, isDashed, label, flow);
|
||||
});
|
||||
ast.evolves.forEach((evolve) => {
|
||||
const node = db.getNode(evolve.component);
|
||||
if (node?.y !== void 0) {
|
||||
const target = toPercent(evolve.target, `Evolve target for "${evolve.component}"`);
|
||||
db.addTrend(evolve.component, target, node.y);
|
||||
}
|
||||
});
|
||||
if (ast.annotations.length > 0) {
|
||||
const annotationsBox = ast.annotations[0];
|
||||
const coords = toCoordinates(annotationsBox.x, annotationsBox.y, "Annotations box");
|
||||
db.setAnnotationsBox(coords.x, coords.y);
|
||||
}
|
||||
ast.annotation.forEach((annotation) => {
|
||||
const coords = toCoordinates(annotation.x, annotation.y, `Annotation ${annotation.number}`);
|
||||
db.addAnnotation(annotation.number, [{ x: coords.x, y: coords.y }], annotation.text);
|
||||
});
|
||||
ast.accelerators.forEach((accelerator) => {
|
||||
const coords = toCoordinates(accelerator.x, accelerator.y, `Accelerator "${accelerator.name}"`);
|
||||
db.addAccelerator(accelerator.name, coords.x, coords.y);
|
||||
});
|
||||
ast.deaccelerators.forEach((deaccelerator) => {
|
||||
const coords = toCoordinates(
|
||||
deaccelerator.x,
|
||||
deaccelerator.y,
|
||||
`Deaccelerator "${deaccelerator.name}"`
|
||||
);
|
||||
db.addDeaccelerator(deaccelerator.name, coords.x, coords.y);
|
||||
});
|
||||
}, "populateDb");
|
||||
var parser = {
|
||||
parser: {
|
||||
// @ts-expect-error - WardleyDB is not assignable to DiagramDB
|
||||
yy: void 0
|
||||
},
|
||||
parse: /* @__PURE__ */ __name(async (input) => {
|
||||
const ast = await parse("wardley", input);
|
||||
log.debug(ast);
|
||||
const db = parser.parser?.yy;
|
||||
if (!db || typeof db.addNode !== "function") {
|
||||
throw new Error(
|
||||
"parser.parser?.yy was not a WardleyDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues."
|
||||
);
|
||||
}
|
||||
populateDb(ast, db);
|
||||
}, "parse")
|
||||
};
|
||||
|
||||
// src/diagrams/wardley/wardleyBuilder.ts
|
||||
var WardleyBuilder = class {
|
||||
constructor() {
|
||||
this.nodes = /* @__PURE__ */ new Map();
|
||||
this.links = [];
|
||||
this.trends = /* @__PURE__ */ new Map();
|
||||
this.pipelines = /* @__PURE__ */ new Map();
|
||||
this.annotations = [];
|
||||
this.notes = [];
|
||||
this.accelerators = [];
|
||||
this.deaccelerators = [];
|
||||
this.axes = {};
|
||||
}
|
||||
static {
|
||||
__name(this, "WardleyBuilder");
|
||||
}
|
||||
addNode(node) {
|
||||
const existing = this.nodes.get(node.id) ?? { id: node.id, label: node.label };
|
||||
const merged = {
|
||||
...existing,
|
||||
...node,
|
||||
className: node.className ?? existing.className,
|
||||
labelOffsetX: node.labelOffsetX ?? existing.labelOffsetX,
|
||||
labelOffsetY: node.labelOffsetY ?? existing.labelOffsetY
|
||||
};
|
||||
this.nodes.set(node.id, merged);
|
||||
}
|
||||
addLink(link) {
|
||||
this.links.push(link);
|
||||
}
|
||||
addTrend(trend) {
|
||||
this.trends.set(trend.nodeId, trend);
|
||||
}
|
||||
startPipeline(nodeId) {
|
||||
this.pipelines.set(nodeId, { nodeId, componentIds: [] });
|
||||
const node = this.nodes.get(nodeId);
|
||||
if (node) {
|
||||
node.isPipelineParent = true;
|
||||
}
|
||||
}
|
||||
addPipelineComponent(pipelineNodeId, componentId) {
|
||||
const pipeline = this.pipelines.get(pipelineNodeId);
|
||||
if (pipeline) {
|
||||
pipeline.componentIds.push(componentId);
|
||||
}
|
||||
const node = this.nodes.get(componentId);
|
||||
if (node) {
|
||||
node.inPipeline = true;
|
||||
}
|
||||
}
|
||||
addAnnotation(annotation) {
|
||||
this.annotations.push(annotation);
|
||||
}
|
||||
addNote(note) {
|
||||
this.notes.push(note);
|
||||
}
|
||||
addAccelerator(accelerator) {
|
||||
this.accelerators.push(accelerator);
|
||||
}
|
||||
addDeaccelerator(deaccelerator) {
|
||||
this.deaccelerators.push(deaccelerator);
|
||||
}
|
||||
setAnnotationsBox(x, y) {
|
||||
this.annotationsBox = { x, y };
|
||||
}
|
||||
setAxes(partial) {
|
||||
this.axes = {
|
||||
...this.axes,
|
||||
...partial
|
||||
};
|
||||
}
|
||||
setSize(width, height) {
|
||||
this.size = { width, height };
|
||||
}
|
||||
getNode(id) {
|
||||
return this.nodes.get(id);
|
||||
}
|
||||
build() {
|
||||
const nodes = [];
|
||||
for (const node of this.nodes.values()) {
|
||||
if (typeof node.x !== "number" || typeof node.y !== "number") {
|
||||
throw new Error(`Node "${node.label}" is missing coordinates`);
|
||||
}
|
||||
nodes.push(node);
|
||||
}
|
||||
return {
|
||||
nodes,
|
||||
links: [...this.links],
|
||||
trends: [...this.trends.values()],
|
||||
pipelines: [...this.pipelines.values()],
|
||||
annotations: [...this.annotations],
|
||||
notes: [...this.notes],
|
||||
accelerators: [...this.accelerators],
|
||||
deaccelerators: [...this.deaccelerators],
|
||||
annotationsBox: this.annotationsBox,
|
||||
axes: { ...this.axes },
|
||||
size: this.size
|
||||
};
|
||||
}
|
||||
clear() {
|
||||
this.nodes.clear();
|
||||
this.links = [];
|
||||
this.trends.clear();
|
||||
this.pipelines.clear();
|
||||
this.annotations = [];
|
||||
this.notes = [];
|
||||
this.accelerators = [];
|
||||
this.deaccelerators = [];
|
||||
this.annotationsBox = void 0;
|
||||
this.axes = {};
|
||||
this.size = void 0;
|
||||
}
|
||||
};
|
||||
|
||||
// src/diagrams/wardley/wardleyDb.ts
|
||||
var builder = new WardleyBuilder();
|
||||
function textSanitizer(text) {
|
||||
const config = getConfig();
|
||||
return sanitizeText(text.trim(), config);
|
||||
}
|
||||
__name(textSanitizer, "textSanitizer");
|
||||
function getConfig2() {
|
||||
return getConfig()["wardley-beta"];
|
||||
}
|
||||
__name(getConfig2, "getConfig");
|
||||
function addNode(id, label, x, y, className, labelOffsetX, labelOffsetY, inertia, sourceStrategy) {
|
||||
builder.addNode({
|
||||
id,
|
||||
label: textSanitizer(label),
|
||||
x,
|
||||
y,
|
||||
className,
|
||||
labelOffsetX,
|
||||
labelOffsetY,
|
||||
inertia,
|
||||
sourceStrategy
|
||||
});
|
||||
}
|
||||
__name(addNode, "addNode");
|
||||
function addLink(sourceId, targetId, dashed = false, label, flow) {
|
||||
builder.addLink({ source: sourceId, target: targetId, dashed, label, flow });
|
||||
}
|
||||
__name(addLink, "addLink");
|
||||
function addTrend(nodeId, targetX, targetY) {
|
||||
builder.addTrend({ nodeId, targetX, targetY });
|
||||
}
|
||||
__name(addTrend, "addTrend");
|
||||
function addAnnotation(number, coordinates, text) {
|
||||
builder.addAnnotation({
|
||||
number,
|
||||
coordinates,
|
||||
text: text ? textSanitizer(text) : void 0
|
||||
});
|
||||
}
|
||||
__name(addAnnotation, "addAnnotation");
|
||||
function addNote(text, x, y) {
|
||||
builder.addNote({
|
||||
text: textSanitizer(text),
|
||||
x,
|
||||
y
|
||||
});
|
||||
}
|
||||
__name(addNote, "addNote");
|
||||
function addAccelerator(name, x, y) {
|
||||
builder.addAccelerator({
|
||||
name: textSanitizer(name),
|
||||
x,
|
||||
y
|
||||
});
|
||||
}
|
||||
__name(addAccelerator, "addAccelerator");
|
||||
function addDeaccelerator(name, x, y) {
|
||||
builder.addDeaccelerator({
|
||||
name: textSanitizer(name),
|
||||
x,
|
||||
y
|
||||
});
|
||||
}
|
||||
__name(addDeaccelerator, "addDeaccelerator");
|
||||
function setAnnotationsBox(x, y) {
|
||||
builder.setAnnotationsBox(x, y);
|
||||
}
|
||||
__name(setAnnotationsBox, "setAnnotationsBox");
|
||||
function setSize(width, height) {
|
||||
builder.setSize(width, height);
|
||||
}
|
||||
__name(setSize, "setSize");
|
||||
function startPipeline(nodeId) {
|
||||
builder.startPipeline(nodeId);
|
||||
}
|
||||
__name(startPipeline, "startPipeline");
|
||||
function addPipelineComponent(pipelineNodeId, componentId) {
|
||||
builder.addPipelineComponent(pipelineNodeId, componentId);
|
||||
}
|
||||
__name(addPipelineComponent, "addPipelineComponent");
|
||||
function updateAxes(partial) {
|
||||
const sanitized = {};
|
||||
if (partial.xLabel) {
|
||||
sanitized.xLabel = textSanitizer(partial.xLabel);
|
||||
}
|
||||
if (partial.yLabel) {
|
||||
sanitized.yLabel = textSanitizer(partial.yLabel);
|
||||
}
|
||||
if (partial.stages) {
|
||||
sanitized.stages = partial.stages.map((stage) => textSanitizer(stage));
|
||||
}
|
||||
if (partial.stageBoundaries) {
|
||||
sanitized.stageBoundaries = partial.stageBoundaries;
|
||||
}
|
||||
builder.setAxes(sanitized);
|
||||
}
|
||||
__name(updateAxes, "updateAxes");
|
||||
function getNode(id) {
|
||||
return builder.getNode(id);
|
||||
}
|
||||
__name(getNode, "getNode");
|
||||
function getWardleyData() {
|
||||
return builder.build();
|
||||
}
|
||||
__name(getWardleyData, "getWardleyData");
|
||||
function clear2() {
|
||||
builder.clear();
|
||||
clear();
|
||||
}
|
||||
__name(clear2, "clear");
|
||||
var wardleyDb_default = {
|
||||
getConfig: getConfig2,
|
||||
addNode,
|
||||
addLink,
|
||||
addTrend,
|
||||
addAnnotation,
|
||||
addNote,
|
||||
addAccelerator,
|
||||
addDeaccelerator,
|
||||
setAnnotationsBox,
|
||||
setSize,
|
||||
startPipeline,
|
||||
addPipelineComponent,
|
||||
updateAxes,
|
||||
getNode,
|
||||
getWardleyData,
|
||||
clear: clear2,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription
|
||||
};
|
||||
|
||||
// src/diagrams/wardley/wardleyRenderer.ts
|
||||
var DEFAULT_STAGES = ["Genesis", "Custom Built", "Product", "Commodity"];
|
||||
var getTheme = /* @__PURE__ */ __name(() => {
|
||||
const { themeVariables } = getConfig();
|
||||
return {
|
||||
backgroundColor: themeVariables.wardley?.backgroundColor ?? themeVariables.background ?? "#fff",
|
||||
axisColor: themeVariables.wardley?.axisColor ?? "#000",
|
||||
axisTextColor: themeVariables.wardley?.axisTextColor ?? themeVariables.primaryTextColor ?? "#222",
|
||||
gridColor: themeVariables.wardley?.gridColor ?? "rgba(100, 100, 100, 0.2)",
|
||||
componentFill: themeVariables.wardley?.componentFill ?? "#fff",
|
||||
componentStroke: themeVariables.wardley?.componentStroke ?? "#000",
|
||||
componentLabelColor: themeVariables.wardley?.componentLabelColor ?? themeVariables.primaryTextColor ?? "#222",
|
||||
linkStroke: themeVariables.wardley?.linkStroke ?? "#000",
|
||||
evolutionStroke: themeVariables.wardley?.evolutionStroke ?? "#dc3545",
|
||||
annotationStroke: themeVariables.wardley?.annotationStroke ?? "#000",
|
||||
annotationTextColor: themeVariables.wardley?.annotationTextColor ?? themeVariables.primaryTextColor ?? "#222",
|
||||
annotationFill: themeVariables.wardley?.annotationFill ?? themeVariables.background ?? "#fff"
|
||||
};
|
||||
}, "getTheme");
|
||||
var getConfigValues = /* @__PURE__ */ __name(() => {
|
||||
const wardleyConfig = getConfig()["wardley-beta"];
|
||||
return {
|
||||
width: wardleyConfig?.width ?? 900,
|
||||
height: wardleyConfig?.height ?? 600,
|
||||
padding: wardleyConfig?.padding ?? 48,
|
||||
nodeRadius: wardleyConfig?.nodeRadius ?? 6,
|
||||
nodeLabelOffset: wardleyConfig?.nodeLabelOffset ?? 8,
|
||||
axisFontSize: wardleyConfig?.axisFontSize ?? 12,
|
||||
labelFontSize: wardleyConfig?.labelFontSize ?? 10,
|
||||
showGrid: wardleyConfig?.showGrid ?? false,
|
||||
useMaxWidth: wardleyConfig?.useMaxWidth ?? true
|
||||
};
|
||||
}, "getConfigValues");
|
||||
var draw = /* @__PURE__ */ __name((text, id, _version, diagObj) => {
|
||||
log.debug("Rendering Wardley map\n" + text);
|
||||
const configValues = getConfigValues();
|
||||
const theme = getTheme();
|
||||
const squareSize = configValues.nodeRadius * 1.6;
|
||||
const db = diagObj.db;
|
||||
const data = db.getWardleyData();
|
||||
const title = db.getDiagramTitle();
|
||||
const width = data.size?.width ?? configValues.width;
|
||||
const height = data.size?.height ?? configValues.height;
|
||||
const svg = selectSvgElement(id);
|
||||
svg.selectAll("*").remove();
|
||||
configureSvgSize(svg, height, width, configValues.useMaxWidth);
|
||||
svg.attr("viewBox", `0 0 ${width} ${height}`);
|
||||
const root = svg.append("g").attr("class", "wardley-map");
|
||||
const defs = svg.append("defs");
|
||||
defs.append("marker").attr("id", `arrow-${id}`).attr("viewBox", "0 0 10 10").attr("refX", 9).attr("refY", 5).attr("markerWidth", 6).attr("markerHeight", 6).attr("orient", "auto-start-reverse").append("path").attr("d", "M 0 0 L 10 5 L 0 10 z").attr("fill", theme.evolutionStroke).attr("stroke", "none");
|
||||
defs.append("marker").attr("id", `link-arrow-end-${id}`).attr("viewBox", "0 0 10 10").attr("refX", 9).attr("refY", 5).attr("markerWidth", 5).attr("markerHeight", 5).attr("orient", "auto").append("path").attr("d", "M 0 0 L 10 5 L 0 10 z").attr("fill", theme.linkStroke).attr("stroke", "none");
|
||||
defs.append("marker").attr("id", `link-arrow-start-${id}`).attr("viewBox", "0 0 10 10").attr("refX", 1).attr("refY", 5).attr("markerWidth", 5).attr("markerHeight", 5).attr("orient", "auto").append("path").attr("d", "M 10 0 L 0 5 L 10 10 z").attr("fill", theme.linkStroke).attr("stroke", "none");
|
||||
root.append("rect").attr("class", "wardley-background").attr("width", width).attr("height", height).attr("fill", theme.backgroundColor);
|
||||
const chartWidth = width - configValues.padding * 2;
|
||||
const chartHeight = height - configValues.padding * 2;
|
||||
if (title) {
|
||||
root.append("text").attr("class", "wardley-title").attr("x", width / 2).attr("y", configValues.padding / 2).attr("fill", theme.axisTextColor).attr("font-size", configValues.axisFontSize * 1.05).attr("font-weight", "bold").attr("text-anchor", "middle").attr("dominant-baseline", "middle").text(title);
|
||||
}
|
||||
const projectX = /* @__PURE__ */ __name((value) => configValues.padding + value / 100 * chartWidth, "projectX");
|
||||
const projectY = /* @__PURE__ */ __name((value) => height - configValues.padding - value / 100 * chartHeight, "projectY");
|
||||
const axisGroup = root.append("g").attr("class", "wardley-axes");
|
||||
axisGroup.append("line").attr("x1", configValues.padding).attr("x2", width - configValues.padding).attr("y1", height - configValues.padding).attr("y2", height - configValues.padding).attr("stroke", theme.axisColor).attr("stroke-width", 1);
|
||||
axisGroup.append("line").attr("x1", configValues.padding).attr("x2", configValues.padding).attr("y1", configValues.padding).attr("y2", height - configValues.padding).attr("stroke", theme.axisColor).attr("stroke-width", 1);
|
||||
const xLabel = data.axes.xLabel ?? "Evolution";
|
||||
const yLabel = data.axes.yLabel ?? "Visibility";
|
||||
axisGroup.append("text").attr("class", "wardley-axis-label wardley-axis-label-x").attr("x", configValues.padding + chartWidth / 2).attr("y", height - configValues.padding / 4).attr("fill", theme.axisTextColor).attr("font-size", configValues.axisFontSize).attr("font-weight", "bold").attr("text-anchor", "middle").text(xLabel);
|
||||
axisGroup.append("text").attr("class", "wardley-axis-label wardley-axis-label-y").attr("x", configValues.padding / 3).attr("y", configValues.padding + chartHeight / 2).attr("fill", theme.axisTextColor).attr("font-size", configValues.axisFontSize).attr("font-weight", "bold").attr("text-anchor", "middle").attr(
|
||||
"transform",
|
||||
`rotate(-90 ${configValues.padding / 3} ${configValues.padding + chartHeight / 2})`
|
||||
).text(yLabel);
|
||||
const stages = data.axes.stages && data.axes.stages.length > 0 ? data.axes.stages : DEFAULT_STAGES;
|
||||
if (stages.length > 0) {
|
||||
const stageGroup = root.append("g").attr("class", "wardley-stages");
|
||||
const boundaries = data.axes.stageBoundaries;
|
||||
const stagePositions = [];
|
||||
if (boundaries && boundaries.length === stages.length) {
|
||||
let prevBoundary = 0;
|
||||
boundaries.forEach((boundary) => {
|
||||
stagePositions.push({ start: prevBoundary, end: boundary });
|
||||
prevBoundary = boundary;
|
||||
});
|
||||
} else {
|
||||
const stageWidth = 1 / stages.length;
|
||||
stages.forEach((_, index) => {
|
||||
stagePositions.push({
|
||||
start: index * stageWidth,
|
||||
end: (index + 1) * stageWidth
|
||||
});
|
||||
});
|
||||
}
|
||||
stages.forEach((stage, index) => {
|
||||
const pos = stagePositions[index];
|
||||
const startX = configValues.padding + pos.start * chartWidth;
|
||||
const endX = configValues.padding + pos.end * chartWidth;
|
||||
const centerX = (startX + endX) / 2;
|
||||
if (index > 0) {
|
||||
stageGroup.append("line").attr("x1", startX).attr("x2", startX).attr("y1", configValues.padding).attr("y2", height - configValues.padding).attr("stroke", "#000").attr("stroke-width", 1).attr("stroke-dasharray", "5 5").attr("opacity", 0.8);
|
||||
}
|
||||
stageGroup.append("text").attr("class", "wardley-stage-label").attr("x", centerX).attr("y", height - configValues.padding / 1.5).attr("fill", theme.axisTextColor).attr("font-size", configValues.axisFontSize - 2).attr("text-anchor", "middle").text(stage);
|
||||
});
|
||||
}
|
||||
if (configValues.showGrid) {
|
||||
const gridGroup = root.append("g").attr("class", "wardley-grid");
|
||||
for (let i = 1; i < 4; i++) {
|
||||
const ratio = i / 4;
|
||||
const x = configValues.padding + chartWidth * ratio;
|
||||
gridGroup.append("line").attr("x1", x).attr("x2", x).attr("y1", configValues.padding).attr("y2", height - configValues.padding).attr("stroke", theme.gridColor).attr("stroke-dasharray", "2 6");
|
||||
gridGroup.append("line").attr("x1", configValues.padding).attr("x2", width - configValues.padding).attr("y1", height - configValues.padding - chartHeight * ratio).attr("y2", height - configValues.padding - chartHeight * ratio).attr("stroke", theme.gridColor).attr("stroke-dasharray", "2 6");
|
||||
}
|
||||
}
|
||||
const positions = /* @__PURE__ */ new Map();
|
||||
data.nodes.forEach((node) => {
|
||||
positions.set(node.id, {
|
||||
x: projectX(node.x),
|
||||
y: projectY(node.y),
|
||||
node
|
||||
});
|
||||
});
|
||||
if (data.pipelines.length > 0) {
|
||||
const pipelineGroup = root.append("g").attr("class", "wardley-pipelines");
|
||||
const pipelineLinksGroup = root.append("g").attr("class", "wardley-pipeline-links");
|
||||
data.pipelines.forEach((pipeline) => {
|
||||
if (pipeline.componentIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
const sortedComponents = pipeline.componentIds.map((id2) => ({ id: id2, pos: positions.get(id2), node: data.nodes.find((n) => n.id === id2) })).filter((c) => c.pos && c.node).sort((a, b) => a.node.x - b.node.x);
|
||||
for (let i = 0; i < sortedComponents.length - 1; i++) {
|
||||
const current = sortedComponents[i];
|
||||
const next = sortedComponents[i + 1];
|
||||
pipelineLinksGroup.append("line").attr("class", "wardley-pipeline-evolution-link").attr("x1", current.pos.x).attr("y1", current.pos.y).attr("x2", next.pos.x).attr("y2", next.pos.y).attr("stroke", theme.linkStroke).attr("stroke-width", 1).attr("stroke-dasharray", "4 4");
|
||||
}
|
||||
let minX = Infinity;
|
||||
let maxX = -Infinity;
|
||||
let y = 0;
|
||||
pipeline.componentIds.forEach((componentId) => {
|
||||
const pos = positions.get(componentId);
|
||||
if (pos) {
|
||||
minX = Math.min(minX, pos.x);
|
||||
maxX = Math.max(maxX, pos.x);
|
||||
y = pos.y;
|
||||
}
|
||||
});
|
||||
if (minX !== Infinity && maxX !== -Infinity) {
|
||||
const padding = 15;
|
||||
const height2 = configValues.nodeRadius * 4;
|
||||
const boxTop = y - height2 / 2;
|
||||
const parentPos = positions.get(pipeline.nodeId);
|
||||
if (parentPos) {
|
||||
const centerX = (minX + maxX) / 2;
|
||||
parentPos.x = centerX;
|
||||
parentPos.y = boxTop - squareSize / 6;
|
||||
}
|
||||
pipelineGroup.append("rect").attr("class", "wardley-pipeline-box").attr("x", minX - padding).attr("y", boxTop).attr("width", maxX - minX + padding * 2).attr("height", height2).attr("fill", "none").attr("stroke", theme.axisColor).attr("stroke-width", 1.5).attr("rx", 4).attr("ry", 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
const linksGroup = root.append("g").attr("class", "wardley-links");
|
||||
const pipelineMap = /* @__PURE__ */ new Map();
|
||||
data.pipelines.forEach((pipeline) => {
|
||||
pipelineMap.set(pipeline.nodeId, new Set(pipeline.componentIds));
|
||||
});
|
||||
const validLinks = data.links.filter((link) => {
|
||||
if (!positions.has(link.source) || !positions.has(link.target)) {
|
||||
return false;
|
||||
}
|
||||
const pipelineComponents = pipelineMap.get(link.target);
|
||||
if (pipelineComponents?.has(link.source)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
linksGroup.selectAll("line").data(validLinks).enter().append("line").attr("class", (link) => `wardley-link${link.dashed ? " wardley-link--dashed" : ""}`).attr("x1", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const sourceNode = data.nodes.find((n) => n.id === link.source);
|
||||
const radius = sourceNode.isPipelineParent ? squareSize / Math.sqrt(2) : configValues.nodeRadius;
|
||||
const dx = targetPos.x - sourcePos.x;
|
||||
const dy = targetPos.y - sourcePos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
return sourcePos.x + dx / distance * radius;
|
||||
}).attr("y1", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const sourceNode = data.nodes.find((n) => n.id === link.source);
|
||||
const radius = sourceNode.isPipelineParent ? squareSize / Math.sqrt(2) : configValues.nodeRadius;
|
||||
const dx = targetPos.x - sourcePos.x;
|
||||
const dy = targetPos.y - sourcePos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
return sourcePos.y + dy / distance * radius;
|
||||
}).attr("x2", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const targetNode = data.nodes.find((n) => n.id === link.target);
|
||||
const radius = targetNode.isPipelineParent ? squareSize / Math.sqrt(2) : configValues.nodeRadius;
|
||||
const dx = sourcePos.x - targetPos.x;
|
||||
const dy = sourcePos.y - targetPos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
return targetPos.x + dx / distance * radius;
|
||||
}).attr("y2", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const targetNode = data.nodes.find((n) => n.id === link.target);
|
||||
const radius = targetNode.isPipelineParent ? squareSize / Math.sqrt(2) : configValues.nodeRadius;
|
||||
const dx = sourcePos.x - targetPos.x;
|
||||
const dy = sourcePos.y - targetPos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
return targetPos.y + dy / distance * radius;
|
||||
}).attr("stroke", theme.linkStroke).attr("stroke-width", 1).attr("stroke-dasharray", (link) => link.dashed ? "6 6" : null).attr("marker-end", (link) => {
|
||||
if (link.flow === "forward" || link.flow === "bidirectional") {
|
||||
return `url(#link-arrow-end-${id})`;
|
||||
}
|
||||
return null;
|
||||
}).attr("marker-start", (link) => {
|
||||
if (link.flow === "backward" || link.flow === "bidirectional") {
|
||||
return `url(#link-arrow-start-${id})`;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
linksGroup.selectAll("text").data(validLinks.filter((link) => link.label)).enter().append("text").attr("class", "wardley-link-label").attr("x", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const midX = (sourcePos.x + targetPos.x) / 2;
|
||||
const dy = targetPos.y - sourcePos.y;
|
||||
const dx = targetPos.x - sourcePos.x;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const offset = 8;
|
||||
const perpX = dy / distance;
|
||||
return midX + perpX * offset;
|
||||
}).attr("y", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const midY = (sourcePos.y + targetPos.y) / 2;
|
||||
const dx = targetPos.x - sourcePos.x;
|
||||
const dy = targetPos.y - sourcePos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const offset = 8;
|
||||
const perpY = -dx / distance;
|
||||
return midY + perpY * offset;
|
||||
}).attr("fill", theme.axisTextColor).attr("font-size", configValues.labelFontSize).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("transform", (link) => {
|
||||
const sourcePos = positions.get(link.source);
|
||||
const targetPos = positions.get(link.target);
|
||||
const midX = (sourcePos.x + targetPos.x) / 2;
|
||||
const midY = (sourcePos.y + targetPos.y) / 2;
|
||||
const dx = targetPos.x - sourcePos.x;
|
||||
const dy = targetPos.y - sourcePos.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const offset = 8;
|
||||
const perpX = dy / distance;
|
||||
const perpY = -dx / distance;
|
||||
const labelX = midX + perpX * offset;
|
||||
const labelY = midY + perpY * offset;
|
||||
let angle = Math.atan2(dy, dx) * 180 / Math.PI;
|
||||
if (angle > 90 || angle < -90) {
|
||||
angle += 180;
|
||||
}
|
||||
return `rotate(${angle} ${labelX} ${labelY})`;
|
||||
}).text((link) => link.label);
|
||||
const trendGroup = root.append("g").attr("class", "wardley-trends");
|
||||
const trendsWithPositions = data.trends.map((trend) => {
|
||||
const origin = positions.get(trend.nodeId);
|
||||
if (!origin) {
|
||||
return null;
|
||||
}
|
||||
const targetX = projectX(trend.targetX);
|
||||
const targetY = projectY(trend.targetY);
|
||||
const dx = targetX - origin.x;
|
||||
const dy = targetY - origin.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const shortenBy = configValues.nodeRadius + 2;
|
||||
const adjustedX2 = distance > shortenBy ? targetX - dx / distance * shortenBy : targetX;
|
||||
const adjustedY2 = distance > shortenBy ? targetY - dy / distance * shortenBy : targetY;
|
||||
return {
|
||||
origin,
|
||||
targetX,
|
||||
targetY,
|
||||
adjustedX2,
|
||||
adjustedY2
|
||||
};
|
||||
}).filter((trend) => trend !== null);
|
||||
trendGroup.selectAll("line").data(trendsWithPositions).enter().append("line").attr("class", "wardley-trend").attr("x1", (trend) => trend.origin.x).attr("y1", (trend) => trend.origin.y).attr("x2", (trend) => trend.adjustedX2).attr("y2", (trend) => trend.adjustedY2).attr("stroke", theme.evolutionStroke).attr("stroke-width", 1).attr("stroke-dasharray", "4 4").attr("marker-end", `url(#arrow-${id})`);
|
||||
const nodesGroup = root.append("g").attr("class", "wardley-nodes");
|
||||
const nodeEnter = nodesGroup.selectAll("g").data(data.nodes).enter().append("g").attr(
|
||||
"class",
|
||||
(node) => ["wardley-node", node.className ? `wardley-node--${node.className}` : ""].filter(Boolean).join(" ")
|
||||
);
|
||||
nodeEnter.filter((node) => node.sourceStrategy === "outsource").append("circle").attr("class", "wardley-outsource-overlay").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y).attr("r", configValues.nodeRadius * 2).attr("fill", "#666").attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
nodeEnter.filter((node) => node.sourceStrategy === "buy").append("circle").attr("class", "wardley-buy-overlay").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y).attr("r", configValues.nodeRadius * 2).attr("fill", "#ccc").attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
nodeEnter.filter((node) => node.sourceStrategy === "build").append("circle").attr("class", "wardley-build-overlay").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y).attr("r", configValues.nodeRadius * 2).attr("fill", "#eee").attr("stroke", "#000").attr("stroke-width", 1);
|
||||
const marketNodes = nodeEnter.filter((node) => node.sourceStrategy === "market");
|
||||
marketNodes.append("circle").attr("class", "wardley-market-overlay").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y).attr("r", configValues.nodeRadius * 2).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
nodeEnter.filter(
|
||||
(node) => !node.isPipelineParent && node.sourceStrategy !== "market" && node.className !== "anchor"
|
||||
).append("circle").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y).attr("r", configValues.nodeRadius).attr("fill", theme.componentFill).attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
const smallCircleRadius = configValues.nodeRadius * 0.7;
|
||||
const triangleRadius = configValues.nodeRadius * 1.2;
|
||||
marketNodes.append("line").attr("class", "wardley-market-line").attr("x1", (node) => positions.get(node.id).x).attr("y1", (node) => positions.get(node.id).y - triangleRadius).attr("x2", (node) => positions.get(node.id).x - triangleRadius * Math.cos(Math.PI / 6)).attr("y2", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
marketNodes.append("line").attr("class", "wardley-market-line").attr("x1", (node) => positions.get(node.id).x - triangleRadius * Math.cos(Math.PI / 6)).attr("y1", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("x2", (node) => positions.get(node.id).x + triangleRadius * Math.cos(Math.PI / 6)).attr("y2", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
marketNodes.append("line").attr("class", "wardley-market-line").attr("x1", (node) => positions.get(node.id).x + triangleRadius * Math.cos(Math.PI / 6)).attr("y1", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("x2", (node) => positions.get(node.id).x).attr("y2", (node) => positions.get(node.id).y - triangleRadius).attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
marketNodes.append("circle").attr("class", "wardley-market-dot").attr("cx", (node) => positions.get(node.id).x).attr("cy", (node) => positions.get(node.id).y - triangleRadius).attr("r", smallCircleRadius).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 2);
|
||||
marketNodes.append("circle").attr("class", "wardley-market-dot").attr("cx", (node) => positions.get(node.id).x - triangleRadius * Math.cos(Math.PI / 6)).attr("cy", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("r", smallCircleRadius).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 2);
|
||||
marketNodes.append("circle").attr("class", "wardley-market-dot").attr("cx", (node) => positions.get(node.id).x + triangleRadius * Math.cos(Math.PI / 6)).attr("cy", (node) => positions.get(node.id).y + triangleRadius * Math.sin(Math.PI / 6)).attr("r", smallCircleRadius).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 2);
|
||||
nodeEnter.filter((node) => node.isPipelineParent === true).append("rect").attr("x", (node) => positions.get(node.id).x - squareSize / 2).attr("y", (node) => positions.get(node.id).y - squareSize / 2).attr("width", squareSize).attr("height", squareSize).attr("fill", theme.componentFill).attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
nodeEnter.filter((node) => node.inertia === true).append("line").attr("class", "wardley-inertia").attr("x1", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
let offset = node.isPipelineParent ? squareSize / 2 + 15 : configValues.nodeRadius + 15;
|
||||
if (node.sourceStrategy) {
|
||||
offset += configValues.nodeRadius + 10;
|
||||
}
|
||||
return pos.x + offset;
|
||||
}).attr("y1", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
const lineHeight = node.isPipelineParent ? squareSize : configValues.nodeRadius * 2;
|
||||
return pos.y - lineHeight / 2;
|
||||
}).attr("x2", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
let offset = node.isPipelineParent ? squareSize / 2 + 15 : configValues.nodeRadius + 15;
|
||||
if (node.sourceStrategy) {
|
||||
offset += configValues.nodeRadius + 10;
|
||||
}
|
||||
return pos.x + offset;
|
||||
}).attr("y2", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
const lineHeight = node.isPipelineParent ? squareSize : configValues.nodeRadius * 2;
|
||||
return pos.y + lineHeight / 2;
|
||||
}).attr("stroke", theme.componentStroke).attr("stroke-width", 6);
|
||||
nodeEnter.append("text").attr("x", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
if (node.className === "anchor") {
|
||||
return node.labelOffsetX !== void 0 ? pos.x + node.labelOffsetX : pos.x;
|
||||
}
|
||||
let defaultOffset = configValues.nodeLabelOffset;
|
||||
if (node.sourceStrategy && node.labelOffsetX === void 0) {
|
||||
defaultOffset += 10;
|
||||
}
|
||||
const customOffset = node.labelOffsetX ?? defaultOffset;
|
||||
return pos.x + customOffset;
|
||||
}).attr("y", (node) => {
|
||||
const pos = positions.get(node.id);
|
||||
if (node.className === "anchor") {
|
||||
return node.labelOffsetY !== void 0 ? pos.y + node.labelOffsetY : pos.y - 3;
|
||||
}
|
||||
let defaultOffset = -configValues.nodeLabelOffset;
|
||||
if (node.sourceStrategy && node.labelOffsetY === void 0) {
|
||||
defaultOffset -= 10;
|
||||
}
|
||||
const customOffset = node.labelOffsetY ?? defaultOffset;
|
||||
return pos.y + customOffset;
|
||||
}).attr("class", "wardley-node-label").attr("fill", (node) => {
|
||||
if (node.className === "evolved") {
|
||||
return theme.evolutionStroke;
|
||||
}
|
||||
if (node.className === "anchor") {
|
||||
return "#000";
|
||||
}
|
||||
return theme.componentLabelColor;
|
||||
}).attr("font-size", configValues.labelFontSize).attr("font-weight", (node) => node.className === "anchor" ? "bold" : "normal").attr("text-anchor", (node) => node.className === "anchor" ? "middle" : "start").attr("dominant-baseline", (node) => node.className === "anchor" ? "middle" : "auto").text((node) => node.label);
|
||||
if (data.annotations.length > 0) {
|
||||
const annotationsGroup = root.append("g").attr("class", "wardley-annotations");
|
||||
data.annotations.forEach((annotation) => {
|
||||
const projectedCoords = annotation.coordinates.map((coord) => ({
|
||||
x: projectX(coord.x),
|
||||
y: projectY(coord.y)
|
||||
}));
|
||||
if (projectedCoords.length > 1) {
|
||||
for (let i = 0; i < projectedCoords.length - 1; i++) {
|
||||
annotationsGroup.append("line").attr("class", "wardley-annotation-line").attr("x1", projectedCoords[i].x).attr("y1", projectedCoords[i].y).attr("x2", projectedCoords[i + 1].x).attr("y2", projectedCoords[i + 1].y).attr("stroke", theme.axisColor).attr("stroke-width", 1.5).attr("stroke-dasharray", "4 4");
|
||||
}
|
||||
}
|
||||
projectedCoords.forEach((coord) => {
|
||||
const annotationNode = annotationsGroup.append("g").attr("class", "wardley-annotation");
|
||||
annotationNode.append("circle").attr("cx", coord.x).attr("cy", coord.y).attr("r", 10).attr("fill", "white").attr("stroke", theme.axisColor).attr("stroke-width", 1.5);
|
||||
annotationNode.append("text").attr("x", coord.x).attr("y", coord.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", 10).attr("fill", theme.axisTextColor).attr("font-weight", "bold").text(annotation.number);
|
||||
});
|
||||
});
|
||||
if (data.annotationsBox) {
|
||||
let boxX = projectX(data.annotationsBox.x);
|
||||
let boxY = projectY(data.annotationsBox.y);
|
||||
const padding = 10;
|
||||
const lineHeight = 16;
|
||||
const fontSize = 11;
|
||||
const textBoxGroup = annotationsGroup.append("g").attr("class", "wardley-annotations-box");
|
||||
const sortedAnnotations = [...data.annotations].filter((a) => a.text).sort((a, b) => a.number - b.number);
|
||||
const textElements = [];
|
||||
sortedAnnotations.forEach((annotation, idx) => {
|
||||
const text2 = textBoxGroup.append("text").attr("x", boxX + padding).attr("y", boxY + padding + (idx + 1) * lineHeight).attr("font-size", fontSize).attr("fill", theme.axisTextColor).attr("text-anchor", "start").attr("dominant-baseline", "middle").text(`${annotation.number}. ${annotation.text}`);
|
||||
textElements.push(text2);
|
||||
});
|
||||
if (textElements.length > 0) {
|
||||
let maxWidth = 0;
|
||||
let maxHeight = 0;
|
||||
textElements.forEach((text2) => {
|
||||
const textNode = text2.node();
|
||||
const textWidth = textNode.getComputedTextLength();
|
||||
maxWidth = Math.max(maxWidth, textWidth);
|
||||
const bbox = textNode.getBBox();
|
||||
maxHeight = Math.max(maxHeight, bbox.height);
|
||||
});
|
||||
const boxWidth = maxWidth + padding * 2 + 105;
|
||||
const boxHeight = sortedAnnotations.length * lineHeight + padding * 2 + maxHeight / 2;
|
||||
const minX = configValues.padding;
|
||||
const maxX = width - configValues.padding - boxWidth;
|
||||
const minY = configValues.padding;
|
||||
const maxY = height - configValues.padding - boxHeight;
|
||||
boxX = Math.max(minX, Math.min(boxX, maxX));
|
||||
boxY = Math.max(minY, Math.min(boxY, maxY));
|
||||
textElements.forEach((text2, idx) => {
|
||||
text2.attr("x", boxX + padding).attr("y", boxY + padding + (idx + 1) * lineHeight);
|
||||
});
|
||||
textBoxGroup.insert("rect", "text").attr("x", boxX).attr("y", boxY).attr("width", boxWidth).attr("height", boxHeight).attr("fill", "white").attr("stroke", theme.axisColor).attr("stroke-width", 1.5).attr("rx", 4).attr("ry", 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.notes.length > 0) {
|
||||
const notesGroup = root.append("g").attr("class", "wardley-notes");
|
||||
data.notes.forEach((note) => {
|
||||
const noteX = projectX(note.x);
|
||||
const noteY = projectY(note.y);
|
||||
notesGroup.append("text").attr("x", noteX).attr("y", noteY).attr("text-anchor", "start").attr("font-size", 11).attr("fill", theme.axisTextColor).attr("font-weight", "bold").text(note.text);
|
||||
});
|
||||
}
|
||||
if (data.accelerators.length > 0) {
|
||||
const acceleratorsGroup = root.append("g").attr("class", "wardley-accelerators");
|
||||
data.accelerators.forEach((accelerator) => {
|
||||
const accX = projectX(accelerator.x);
|
||||
const accY = projectY(accelerator.y);
|
||||
const arrowWidth = 60;
|
||||
const arrowHeight = 30;
|
||||
const arrowHeadWidth = 20;
|
||||
const arrowPath = `
|
||||
M ${accX} ${accY - arrowHeight / 2}
|
||||
L ${accX + arrowWidth - arrowHeadWidth} ${accY - arrowHeight / 2}
|
||||
L ${accX + arrowWidth - arrowHeadWidth} ${accY - arrowHeight / 2 - 8}
|
||||
L ${accX + arrowWidth} ${accY}
|
||||
L ${accX + arrowWidth - arrowHeadWidth} ${accY + arrowHeight / 2 + 8}
|
||||
L ${accX + arrowWidth - arrowHeadWidth} ${accY + arrowHeight / 2}
|
||||
L ${accX} ${accY + arrowHeight / 2}
|
||||
Z
|
||||
`;
|
||||
acceleratorsGroup.append("path").attr("d", arrowPath).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
acceleratorsGroup.append("text").attr("x", accX + arrowWidth / 2).attr("y", accY + arrowHeight / 2 + 15).attr("text-anchor", "middle").attr("font-size", 10).attr("fill", theme.axisTextColor).attr("font-weight", "bold").text(accelerator.name);
|
||||
});
|
||||
}
|
||||
if (data.deaccelerators.length > 0) {
|
||||
const deacceleratorsGroup = root.append("g").attr("class", "wardley-deaccelerators");
|
||||
data.deaccelerators.forEach((deaccelerator) => {
|
||||
const decX = projectX(deaccelerator.x);
|
||||
const decY = projectY(deaccelerator.y);
|
||||
const arrowWidth = 60;
|
||||
const arrowHeight = 30;
|
||||
const arrowHeadWidth = 20;
|
||||
const arrowPath = `
|
||||
M ${decX + arrowWidth} ${decY - arrowHeight / 2}
|
||||
L ${decX + arrowHeadWidth} ${decY - arrowHeight / 2}
|
||||
L ${decX + arrowHeadWidth} ${decY - arrowHeight / 2 - 8}
|
||||
L ${decX} ${decY}
|
||||
L ${decX + arrowHeadWidth} ${decY + arrowHeight / 2 + 8}
|
||||
L ${decX + arrowHeadWidth} ${decY + arrowHeight / 2}
|
||||
L ${decX + arrowWidth} ${decY + arrowHeight / 2}
|
||||
Z
|
||||
`;
|
||||
deacceleratorsGroup.append("path").attr("d", arrowPath).attr("fill", "white").attr("stroke", theme.componentStroke).attr("stroke-width", 1);
|
||||
deacceleratorsGroup.append("text").attr("x", decX + arrowWidth / 2).attr("y", decY + arrowHeight / 2 + 15).attr("text-anchor", "middle").attr("font-size", 10).attr("fill", theme.axisTextColor).attr("font-weight", "bold").text(deaccelerator.name);
|
||||
});
|
||||
}
|
||||
}, "draw");
|
||||
var wardleyRenderer_default = {
|
||||
draw
|
||||
};
|
||||
|
||||
// src/diagrams/wardley/wardleyDiagram.ts
|
||||
var diagram = {
|
||||
parser,
|
||||
db: wardleyDb_default,
|
||||
renderer: wardleyRenderer_default,
|
||||
styles: /* @__PURE__ */ __name(() => "", "styles")
|
||||
};
|
||||
export {
|
||||
diagram
|
||||
};
|
||||
Generated
Vendored
+7
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user