mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-23 16:04:12 +02:00
Merge pull request #5606 from mermaid-js/sidv/5237_Cleanup
chore: 5237 Cleanup
This commit is contained in:
@@ -3,8 +3,7 @@ export interface TreeData {
|
|||||||
childrenById: Record<string, string[]>;
|
childrenById: Record<string, string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData) => {
|
export const findCommonAncestor = (id1: string, id2: string, { parentById }: TreeData) => {
|
||||||
const { parentById } = treeData;
|
|
||||||
const visited = new Set();
|
const visited = new Set();
|
||||||
let currentId = id1;
|
let currentId = id1;
|
||||||
|
|
||||||
@@ -20,6 +19,7 @@ export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData)
|
|||||||
}
|
}
|
||||||
currentId = parentById[currentId];
|
currentId = parentById[currentId];
|
||||||
}
|
}
|
||||||
|
|
||||||
currentId = id2;
|
currentId = id2;
|
||||||
while (currentId) {
|
while (currentId) {
|
||||||
if (visited.has(currentId)) {
|
if (visited.has(currentId)) {
|
||||||
@@ -27,5 +27,6 @@ export const findCommonAncestor = (id1: string, id2: string, treeData: TreeData)
|
|||||||
}
|
}
|
||||||
currentId = parentById[currentId];
|
currentId = parentById[currentId];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'root';
|
return 'root';
|
||||||
};
|
};
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
// @ts-nocheck File not ready to check types
|
// @ts-nocheck File not ready to check types
|
||||||
import { curveLinear } from 'd3';
|
import { curveLinear } from 'd3';
|
||||||
import ELK from 'elkjs/lib/elk.bundled.js';
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
||||||
import mermaid from 'mermaid';
|
import mermaid, { type LayoutData } from 'mermaid';
|
||||||
import { findCommonAncestor } from './find-common-ancestor.js';
|
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
common,
|
common,
|
||||||
@@ -201,13 +201,13 @@ const getNextPort = (node, edgeDirection, graphDirection) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addSubGraphs = function (nodeArr) {
|
const addSubGraphs = (nodeArr): TreeData => {
|
||||||
const parentLookupDb = { parentById: {}, childrenById: {} };
|
const parentLookupDb: TreeData = { parentById: {}, childrenById: {} };
|
||||||
const subgraphs = nodeArr.filter((node) => node.isGroup);
|
const subgraphs = nodeArr.filter((node) => node.isGroup);
|
||||||
log.info('Subgraphs - ', subgraphs);
|
log.info('Subgraphs - ', subgraphs);
|
||||||
subgraphs.forEach(function (subgraph) {
|
subgraphs.forEach((subgraph) => {
|
||||||
const children = nodeArr.filter((node) => node.parentId === subgraph.id);
|
const children = nodeArr.filter((node) => node.parentId === subgraph.id);
|
||||||
children.forEach(function (node) {
|
children.forEach((node) => {
|
||||||
parentLookupDb.parentById[node.id] = subgraph.id;
|
parentLookupDb.parentById[node.id] = subgraph.id;
|
||||||
if (parentLookupDb.childrenById[subgraph.id] === undefined) {
|
if (parentLookupDb.childrenById[subgraph.id] === undefined) {
|
||||||
parentLookupDb.childrenById[subgraph.id] = [];
|
parentLookupDb.childrenById[subgraph.id] = [];
|
||||||
@@ -252,7 +252,7 @@ const getEdgeStartEndPoint = (edge, dir) => {
|
|||||||
return { source, target, sourceId, targetId };
|
return { source, target, sourceId, targetId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const calcOffset = function (src, dest, parentLookupDb) {
|
const calcOffset = function (src: string, dest: string, parentLookupDb: TreeData) {
|
||||||
const ancestor = findCommonAncestor(src, dest, parentLookupDb);
|
const ancestor = findCommonAncestor(src, dest, parentLookupDb);
|
||||||
if (ancestor === undefined || ancestor === 'root') {
|
if (ancestor === undefined || ancestor === 'root') {
|
||||||
return { x: 0, y: 0 };
|
return { x: 0, y: 0 };
|
||||||
@@ -351,11 +351,6 @@ export const addEdges = async function (dataForLayout, graph, svg) {
|
|||||||
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// if (edge.style !== undefined) {
|
|
||||||
// const styles = getStylesFromArray(edge.style);
|
|
||||||
// style = styles.style;
|
|
||||||
// labelStyle = styles.labelStyle;
|
|
||||||
// }
|
|
||||||
|
|
||||||
edgeData.style = edgeData.style += style;
|
edgeData.style = edgeData.style += style;
|
||||||
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
|
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
|
||||||
@@ -455,7 +450,7 @@ function setIncludeChildrenPolicy(nodeId: string, ancestorId: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const render = async (data4Layout, svg, element, algorithm) => {
|
export const render = async (data4Layout: LayoutData, svg, element, algorithm) => {
|
||||||
const elk = new ELK();
|
const elk = new ELK();
|
||||||
|
|
||||||
// Add the arrowheads to the svg
|
// Add the arrowheads to the svg
|
||||||
@@ -558,9 +553,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// log.info('before layout', JSON.stringify(elkGraph, null, 2));
|
|
||||||
const g = await elk.layout(elkGraph);
|
const g = await elk.layout(elkGraph);
|
||||||
// log.info('after layout', JSON.stringify(g));
|
|
||||||
|
|
||||||
// debugger;
|
// debugger;
|
||||||
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||||
@@ -688,6 +681,32 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||||
positionEdgeLabel(edge, paths);
|
positionEdgeLabel(edge, paths);
|
||||||
}
|
}
|
||||||
|
const src = edge.sections[0].startPoint;
|
||||||
|
const dest = edge.sections[0].endPoint;
|
||||||
|
const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];
|
||||||
|
|
||||||
|
const segPoints = segments.map((segment) => {
|
||||||
|
return { x: segment.x + offset.x, y: segment.y + offset.y };
|
||||||
|
});
|
||||||
|
edge.points = [
|
||||||
|
{ x: src.x + offset.x, y: src.y + offset.y },
|
||||||
|
...segPoints,
|
||||||
|
{ x: dest.x + offset.x, y: dest.y + offset.y },
|
||||||
|
];
|
||||||
|
const paths = insertEdge(
|
||||||
|
edgesEl,
|
||||||
|
edge,
|
||||||
|
clusterDb,
|
||||||
|
data4Layout.type,
|
||||||
|
startNode,
|
||||||
|
endNode,
|
||||||
|
data4Layout.diagramId
|
||||||
|
);
|
||||||
|
log.info('APA12 edge points after insert', JSON.stringify(edge.points));
|
||||||
|
|
||||||
|
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
||||||
|
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||||
|
positionEdgeLabel(edge, paths);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -696,10 +715,10 @@ function intersectLine(p1, p2, q1, q2) {
|
|||||||
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
||||||
// p7 and p473.
|
// p7 and p473.
|
||||||
|
|
||||||
var a1, a2, b1, b2, c1, c2;
|
let a1, a2, b1, b2, c1, c2;
|
||||||
var r1, r2, r3, r4;
|
let r1, r2, r3, r4;
|
||||||
var denom, offset, num;
|
let denom, offset, num;
|
||||||
var x, y;
|
let x, y;
|
||||||
|
|
||||||
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
|
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
|
||||||
// b1 y + c1 = 0.
|
// b1 y + c1 = 0.
|
||||||
@@ -761,8 +780,8 @@ function sameSign(r1, r2) {
|
|||||||
return r1 * r2 > 0;
|
return r1 * r2 > 0;
|
||||||
}
|
}
|
||||||
const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
||||||
var x1 = bounds.x;
|
const x1 = bounds.x;
|
||||||
var y1 = bounds.y;
|
const y1 = bounds.y;
|
||||||
|
|
||||||
const w = bounds.width; //+ bounds.padding;
|
const w = bounds.width; //+ bounds.padding;
|
||||||
const h = bounds.height; // + bounds.padding;
|
const h = bounds.height; // + bounds.padding;
|
||||||
@@ -782,10 +801,10 @@ const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
|||||||
polyPoints
|
polyPoints
|
||||||
);
|
);
|
||||||
|
|
||||||
var intersections = [];
|
const intersections = [];
|
||||||
|
|
||||||
var minX = Number.POSITIVE_INFINITY;
|
let minX = Number.POSITIVE_INFINITY;
|
||||||
var minY = Number.POSITIVE_INFINITY;
|
let minY = Number.POSITIVE_INFINITY;
|
||||||
if (typeof polyPoints.forEach === 'function') {
|
if (typeof polyPoints.forEach === 'function') {
|
||||||
polyPoints.forEach(function (entry) {
|
polyPoints.forEach(function (entry) {
|
||||||
minX = Math.min(minX, entry.x);
|
minX = Math.min(minX, entry.x);
|
||||||
@@ -796,13 +815,18 @@ const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
|||||||
minY = Math.min(minY, polyPoints.y);
|
minY = Math.min(minY, polyPoints.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
var left = x1 - w / 2;
|
const left = x1 - w / 2;
|
||||||
var top = y1 + h / 2;
|
const top = y1 + h / 2;
|
||||||
|
|
||||||
for (var i = 0; i < polyPoints.length; i++) {
|
for (let i = 0; i < polyPoints.length; i++) {
|
||||||
var p1 = polyPoints[i];
|
const p1 = polyPoints[i];
|
||||||
var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
const p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
||||||
var intersect = intersectLine(bounds, outsidePoint, { x: p1.x, y: p1.y }, { x: p2.x, y: p2.y });
|
const intersect = intersectLine(
|
||||||
|
bounds,
|
||||||
|
outsidePoint,
|
||||||
|
{ x: p1.x, y: p1.y },
|
||||||
|
{ x: p2.x, y: p2.y }
|
||||||
|
);
|
||||||
|
|
||||||
if (intersect) {
|
if (intersect) {
|
||||||
intersections.push(intersect);
|
intersections.push(intersect);
|
||||||
@@ -818,13 +842,13 @@ const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
|||||||
if (intersections.length > 1) {
|
if (intersections.length > 1) {
|
||||||
// More intersections, find the one nearest to edge end point
|
// More intersections, find the one nearest to edge end point
|
||||||
intersections.sort(function (p, q) {
|
intersections.sort(function (p, q) {
|
||||||
var pdx = p.x - outsidePoint.x;
|
const pdx = p.x - outsidePoint.x;
|
||||||
var pdy = p.y - outsidePoint.y;
|
const pdy = p.y - outsidePoint.y;
|
||||||
var distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
const distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
||||||
|
|
||||||
var qdx = q.x - outsidePoint.x;
|
const qdx = q.x - outsidePoint.x;
|
||||||
var qdy = q.y - outsidePoint.y;
|
const qdy = q.y - outsidePoint.y;
|
||||||
var distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
const distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
||||||
|
|
||||||
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
||||||
});
|
});
|
||||||
@@ -852,7 +876,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
|||||||
|
|
||||||
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
||||||
// Intersection is top or bottom of rect.
|
// Intersection is top or bottom of rect.
|
||||||
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
const q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||||
r = (R * q) / Q;
|
r = (R * q) / Q;
|
||||||
const res = {
|
const res = {
|
||||||
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
|
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
|
||||||
@@ -881,7 +905,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
|||||||
// r = outsidePoint.x - w - x;
|
// r = outsidePoint.x - w - x;
|
||||||
r = x - w - outsidePoint.x;
|
r = x - w - outsidePoint.x;
|
||||||
}
|
}
|
||||||
let q = (Q * r) / R;
|
const q = (Q * r) / R;
|
||||||
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;
|
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;
|
||||||
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
|
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
|
||||||
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
|
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
|
||||||
@@ -925,7 +949,7 @@ const outsideNode = (node, point) => {
|
|||||||
*/
|
*/
|
||||||
const cutPathAtIntersect = (_points, bounds, isDiamond: boolean) => {
|
const cutPathAtIntersect = (_points, bounds, isDiamond: boolean) => {
|
||||||
console.log('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
console.log('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||||
let points = [];
|
const points = [];
|
||||||
let lastPointOutside = _points[0];
|
let lastPointOutside = _points[0];
|
||||||
let isInside = false;
|
let isInside = false;
|
||||||
_points.forEach((point) => {
|
_points.forEach((point) => {
|
||||||
@@ -939,7 +963,7 @@ const cutPathAtIntersect = (_points, bounds, isDiamond: boolean) => {
|
|||||||
let inter;
|
let inter;
|
||||||
|
|
||||||
if (isDiamond) {
|
if (isDiamond) {
|
||||||
let inter2 = diamondIntersection(bounds, lastPointOutside, point);
|
const inter2 = diamondIntersection(bounds, lastPointOutside, point);
|
||||||
const distance = Math.sqrt(
|
const distance = Math.sqrt(
|
||||||
(lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
|
(lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
|
||||||
);
|
);
|
||||||
|
@@ -15,8 +15,6 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
|||||||
classes = _classes;
|
classes = _classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('parentY', parent.node());
|
|
||||||
|
|
||||||
// Add outer g element
|
// Add outer g element
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
.insert('g')
|
.insert('g')
|
||||||
@@ -35,7 +33,6 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const textNode = label.node();
|
const textNode = label.node();
|
||||||
// console.log('parentX', parent, 'node',node,'labelText',labelText, textNode, node.labelType, 'label', label.node());
|
|
||||||
let text;
|
let text;
|
||||||
if (node.labelType === 'markdown') {
|
if (node.labelType === 'markdown') {
|
||||||
// text = textNode;
|
// text = textNode;
|
||||||
|
@@ -26,7 +26,7 @@ const detector: DiagramDetector = (txt, config): boolean => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
// @ts-ignore - TODO: Fix after refactor
|
|
||||||
const loader: DiagramLoader = async () => {
|
const loader: DiagramLoader = async () => {
|
||||||
const { diagram } = await import('../flowDiagram-v2.js');
|
const { diagram } = await import('../flowDiagram-v2.js');
|
||||||
return { id, diagram };
|
return { id, diagram };
|
||||||
|
@@ -729,14 +729,12 @@ export const destructLink = (_str: string, _startStr: string) => {
|
|||||||
|
|
||||||
// Todo optimizer this by caching existing nodes
|
// Todo optimizer this by caching existing nodes
|
||||||
const exists = (allSgs: FlowSubGraph[], _id: string) => {
|
const exists = (allSgs: FlowSubGraph[], _id: string) => {
|
||||||
let res = false;
|
for (const sg of allSgs) {
|
||||||
allSgs.forEach((sg) => {
|
if (sg.nodes.indexOf(_id) >= 0) {
|
||||||
const pos = sg.nodes.indexOf(_id);
|
return true;
|
||||||
if (pos >= 0) {
|
|
||||||
res = true;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return res;
|
return false;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Deletes an id from all subgraphs
|
* Deletes an id from all subgraphs
|
||||||
@@ -787,6 +785,7 @@ const destructEdgeType = (type: string | undefined) => {
|
|||||||
}
|
}
|
||||||
return { arrowTypeStart, arrowTypeEnd };
|
return { arrowTypeStart, arrowTypeEnd };
|
||||||
};
|
};
|
||||||
|
|
||||||
const addNodeFromVertex = (
|
const addNodeFromVertex = (
|
||||||
vertex: FlowVertex,
|
vertex: FlowVertex,
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
@@ -799,7 +798,11 @@ const addNodeFromVertex = (
|
|||||||
const isGroup = subGraphDB.get(vertex.id) ?? false;
|
const isGroup = subGraphDB.get(vertex.id) ?? false;
|
||||||
|
|
||||||
const node = findNode(nodes, vertex.id);
|
const node = findNode(nodes, vertex.id);
|
||||||
if (!node) {
|
if (node) {
|
||||||
|
node.cssStyles = vertex.styles;
|
||||||
|
node.cssCompiledStyles = getCompiledStyles(vertex.classes);
|
||||||
|
node.cssClasses = vertex.classes.join(' ');
|
||||||
|
} else {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
id: vertex.id,
|
id: vertex.id,
|
||||||
label: vertex.text,
|
label: vertex.text,
|
||||||
@@ -818,10 +821,6 @@ const addNodeFromVertex = (
|
|||||||
linkTarget: vertex.linkTarget,
|
linkTarget: vertex.linkTarget,
|
||||||
tooltip: getTooltip(vertex.id),
|
tooltip: getTooltip(vertex.id),
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
node.cssStyles = vertex.styles;
|
|
||||||
node.cssCompiledStyles = getCompiledStyles(vertex.classes);
|
|
||||||
node.cssClasses = vertex.classes.join(' ');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -829,14 +828,11 @@ function getCompiledStyles(classDefs: string[]) {
|
|||||||
let compiledStyles: string[] = [];
|
let compiledStyles: string[] = [];
|
||||||
for (const customClass of classDefs) {
|
for (const customClass of classDefs) {
|
||||||
const cssClass = classes.get(customClass);
|
const cssClass = classes.get(customClass);
|
||||||
// log.debug('IPI cssClass in flowDb', cssClass);
|
if (cssClass?.styles) {
|
||||||
if (cssClass) {
|
compiledStyles = [...compiledStyles, ...(cssClass.styles ?? [])].map((s) => s.trim());
|
||||||
if (cssClass.styles) {
|
}
|
||||||
compiledStyles = [...compiledStyles, ...(cssClass.styles ?? [])].map((s) => s.trim());
|
if (cssClass?.textStyles) {
|
||||||
}
|
compiledStyles = [...compiledStyles, ...(cssClass.textStyles ?? [])].map((s) => s.trim());
|
||||||
if (cssClass.textStyles) {
|
|
||||||
compiledStyles = [...compiledStyles, ...(cssClass.textStyles ?? [])].map((s) => s.trim());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return compiledStyles;
|
return compiledStyles;
|
||||||
@@ -857,9 +853,9 @@ export const getData = () => {
|
|||||||
if (subGraph.nodes.length > 0) {
|
if (subGraph.nodes.length > 0) {
|
||||||
subGraphDB.set(subGraph.id, true);
|
subGraphDB.set(subGraph.id, true);
|
||||||
}
|
}
|
||||||
subGraph.nodes.forEach((id) => {
|
for (const id of subGraph.nodes) {
|
||||||
parentDB.set(id, subGraph.id);
|
parentDB.set(id, subGraph.id);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data is setup, add the nodes
|
// Data is setup, add the nodes
|
||||||
@@ -917,8 +913,6 @@ export const getData = () => {
|
|||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
});
|
});
|
||||||
|
|
||||||
// log.debug('IPI nodes', JSON.stringify(nodes, null, 2));
|
|
||||||
|
|
||||||
return { nodes, edges, other: {}, config };
|
return { nodes, edges, other: {}, config };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@ const detector: DiagramDetector = (txt, config) => {
|
|||||||
return /^\s*flowchart/.test(txt);
|
return /^\s*flowchart/.test(txt);
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore - TODO: Fix after refactor
|
|
||||||
const loader: DiagramLoader = async () => {
|
const loader: DiagramLoader = async () => {
|
||||||
const { diagram } = await import('./flowDiagram-v2.js');
|
const { diagram } = await import('./flowDiagram-v2.js');
|
||||||
return { id, diagram };
|
return { id, diagram };
|
||||||
|
@@ -9,7 +9,6 @@ import { setConfig } from '../../diagram-api/diagramAPI.js';
|
|||||||
export const diagram = {
|
export const diagram = {
|
||||||
parser: flowParser,
|
parser: flowParser,
|
||||||
db: flowDb,
|
db: flowDb,
|
||||||
// renderer: flowRendererV2,
|
|
||||||
renderer: flowRendererV3,
|
renderer: flowRendererV3,
|
||||||
styles: flowStyles,
|
styles: flowStyles,
|
||||||
init: (cnf: MermaidConfig) => {
|
init: (cnf: MermaidConfig) => {
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
// @ts-ignore: JISON doesn't support types
|
|
||||||
import flowParser from './parser/flow.jison';
|
|
||||||
import flowDb from './flowDb.js';
|
|
||||||
import flowRendererV2 from './flowRenderer-v2.js';
|
|
||||||
import flowStyles from './styles.js';
|
|
||||||
import type { MermaidConfig } from '../../config.type.js';
|
|
||||||
import { setConfig } from '../../diagram-api/diagramAPI.js';
|
|
||||||
|
|
||||||
export const diagram = {
|
|
||||||
parser: flowParser,
|
|
||||||
db: flowDb,
|
|
||||||
renderer: flowRendererV2,
|
|
||||||
styles: flowStyles,
|
|
||||||
init: (cnf: MermaidConfig) => {
|
|
||||||
if (!cnf.flowchart) {
|
|
||||||
cnf.flowchart = {};
|
|
||||||
}
|
|
||||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
|
||||||
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
|
|
||||||
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
|
||||||
flowRendererV2.setConf(cnf.flowchart);
|
|
||||||
flowDb.clear();
|
|
||||||
flowDb.setGen('gen-2');
|
|
||||||
},
|
|
||||||
};
|
|
@@ -29,7 +29,6 @@ export const setConf = function (cnf) {
|
|||||||
*/
|
*/
|
||||||
export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
|
export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
|
||||||
const svg = root.select(`[id="${svgId}"]`);
|
const svg = root.select(`[id="${svgId}"]`);
|
||||||
// console.log('SVG:', svg, svg.node(), 'root:', root, root.node());
|
|
||||||
|
|
||||||
const keys = vert.keys();
|
const keys = vert.keys();
|
||||||
|
|
||||||
|
@@ -1,30 +1,18 @@
|
|||||||
import { log } from '../../logger.js';
|
|
||||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
|
||||||
import type { LayoutData } from '../../rendering-util/types.js';
|
|
||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
|
||||||
import { render } from '../../rendering-util/render.js';
|
|
||||||
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
|
|
||||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
|
||||||
import { getDirection } from './flowDb.js';
|
|
||||||
|
|
||||||
import utils from '../../utils.js';
|
|
||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
// Configuration
|
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
const conf: Record<string, any> = {};
|
import { log } from '../../logger.js';
|
||||||
|
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
|
||||||
export const setConf = function (cnf: Record<string, any>) {
|
import { render } from '../../rendering-util/render.js';
|
||||||
const keys = Object.keys(cnf);
|
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
||||||
for (const key of keys) {
|
import type { LayoutData } from '../../rendering-util/types.js';
|
||||||
conf[key] = cnf[key];
|
import utils from '../../utils.js';
|
||||||
}
|
import { getDirection } from './flowDb.js';
|
||||||
};
|
|
||||||
|
|
||||||
export const getClasses = function (
|
export const getClasses = function (
|
||||||
text: string,
|
text: string,
|
||||||
diagramObj: any
|
diagramObj: any
|
||||||
): Record<string, DiagramStyleClassDef> {
|
): Map<string, DiagramStyleClassDef> {
|
||||||
// diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
|
||||||
return diagramObj.db.getClasses();
|
return diagramObj.db.getClasses();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,8 +30,6 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
// @ts-ignore - document is always available
|
// @ts-ignore - document is always available
|
||||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||||
|
|
||||||
const DIR = getDirection();
|
|
||||||
|
|
||||||
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||||
// into the Layout data format
|
// into the Layout data format
|
||||||
log.debug('Before getData: ');
|
log.debug('Before getData: ');
|
||||||
@@ -51,10 +37,11 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
log.debug('Data: ', data4Layout);
|
log.debug('Data: ', data4Layout);
|
||||||
// Create the root SVG - the element is the div containing the SVG element
|
// Create the root SVG - the element is the div containing the SVG element
|
||||||
const { element, svg } = getDiagramElements(id, securityLevel);
|
const { element, svg } = getDiagramElements(id, securityLevel);
|
||||||
|
const direction = getDirection();
|
||||||
|
|
||||||
data4Layout.type = diag.type;
|
data4Layout.type = diag.type;
|
||||||
data4Layout.layoutAlgorithm = layout;
|
data4Layout.layoutAlgorithm = layout;
|
||||||
data4Layout.direction = DIR;
|
data4Layout.direction = direction;
|
||||||
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||||
data4Layout.markers = ['point', 'circle', 'cross'];
|
data4Layout.markers = ['point', 'circle', 'cross'];
|
||||||
@@ -72,43 +59,41 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
setupViewPortForSVG(svg, padding, 'flowchart', conf?.useMaxWidth || false);
|
setupViewPortForSVG(svg, padding, 'flowchart', conf?.useMaxWidth || false);
|
||||||
|
|
||||||
// If node has a link, wrap it in an anchor SVG object.
|
// If node has a link, wrap it in an anchor SVG object.
|
||||||
data4Layout.nodes.forEach((vertex) => {
|
for (const vertex of data4Layout.nodes) {
|
||||||
if (vertex.link) {
|
const node = select(`#${id} [id="${vertex.id}"]`);
|
||||||
const node = select('#' + id + ' [id="' + vertex.id + '"]');
|
if (!node || !vertex.link) {
|
||||||
if (node) {
|
continue;
|
||||||
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.cssClasses);
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
|
||||||
if (securityLevel === 'sandbox') {
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
|
|
||||||
} else if (vertex.linkTarget) {
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkNode = node.insert(function () {
|
|
||||||
return link;
|
|
||||||
}, ':first-child');
|
|
||||||
|
|
||||||
const shape = node.select('.label-container');
|
|
||||||
if (shape) {
|
|
||||||
linkNode.append(function () {
|
|
||||||
return shape.node();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const label = node.select('.label');
|
|
||||||
if (label) {
|
|
||||||
linkNode.append(function () {
|
|
||||||
return label.node();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.cssClasses);
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
||||||
|
if (securityLevel === 'sandbox') {
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
|
||||||
|
} else if (vertex.linkTarget) {
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkNode = node.insert(function () {
|
||||||
|
return link;
|
||||||
|
}, ':first-child');
|
||||||
|
|
||||||
|
const shape = node.select('.label-container');
|
||||||
|
if (shape) {
|
||||||
|
linkNode.append(function () {
|
||||||
|
return shape.node();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = node.select('.label');
|
||||||
|
if (label) {
|
||||||
|
linkNode.append(function () {
|
||||||
|
return label.node();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setConf,
|
|
||||||
getClasses,
|
getClasses,
|
||||||
draw,
|
draw,
|
||||||
};
|
};
|
||||||
|
@@ -35,7 +35,7 @@ import {
|
|||||||
} from './stateCommon.js';
|
} from './stateCommon.js';
|
||||||
|
|
||||||
// List of nodes created from the parsed diagram statement items
|
// List of nodes created from the parsed diagram statement items
|
||||||
let nodeDb = {};
|
let nodeDb = new Map();
|
||||||
|
|
||||||
let graphItemCount = 0; // used to construct ids, etc.
|
let graphItemCount = 0; // used to construct ids, etc.
|
||||||
|
|
||||||
@@ -104,7 +104,6 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l
|
|||||||
look,
|
look,
|
||||||
};
|
};
|
||||||
edges.push(edgeData);
|
edges.push(edgeData);
|
||||||
//g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount);
|
|
||||||
graphItemCount++;
|
graphItemCount++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -214,6 +213,7 @@ function getStylesFromDbInfo(dbInfoItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dataFetcher = (
|
export const dataFetcher = (
|
||||||
parent,
|
parent,
|
||||||
parsedItem,
|
parsedItem,
|
||||||
@@ -244,17 +244,17 @@ export const dataFetcher = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the node to our list (nodeDb)
|
// Add the node to our list (nodeDb)
|
||||||
if (!nodeDb[itemId]) {
|
if (!nodeDb.get(itemId)) {
|
||||||
nodeDb[itemId] = {
|
nodeDb.set(itemId, {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
shape,
|
shape,
|
||||||
description: common.sanitizeText(itemId, getConfig()),
|
description: common.sanitizeText(itemId, getConfig()),
|
||||||
cssClasses: `${classStr} ${CSS_DIAGRAM_STATE}`,
|
cssClasses: `${classStr} ${CSS_DIAGRAM_STATE}`,
|
||||||
cssStyles: style,
|
cssStyles: style,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newNode = nodeDb[itemId];
|
const newNode = nodeDb.get(itemId);
|
||||||
|
|
||||||
// Save data for description and group so that for instance a statement without description overwrites
|
// Save data for description and group so that for instance a statement without description overwrites
|
||||||
// one with description @todo TODO What does this mean? If important, add a test for it
|
// one with description @todo TODO What does this mean? If important, add a test for it
|
||||||
@@ -290,7 +290,6 @@ export const dataFetcher = (
|
|||||||
} else {
|
} else {
|
||||||
newNode.shape = SHAPE_STATE;
|
newNode.shape = SHAPE_STATE;
|
||||||
}
|
}
|
||||||
//newNode.shape = SHAPE_STATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// group
|
// group
|
||||||
@@ -300,12 +299,7 @@ export const dataFetcher = (
|
|||||||
newNode.isGroup = true;
|
newNode.isGroup = true;
|
||||||
newNode.dir = getDir(parsedItem);
|
newNode.dir = getDir(parsedItem);
|
||||||
newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
||||||
newNode.cssClasses =
|
newNode.cssClasses = `${newNode.cssClasses} ${CSS_DIAGRAM_CLUSTER} ${altFlag ? CSS_DIAGRAM_CLUSTER_ALT : ''}`;
|
||||||
newNode.cssClasses +
|
|
||||||
' ' +
|
|
||||||
CSS_DIAGRAM_CLUSTER +
|
|
||||||
' ' +
|
|
||||||
(altFlag ? CSS_DIAGRAM_CLUSTER_ALT : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is what will be added to the graph
|
// This is what will be added to the graph
|
||||||
@@ -421,6 +415,6 @@ export const dataFetcher = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const reset = () => {
|
export const reset = () => {
|
||||||
nodeDb = {};
|
nodeDb.clear();
|
||||||
graphItemCount = 0;
|
graphItemCount = 0;
|
||||||
};
|
};
|
||||||
|
@@ -3,7 +3,6 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
|||||||
import parser from './parser/stateDiagram.jison';
|
import parser from './parser/stateDiagram.jison';
|
||||||
import db from './stateDb.js';
|
import db from './stateDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
// import renderer from './stateRenderer-v2.js';
|
|
||||||
import renderer from './stateRenderer-v3-unified.js';
|
import renderer from './stateRenderer-v3-unified.js';
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
export const diagram: DiagramDefinition = {
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
|
||||||
// @ts-ignore: JISON doesn't support types
|
|
||||||
import parser from './parser/stateDiagram.jison';
|
|
||||||
import db from './stateDb.js';
|
|
||||||
import styles from './styles.js';
|
|
||||||
import renderer from './stateRenderer-v3-unified.js';
|
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
|
||||||
parser,
|
|
||||||
db,
|
|
||||||
renderer,
|
|
||||||
styles,
|
|
||||||
init: (cnf) => {
|
|
||||||
if (!cnf.state) {
|
|
||||||
cnf.state = {};
|
|
||||||
}
|
|
||||||
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
|
||||||
db.clear();
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,479 +0,0 @@
|
|||||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
|
||||||
import { select } from 'd3';
|
|
||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
|
||||||
import { render } from '../../dagre-wrapper/index.js';
|
|
||||||
import { log } from '../../logger.js';
|
|
||||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
|
||||||
import common from '../common/common.js';
|
|
||||||
import utils, { getEdgeId } from '../../utils.js';
|
|
||||||
|
|
||||||
import {
|
|
||||||
DEFAULT_DIAGRAM_DIRECTION,
|
|
||||||
DEFAULT_NESTED_DOC_DIR,
|
|
||||||
STMT_STATE,
|
|
||||||
STMT_RELATION,
|
|
||||||
DEFAULT_STATE_TYPE,
|
|
||||||
DIVIDER_TYPE,
|
|
||||||
} from './stateCommon.js';
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// Shapes
|
|
||||||
const SHAPE_STATE = 'rect';
|
|
||||||
const SHAPE_STATE_WITH_DESC = 'rectWithTitle';
|
|
||||||
const SHAPE_START = 'start';
|
|
||||||
const SHAPE_END = 'end';
|
|
||||||
const SHAPE_DIVIDER = 'divider';
|
|
||||||
const SHAPE_GROUP = 'roundedWithTitle';
|
|
||||||
const SHAPE_NOTE = 'note';
|
|
||||||
const SHAPE_NOTEGROUP = 'noteGroup';
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// CSS classes
|
|
||||||
const CSS_DIAGRAM = 'statediagram';
|
|
||||||
const CSS_STATE = 'state';
|
|
||||||
const CSS_DIAGRAM_STATE = `${CSS_DIAGRAM}-${CSS_STATE}`;
|
|
||||||
const CSS_EDGE = 'transition';
|
|
||||||
const CSS_NOTE = 'note';
|
|
||||||
const CSS_NOTE_EDGE = 'note-edge';
|
|
||||||
const CSS_EDGE_NOTE_EDGE = `${CSS_EDGE} ${CSS_NOTE_EDGE}`;
|
|
||||||
const CSS_DIAGRAM_NOTE = `${CSS_DIAGRAM}-${CSS_NOTE}`;
|
|
||||||
const CSS_CLUSTER = 'cluster';
|
|
||||||
const CSS_DIAGRAM_CLUSTER = `${CSS_DIAGRAM}-${CSS_CLUSTER}`;
|
|
||||||
const CSS_CLUSTER_ALT = 'cluster-alt';
|
|
||||||
const CSS_DIAGRAM_CLUSTER_ALT = `${CSS_DIAGRAM}-${CSS_CLUSTER_ALT}`;
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// DOM and element IDs
|
|
||||||
const PARENT = 'parent';
|
|
||||||
const NOTE = 'note';
|
|
||||||
const DOMID_STATE = 'state';
|
|
||||||
const DOMID_TYPE_SPACER = '----';
|
|
||||||
const NOTE_ID = `${DOMID_TYPE_SPACER}${NOTE}`;
|
|
||||||
const PARENT_ID = `${DOMID_TYPE_SPACER}${PARENT}`;
|
|
||||||
// --------------------------------------
|
|
||||||
// Graph edge settings
|
|
||||||
const G_EDGE_STYLE = 'fill:none';
|
|
||||||
const G_EDGE_ARROWHEADSTYLE = 'fill: #333';
|
|
||||||
const G_EDGE_LABELPOS = 'c';
|
|
||||||
const G_EDGE_LABELTYPE = 'text';
|
|
||||||
const G_EDGE_THICKNESS = 'normal';
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// List of nodes created from the parsed diagram statement items
|
|
||||||
let nodeDb = {};
|
|
||||||
|
|
||||||
let graphItemCount = 0; // used to construct ids, etc.
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
const conf = {};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
export const setConf = function (cnf) {
|
|
||||||
const keys = Object.keys(cnf);
|
|
||||||
for (const key of keys) {
|
|
||||||
conf[key] = cnf[key];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the all the classdef styles (a.k.a. classes) from classDef statements in the graph definition.
|
|
||||||
*
|
|
||||||
* @param {string} text - the diagram text to be parsed
|
|
||||||
* @param diagramObj
|
|
||||||
* @returns {Map<string, import('../../diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles (a Map with keys = strings, values = )
|
|
||||||
*/
|
|
||||||
export const getClasses = function (text, diagramObj) {
|
|
||||||
diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
|
||||||
return diagramObj.db.getClasses();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get classes from the db for the info item.
|
|
||||||
* If there aren't any or if dbInfoItem isn't defined, return an empty string.
|
|
||||||
* Else create 1 string from the list of classes found
|
|
||||||
*
|
|
||||||
* @param {undefined | null | object} dbInfoItem
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getClassesFromDbInfo(dbInfoItem) {
|
|
||||||
if (dbInfoItem === undefined || dbInfoItem === null) {
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
if (dbInfoItem.classes) {
|
|
||||||
return dbInfoItem.classes.join(' ');
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a standard string for the dom ID of an item.
|
|
||||||
* If a type is given, insert that before the counter, preceded by the type spacer
|
|
||||||
*
|
|
||||||
* @param itemId
|
|
||||||
* @param counter
|
|
||||||
* @param {string | null} type
|
|
||||||
* @param typeSpacer
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOMID_TYPE_SPACER) {
|
|
||||||
const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : '';
|
|
||||||
return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a graph node based on the statement information
|
|
||||||
*
|
|
||||||
* @param g - graph
|
|
||||||
* @param {object} parent
|
|
||||||
* @param {object} parsedItem - parsed statement item
|
|
||||||
* @param {Map<string, object>} diagramStates - the list of all known states for the diagram
|
|
||||||
* @param {object} diagramDb
|
|
||||||
* @param {boolean} altFlag - for clusters, add the "statediagram-cluster-alt" CSS class
|
|
||||||
*/
|
|
||||||
const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) => {
|
|
||||||
const itemId = parsedItem.id;
|
|
||||||
const classStr = getClassesFromDbInfo(diagramStates.get(itemId));
|
|
||||||
|
|
||||||
if (itemId !== 'root') {
|
|
||||||
let shape = SHAPE_STATE;
|
|
||||||
if (parsedItem.start === true) {
|
|
||||||
shape = SHAPE_START;
|
|
||||||
}
|
|
||||||
if (parsedItem.start === false) {
|
|
||||||
shape = SHAPE_END;
|
|
||||||
}
|
|
||||||
if (parsedItem.type !== DEFAULT_STATE_TYPE) {
|
|
||||||
shape = parsedItem.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the node to our list (nodeDb)
|
|
||||||
if (!nodeDb[itemId]) {
|
|
||||||
nodeDb[itemId] = {
|
|
||||||
id: itemId,
|
|
||||||
shape,
|
|
||||||
description: common.sanitizeText(itemId, getConfig()),
|
|
||||||
classes: `${classStr} ${CSS_DIAGRAM_STATE}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const newNode = nodeDb[itemId];
|
|
||||||
|
|
||||||
// Save data for description and group so that for instance a statement without description overwrites
|
|
||||||
// one with description @todo TODO What does this mean? If important, add a test for it
|
|
||||||
|
|
||||||
// Build of the array of description strings
|
|
||||||
if (parsedItem.description) {
|
|
||||||
if (Array.isArray(newNode.description)) {
|
|
||||||
// There already is an array of strings,add to it
|
|
||||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
|
||||||
newNode.description.push(parsedItem.description);
|
|
||||||
} else {
|
|
||||||
if (newNode.description.length > 0) {
|
|
||||||
// if there is a description already transform it to an array
|
|
||||||
newNode.shape = SHAPE_STATE_WITH_DESC;
|
|
||||||
if (newNode.description === itemId) {
|
|
||||||
// If the previous description was this, remove it
|
|
||||||
newNode.description = [parsedItem.description];
|
|
||||||
} else {
|
|
||||||
newNode.description = [newNode.description, parsedItem.description];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newNode.shape = SHAPE_STATE;
|
|
||||||
newNode.description = parsedItem.description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's only 1 description entry, just use a regular state shape
|
|
||||||
if (newNode.description.length === 1 && newNode.shape === SHAPE_STATE_WITH_DESC) {
|
|
||||||
newNode.shape = SHAPE_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// group
|
|
||||||
if (!newNode.type && parsedItem.doc) {
|
|
||||||
log.info('Setting cluster for ', itemId, getDir(parsedItem));
|
|
||||||
newNode.type = 'group';
|
|
||||||
newNode.dir = getDir(parsedItem);
|
|
||||||
newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
|
||||||
newNode.classes =
|
|
||||||
newNode.classes +
|
|
||||||
' ' +
|
|
||||||
CSS_DIAGRAM_CLUSTER +
|
|
||||||
' ' +
|
|
||||||
(altFlag ? CSS_DIAGRAM_CLUSTER_ALT : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is what will be added to the graph
|
|
||||||
const nodeData = {
|
|
||||||
labelStyle: '',
|
|
||||||
shape: newNode.shape,
|
|
||||||
labelText: newNode.description,
|
|
||||||
// typeof newNode.description === 'object'
|
|
||||||
// ? newNode.description[0]
|
|
||||||
// : newNode.description,
|
|
||||||
classes: newNode.classes,
|
|
||||||
style: '', //styles.style,
|
|
||||||
id: itemId,
|
|
||||||
dir: newNode.dir,
|
|
||||||
domId: stateDomId(itemId, graphItemCount),
|
|
||||||
type: newNode.type,
|
|
||||||
padding: 15, //getConfig().flowchart.padding
|
|
||||||
};
|
|
||||||
// if (useHtmlLabels) {
|
|
||||||
nodeData.centerLabel = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (parsedItem.note) {
|
|
||||||
// Todo: set random id
|
|
||||||
const noteData = {
|
|
||||||
labelStyle: '',
|
|
||||||
shape: SHAPE_NOTE,
|
|
||||||
labelText: parsedItem.note.text,
|
|
||||||
classes: CSS_DIAGRAM_NOTE,
|
|
||||||
// useHtmlLabels: false,
|
|
||||||
style: '', // styles.style,
|
|
||||||
id: itemId + NOTE_ID + '-' + graphItemCount,
|
|
||||||
domId: stateDomId(itemId, graphItemCount, NOTE),
|
|
||||||
type: newNode.type,
|
|
||||||
padding: 15, //getConfig().flowchart.padding
|
|
||||||
};
|
|
||||||
const groupData = {
|
|
||||||
labelStyle: '',
|
|
||||||
shape: SHAPE_NOTEGROUP,
|
|
||||||
labelText: parsedItem.note.text,
|
|
||||||
classes: newNode.classes,
|
|
||||||
style: '', // styles.style,
|
|
||||||
id: itemId + PARENT_ID,
|
|
||||||
domId: stateDomId(itemId, graphItemCount, PARENT),
|
|
||||||
type: 'group',
|
|
||||||
padding: 0, //getConfig().flowchart.padding
|
|
||||||
};
|
|
||||||
|
|
||||||
const parentNodeId = itemId + PARENT_ID;
|
|
||||||
g.setNode(parentNodeId, groupData);
|
|
||||||
|
|
||||||
g.setNode(noteData.id, noteData);
|
|
||||||
g.setNode(itemId, nodeData);
|
|
||||||
|
|
||||||
g.setParent(itemId, parentNodeId);
|
|
||||||
g.setParent(noteData.id, parentNodeId);
|
|
||||||
|
|
||||||
let from = itemId;
|
|
||||||
let to = noteData.id;
|
|
||||||
|
|
||||||
if (parsedItem.note.position === 'left of') {
|
|
||||||
from = noteData.id;
|
|
||||||
to = itemId;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setEdge(from, to, {
|
|
||||||
arrowhead: 'none',
|
|
||||||
arrowType: '',
|
|
||||||
style: G_EDGE_STYLE,
|
|
||||||
labelStyle: '',
|
|
||||||
id: getEdgeId(from, to, {
|
|
||||||
counter: graphItemCount,
|
|
||||||
}),
|
|
||||||
classes: CSS_EDGE_NOTE_EDGE,
|
|
||||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
|
||||||
labelpos: G_EDGE_LABELPOS,
|
|
||||||
labelType: G_EDGE_LABELTYPE,
|
|
||||||
thickness: G_EDGE_THICKNESS,
|
|
||||||
});
|
|
||||||
|
|
||||||
graphItemCount++;
|
|
||||||
} else {
|
|
||||||
g.setNode(itemId, nodeData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent && parent.id !== 'root') {
|
|
||||||
log.trace('Setting node ', itemId, ' to be child of its parent ', parent.id);
|
|
||||||
g.setParent(itemId, parent.id);
|
|
||||||
}
|
|
||||||
if (parsedItem.doc) {
|
|
||||||
log.trace('Adding nodes children ');
|
|
||||||
setupDoc(g, parsedItem, parsedItem.doc, diagramStates, diagramDb, !altFlag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn parsed statements (item.stmt) into nodes, relationships, etc. for a document.
|
|
||||||
* (A document may be nested within others.)
|
|
||||||
*
|
|
||||||
* @param g
|
|
||||||
* @param parentParsedItem - parsed Item that is the parent of this document (doc)
|
|
||||||
* @param doc - the document to set up; it is a list of parsed statements
|
|
||||||
* @param {Map<string, object>} diagramStates - the list of all known states for the diagram
|
|
||||||
* @param diagramDb
|
|
||||||
* @param {boolean} altFlag
|
|
||||||
* @todo This duplicates some of what is done in stateDb.js extract method
|
|
||||||
*/
|
|
||||||
const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) => {
|
|
||||||
// graphItemCount = 0;
|
|
||||||
log.trace('items', doc);
|
|
||||||
doc.forEach((item) => {
|
|
||||||
switch (item.stmt) {
|
|
||||||
case STMT_STATE:
|
|
||||||
setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag);
|
|
||||||
break;
|
|
||||||
case DEFAULT_STATE_TYPE:
|
|
||||||
setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag);
|
|
||||||
break;
|
|
||||||
case STMT_RELATION:
|
|
||||||
{
|
|
||||||
setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag);
|
|
||||||
setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag);
|
|
||||||
const edgeData = {
|
|
||||||
id: getEdgeId(item.state1.id, item.state2.id, {
|
|
||||||
counter: graphItemCount,
|
|
||||||
}),
|
|
||||||
arrowhead: 'normal',
|
|
||||||
arrowTypeEnd: 'arrow_barb',
|
|
||||||
style: G_EDGE_STYLE,
|
|
||||||
labelStyle: '',
|
|
||||||
label: common.sanitizeText(item.description, getConfig()),
|
|
||||||
arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
|
||||||
labelpos: G_EDGE_LABELPOS,
|
|
||||||
labelType: G_EDGE_LABELTYPE,
|
|
||||||
thickness: G_EDGE_THICKNESS,
|
|
||||||
classes: CSS_EDGE,
|
|
||||||
};
|
|
||||||
g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount);
|
|
||||||
graphItemCount++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the direction from the statement items.
|
|
||||||
* Look through all of the documents (docs) in the parsedItems
|
|
||||||
* Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction.
|
|
||||||
* @param {object[]} parsedItem - the parsed statement item to look through
|
|
||||||
* @param [defaultDir] - the direction to use if none is found
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
|
||||||
let dir = defaultDir;
|
|
||||||
if (parsedItem.doc) {
|
|
||||||
for (const parsedItemDoc of parsedItem.doc) {
|
|
||||||
if (parsedItemDoc.stmt === 'dir') {
|
|
||||||
dir = parsedItemDoc.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a state diagram in the tag with id: id based on the graph definition in text.
|
|
||||||
*
|
|
||||||
* @param {any} text
|
|
||||||
* @param {any} id
|
|
||||||
* @param _version
|
|
||||||
* @param diag
|
|
||||||
*/
|
|
||||||
export const draw = async function (text, id, _version, diag) {
|
|
||||||
log.info('Drawing state diagram (v2)', id);
|
|
||||||
nodeDb = {};
|
|
||||||
// Fetch the default direction, use TD if none was found
|
|
||||||
let dir = diag.db.getDirection();
|
|
||||||
if (dir === undefined) {
|
|
||||||
dir = DEFAULT_DIAGRAM_DIRECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { securityLevel, state: conf } = getConfig();
|
|
||||||
const nodeSpacing = conf.nodeSpacing || 50;
|
|
||||||
const rankSpacing = conf.rankSpacing || 50;
|
|
||||||
|
|
||||||
log.info(diag.db.getRootDocV2());
|
|
||||||
|
|
||||||
// This parses the diagram text and sets the classes, relations, styles, classDefs, etc.
|
|
||||||
diag.db.extract(diag.db.getRootDocV2());
|
|
||||||
log.info(diag.db.getRootDocV2());
|
|
||||||
|
|
||||||
const diagramStates = diag.db.getStates();
|
|
||||||
|
|
||||||
// Create the input mermaid.graph
|
|
||||||
const g = new graphlib.Graph({
|
|
||||||
multigraph: true,
|
|
||||||
compound: true,
|
|
||||||
})
|
|
||||||
.setGraph({
|
|
||||||
rankdir: getDir(diag.db.getRootDocV2()),
|
|
||||||
nodesep: nodeSpacing,
|
|
||||||
ranksep: rankSpacing,
|
|
||||||
marginx: 8,
|
|
||||||
marginy: 8,
|
|
||||||
})
|
|
||||||
.setDefaultEdgeLabel(function () {
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
setupNode(g, undefined, diag.db.getRootDocV2(), diagramStates, diag.db, true);
|
|
||||||
|
|
||||||
// Set up an SVG group so that we can translate the final graph.
|
|
||||||
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}"]`);
|
|
||||||
|
|
||||||
// Run the renderer. This is what draws the final graph.
|
|
||||||
|
|
||||||
const element = root.select('#' + id + ' g');
|
|
||||||
await render(element, g, ['barb'], CSS_DIAGRAM, id);
|
|
||||||
|
|
||||||
const padding = 8;
|
|
||||||
|
|
||||||
utils.insertTitle(svg, 'statediagramTitleText', conf.titleTopMargin, diag.db.getDiagramTitle());
|
|
||||||
|
|
||||||
const bounds = svg.node().getBBox();
|
|
||||||
const width = bounds.width + padding * 2;
|
|
||||||
const height = bounds.height + padding * 2;
|
|
||||||
|
|
||||||
// Zoom in a bit
|
|
||||||
svg.attr('class', CSS_DIAGRAM);
|
|
||||||
|
|
||||||
const svgBounds = svg.node().getBBox();
|
|
||||||
|
|
||||||
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
|
||||||
|
|
||||||
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
|
|
||||||
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
|
|
||||||
log.debug(`viewBox ${vBox}`);
|
|
||||||
svg.attr('viewBox', vBox);
|
|
||||||
|
|
||||||
// Add label rects for non html labels
|
|
||||||
// if (!evaluate(conf.htmlLabels) || true) {
|
|
||||||
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
|
||||||
for (const label of labels) {
|
|
||||||
// Get dimensions of label
|
|
||||||
const dim = label.getBBox();
|
|
||||||
|
|
||||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', SHAPE_STATE);
|
|
||||||
rect.setAttribute('rx', 0);
|
|
||||||
rect.setAttribute('ry', 0);
|
|
||||||
rect.setAttribute('width', dim.width);
|
|
||||||
rect.setAttribute('height', dim.height);
|
|
||||||
|
|
||||||
label.insertBefore(rect, label.firstChild);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setConf,
|
|
||||||
getClasses,
|
|
||||||
draw,
|
|
||||||
};
|
|
@@ -1,31 +0,0 @@
|
|||||||
import { expectTypeOf } from 'vitest';
|
|
||||||
|
|
||||||
import { parser } from './parser/stateDiagram.jison';
|
|
||||||
import stateDb from './stateDb.js';
|
|
||||||
import stateRendererV2 from './stateRenderer-v2.js';
|
|
||||||
|
|
||||||
// Can use this instead of having to register diagrams and load/orchestrate them, etc.
|
|
||||||
class FauxDiagramObj {
|
|
||||||
db = stateDb;
|
|
||||||
parser = parser;
|
|
||||||
renderer = stateRendererV2;
|
|
||||||
|
|
||||||
constructor(options = { db: stateDb, parser: parser, renderer: stateRendererV2 }) {
|
|
||||||
this.db = options.db;
|
|
||||||
this.parser = options.parser;
|
|
||||||
this.renderer = options.renderer;
|
|
||||||
this.parser.yy = this.db;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('stateRenderer-v2', () => {
|
|
||||||
describe('getClasses', () => {
|
|
||||||
const diagramText = 'statediagram-v2\n';
|
|
||||||
const fauxStateDiagram = new FauxDiagramObj();
|
|
||||||
|
|
||||||
it('returns a {}', () => {
|
|
||||||
const result = stateRendererV2.getClasses(diagramText, fauxStateDiagram);
|
|
||||||
expectTypeOf(result).toBeObject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -16,15 +16,19 @@ import { CSS_DIAGRAM, DEFAULT_NESTED_DOC_DIR } from './stateCommon.js';
|
|||||||
* @param defaultDir - the direction to use if none is found
|
* @param defaultDir - the direction to use if none is found
|
||||||
* @returns The direction to use
|
* @returns The direction to use
|
||||||
*/
|
*/
|
||||||
export const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
||||||
|
if (!parsedItem.doc) {
|
||||||
|
return defaultDir;
|
||||||
|
}
|
||||||
|
|
||||||
let dir = defaultDir;
|
let dir = defaultDir;
|
||||||
if (parsedItem.doc) {
|
|
||||||
for (const parsedItemDoc of parsedItem.doc) {
|
for (const parsedItemDoc of parsedItem.doc) {
|
||||||
if (parsedItemDoc.stmt === 'dir') {
|
if (parsedItemDoc.stmt === 'dir') {
|
||||||
dir = parsedItemDoc.value;
|
dir = parsedItemDoc.value;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,17 +57,6 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
// Create the root SVG - the element is the div containing the SVG element
|
// Create the root SVG - the element is the div containing the SVG element
|
||||||
const { element, svg } = getDiagramElements(id, securityLevel);
|
const { element, svg } = getDiagramElements(id, securityLevel);
|
||||||
|
|
||||||
// // For some diagrams this call is not needed, but in the state diagram it is
|
|
||||||
// await insertElementsForSize(element, data4Layout);
|
|
||||||
|
|
||||||
// console.log('data4Layout:', data4Layout);
|
|
||||||
|
|
||||||
// // Now we have layout data with real sizes, we can perform the layout
|
|
||||||
// const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
|
||||||
|
|
||||||
// // The performRender method provided in all supported diagrams is used to render the data
|
|
||||||
// performRender(data4Rendering);
|
|
||||||
|
|
||||||
data4Layout.type = diag.type;
|
data4Layout.type = diag.type;
|
||||||
data4Layout.layoutAlgorithm = layout;
|
data4Layout.layoutAlgorithm = layout;
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
|||||||
import { registerLayoutLoaders } from './rendering-util/render.js';
|
import { registerLayoutLoaders } from './rendering-util/render.js';
|
||||||
import type { LayoutLoaderDefinition } from './rendering-util/render.js';
|
import type { LayoutLoaderDefinition } from './rendering-util/render.js';
|
||||||
import { internalHelpers } from './internals.js';
|
import { internalHelpers } from './internals.js';
|
||||||
|
import type { LayoutData } from './rendering-util/types.js';
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
MermaidConfig,
|
MermaidConfig,
|
||||||
@@ -30,6 +31,7 @@ export type {
|
|||||||
ParseResult,
|
ParseResult,
|
||||||
UnknownDiagramError,
|
UnknownDiagramError,
|
||||||
LayoutLoaderDefinition,
|
LayoutLoaderDefinition,
|
||||||
|
LayoutData,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface RunOptions {
|
export interface RunOptions {
|
||||||
|
@@ -30,7 +30,6 @@ vi.mock('./diagrams/packet/renderer.js');
|
|||||||
vi.mock('./diagrams/xychart/xychartRenderer.js');
|
vi.mock('./diagrams/xychart/xychartRenderer.js');
|
||||||
vi.mock('./diagrams/requirement/requirementRenderer.js');
|
vi.mock('./diagrams/requirement/requirementRenderer.js');
|
||||||
vi.mock('./diagrams/sequence/sequenceRenderer.js');
|
vi.mock('./diagrams/sequence/sequenceRenderer.js');
|
||||||
vi.mock('./diagrams/state/stateRenderer-v2.js');
|
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdo
|
|||||||
import { decodeEntities } from '../utils.js';
|
import { decodeEntities } from '../utils.js';
|
||||||
import { splitLineToFitWidth } from './splitText.js';
|
import { splitLineToFitWidth } from './splitText.js';
|
||||||
import type { MarkdownLine, MarkdownWord } from './types.js';
|
import type { MarkdownLine, MarkdownWord } from './types.js';
|
||||||
import common, { hasKatex, renderKatex, hasKatex } from '$root/diagrams/common/common.js';
|
import common, { hasKatex, renderKatex } from '$root/diagrams/common/common.js';
|
||||||
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
|
|
||||||
function applyStyle(dom, styleFn) {
|
function applyStyle(dom, styleFn) {
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
import { log } from '$root/logger.js';
|
|
||||||
import type { LayoutData, LayoutMethod, RenderData } from './types.js';
|
|
||||||
|
|
||||||
const performLayout = (
|
|
||||||
layoutData: LayoutData,
|
|
||||||
id: string,
|
|
||||||
_version: string,
|
|
||||||
layoutMethod: LayoutMethod
|
|
||||||
): RenderData => {
|
|
||||||
log.info('Performing layout', layoutData, id, _version, layoutMethod);
|
|
||||||
return { items: [] };
|
|
||||||
};
|
|
||||||
export default performLayout;
|
|
@@ -1,8 +1,6 @@
|
|||||||
// import type { LayoutData } from './types';
|
|
||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
import { insertNode } from '../dagre-wrapper/nodes.js';
|
import { insertNode } from '../dagre-wrapper/nodes.js';
|
||||||
|
|
||||||
// export const getDiagramElements = (id: string, securityLevel: any) => {
|
|
||||||
export const getDiagramElements = (id, securityLevel) => {
|
export const getDiagramElements = (id, securityLevel) => {
|
||||||
let sandboxElement;
|
let sandboxElement;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
@@ -22,12 +20,6 @@ export const getDiagramElements = (id, securityLevel) => {
|
|||||||
return { svg, element };
|
return { svg, element };
|
||||||
};
|
};
|
||||||
|
|
||||||
// export function insertElementsForSize(el: SVGElement, data: LayoutData): void {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param el
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
export function insertElementsForSize(el, data) {
|
export function insertElementsForSize(el, data) {
|
||||||
const nodesElem = el.insert('g').attr('class', 'nodes');
|
const nodesElem = el.insert('g').attr('class', 'nodes');
|
||||||
el.insert('g').attr('class', 'edges');
|
el.insert('g').attr('class', 'edges');
|
||||||
@@ -60,5 +52,3 @@ export function insertElementsForSize(el, data) {
|
|||||||
// document.body.appendChild(element);
|
// document.body.appendChild(element);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default insertElementsForSize;
|
|
||||||
|
@@ -54,7 +54,6 @@ const rect = async (parent, node) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const padding = 0 * node.padding;
|
const padding = 0 * node.padding;
|
||||||
const halfPadding = padding / 2;
|
|
||||||
|
|
||||||
const width =
|
const width =
|
||||||
(node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding;
|
(node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding;
|
||||||
@@ -293,7 +292,7 @@ const divider = (parent, node) => {
|
|||||||
const siteConfig = getConfig();
|
const siteConfig = getConfig();
|
||||||
|
|
||||||
const { themeVariables, handdrawnSeed } = siteConfig;
|
const { themeVariables, handdrawnSeed } = siteConfig;
|
||||||
const { compositeTitleBackground, nodeBorder } = themeVariables;
|
const { nodeBorder } = themeVariables;
|
||||||
|
|
||||||
// Add outer g element
|
// Add outer g element
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
|
@@ -9,14 +9,13 @@ import { curveBasis, line, select } from 'd3';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import createLabel from './createLabel.js';
|
import createLabel from './createLabel.js';
|
||||||
import { addEdgeMarkers } from './edgeMarker.ts';
|
import { addEdgeMarkers } from './edgeMarker.ts';
|
||||||
//import type { Edge } from '$root/rendering-util/types.d.ts';
|
|
||||||
|
|
||||||
let edgeLabels = {};
|
const edgeLabels = new Map();
|
||||||
let terminalLabels = {};
|
const terminalLabels = new Map();
|
||||||
|
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
edgeLabels = {};
|
edgeLabels.clear();
|
||||||
terminalLabels = {};
|
terminalLabels.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getLabelStyles = (styleArray) => {
|
export const getLabelStyles = (styleArray) => {
|
||||||
@@ -27,16 +26,6 @@ export const getLabelStyles = (styleArray) => {
|
|||||||
export const insertEdgeLabel = async (elem, edge) => {
|
export const insertEdgeLabel = async (elem, edge) => {
|
||||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||||
|
|
||||||
// Create the actual text element
|
|
||||||
// const labelElement =
|
|
||||||
// edge.labelType === 'markdown'
|
|
||||||
// ? await createText(elem, edge.label, {
|
|
||||||
// style: labelStyles,
|
|
||||||
// useHtmlLabels,
|
|
||||||
// addSvgBackground: true,
|
|
||||||
// })
|
|
||||||
// : await createLabel(edge.label, getLabelStyles(edge.labelStyle));
|
|
||||||
|
|
||||||
const labelElement = await createText(elem, edge.label, {
|
const labelElement = await createText(elem, edge.label, {
|
||||||
style: getLabelStyles(edge.labelStyle),
|
style: getLabelStyles(edge.labelStyle),
|
||||||
useHtmlLabels,
|
useHtmlLabels,
|
||||||
@@ -64,7 +53,7 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||||
|
|
||||||
// Make element accessible by id for positioning
|
// Make element accessible by id for positioning
|
||||||
edgeLabels[edge.id] = edgeLabel;
|
edgeLabels.set(edge.id, edgeLabel);
|
||||||
|
|
||||||
// Update the abstract data of the edge with the new information about its width and height
|
// Update the abstract data of the edge with the new information about its width and height
|
||||||
edge.width = bbox.width;
|
edge.width = bbox.width;
|
||||||
@@ -82,10 +71,10 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
fo = inner.node().appendChild(startLabelElement);
|
fo = inner.node().appendChild(startLabelElement);
|
||||||
const slBox = startLabelElement.getBBox();
|
const slBox = startLabelElement.getBBox();
|
||||||
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
if (!terminalLabels[edge.id]) {
|
if (!terminalLabels.get(edge.id)) {
|
||||||
terminalLabels[edge.id] = {};
|
terminalLabels.set(edge.id, {});
|
||||||
}
|
}
|
||||||
terminalLabels[edge.id].startLeft = startEdgeLabelLeft;
|
terminalLabels.get(edge.id).startLeft = startEdgeLabelLeft;
|
||||||
setTerminalWidth(fo, edge.startLabelLeft);
|
setTerminalWidth(fo, edge.startLabelLeft);
|
||||||
}
|
}
|
||||||
if (edge.startLabelRight) {
|
if (edge.startLabelRight) {
|
||||||
@@ -101,10 +90,10 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
const slBox = startLabelElement.getBBox();
|
const slBox = startLabelElement.getBBox();
|
||||||
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
|
||||||
if (!terminalLabels[edge.id]) {
|
if (!terminalLabels.get(edge.id)) {
|
||||||
terminalLabels[edge.id] = {};
|
terminalLabels.set(edge.id, {});
|
||||||
}
|
}
|
||||||
terminalLabels[edge.id].startRight = startEdgeLabelRight;
|
terminalLabels.get(edge.id).startRight = startEdgeLabelRight;
|
||||||
setTerminalWidth(fo, edge.startLabelRight);
|
setTerminalWidth(fo, edge.startLabelRight);
|
||||||
}
|
}
|
||||||
if (edge.endLabelLeft) {
|
if (edge.endLabelLeft) {
|
||||||
@@ -118,10 +107,10 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
|
|
||||||
endEdgeLabelLeft.node().appendChild(endLabelElement);
|
endEdgeLabelLeft.node().appendChild(endLabelElement);
|
||||||
|
|
||||||
if (!terminalLabels[edge.id]) {
|
if (!terminalLabels.get(edge.id)) {
|
||||||
terminalLabels[edge.id] = {};
|
terminalLabels.set(edge.id, {});
|
||||||
}
|
}
|
||||||
terminalLabels[edge.id].endLeft = endEdgeLabelLeft;
|
terminalLabels.get(edge.id).endLeft = endEdgeLabelLeft;
|
||||||
setTerminalWidth(fo, edge.endLabelLeft);
|
setTerminalWidth(fo, edge.endLabelLeft);
|
||||||
}
|
}
|
||||||
if (edge.endLabelRight) {
|
if (edge.endLabelRight) {
|
||||||
@@ -135,10 +124,10 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
|
||||||
|
|
||||||
endEdgeLabelRight.node().appendChild(endLabelElement);
|
endEdgeLabelRight.node().appendChild(endLabelElement);
|
||||||
if (!terminalLabels[edge.id]) {
|
if (!terminalLabels.get(edge.id)) {
|
||||||
terminalLabels[edge.id] = {};
|
terminalLabels.set(edge.id, {});
|
||||||
}
|
}
|
||||||
terminalLabels[edge.id].endRight = endEdgeLabelRight;
|
terminalLabels.get(edge.id).endRight = endEdgeLabelRight;
|
||||||
setTerminalWidth(fo, edge.endLabelRight);
|
setTerminalWidth(fo, edge.endLabelRight);
|
||||||
}
|
}
|
||||||
return labelElement;
|
return labelElement;
|
||||||
@@ -156,12 +145,12 @@ function setTerminalWidth(fo, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const positionEdgeLabel = (edge, paths) => {
|
export const positionEdgeLabel = (edge, paths) => {
|
||||||
log.debug('Moving label abc88 ', edge.id, edge.label, edgeLabels[edge.id], paths);
|
log.debug('Moving label abc88 ', edge.id, edge.label, edgeLabels.get(edge.id), paths);
|
||||||
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
|
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
|
||||||
const siteConfig = getConfig();
|
const siteConfig = getConfig();
|
||||||
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
|
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
|
||||||
if (edge.label) {
|
if (edge.label) {
|
||||||
const el = edgeLabels[edge.id];
|
const el = edgeLabels.get(edge.id);
|
||||||
let x = edge.x;
|
let x = edge.x;
|
||||||
let y = edge.y;
|
let y = edge.y;
|
||||||
if (path) {
|
if (path) {
|
||||||
@@ -188,7 +177,7 @@ export const positionEdgeLabel = (edge, paths) => {
|
|||||||
|
|
||||||
//let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
|
//let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
|
||||||
if (edge.startLabelLeft) {
|
if (edge.startLabelLeft) {
|
||||||
const el = terminalLabels[edge.id].startLeft;
|
const el = terminalLabels.get(edge.id).startLeft;
|
||||||
let x = edge.x;
|
let x = edge.x;
|
||||||
let y = edge.y;
|
let y = edge.y;
|
||||||
if (path) {
|
if (path) {
|
||||||
@@ -200,7 +189,7 @@ export const positionEdgeLabel = (edge, paths) => {
|
|||||||
el.attr('transform', `translate(${x}, ${y})`);
|
el.attr('transform', `translate(${x}, ${y})`);
|
||||||
}
|
}
|
||||||
if (edge.startLabelRight) {
|
if (edge.startLabelRight) {
|
||||||
const el = terminalLabels[edge.id].startRight;
|
const el = terminalLabels.get(edge.id).startRight;
|
||||||
let x = edge.x;
|
let x = edge.x;
|
||||||
let y = edge.y;
|
let y = edge.y;
|
||||||
if (path) {
|
if (path) {
|
||||||
@@ -216,7 +205,7 @@ export const positionEdgeLabel = (edge, paths) => {
|
|||||||
el.attr('transform', `translate(${x}, ${y})`);
|
el.attr('transform', `translate(${x}, ${y})`);
|
||||||
}
|
}
|
||||||
if (edge.endLabelLeft) {
|
if (edge.endLabelLeft) {
|
||||||
const el = terminalLabels[edge.id].endLeft;
|
const el = terminalLabels.get(edge.id).endLeft;
|
||||||
let x = edge.x;
|
let x = edge.x;
|
||||||
let y = edge.y;
|
let y = edge.y;
|
||||||
if (path) {
|
if (path) {
|
||||||
@@ -228,11 +217,10 @@ export const positionEdgeLabel = (edge, paths) => {
|
|||||||
el.attr('transform', `translate(${x}, ${y})`);
|
el.attr('transform', `translate(${x}, ${y})`);
|
||||||
}
|
}
|
||||||
if (edge.endLabelRight) {
|
if (edge.endLabelRight) {
|
||||||
const el = terminalLabels[edge.id].endRight;
|
const el = terminalLabels.get(edge.id).endRight;
|
||||||
let x = edge.x;
|
let x = edge.x;
|
||||||
let y = edge.y;
|
let y = edge.y;
|
||||||
if (path) {
|
if (path) {
|
||||||
// debugger;
|
|
||||||
const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_right', path);
|
const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_right', path);
|
||||||
x = pos.x;
|
x = pos.x;
|
||||||
y = pos.y;
|
y = pos.y;
|
||||||
@@ -242,17 +230,13 @@ export const positionEdgeLabel = (edge, paths) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const outsideNode = (node, point) => {
|
const outsideNode = (node, point) => {
|
||||||
// log.warn('Checking bounds ', node, point);
|
|
||||||
const x = node.x;
|
const x = node.x;
|
||||||
const y = node.y;
|
const y = node.y;
|
||||||
const dx = Math.abs(point.x - x);
|
const dx = Math.abs(point.x - x);
|
||||||
const dy = Math.abs(point.y - y);
|
const dy = Math.abs(point.y - y);
|
||||||
const w = node.width / 2;
|
const w = node.width / 2;
|
||||||
const h = node.height / 2;
|
const h = node.height / 2;
|
||||||
if (dx >= w || dy >= h) {
|
return dx >= w || dy >= h;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const intersection = (node, outsidePoint, insidePoint) => {
|
export const intersection = (node, outsidePoint, insidePoint) => {
|
||||||
@@ -264,7 +248,6 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
|||||||
const y = node.y;
|
const y = node.y;
|
||||||
|
|
||||||
const dx = Math.abs(x - insidePoint.x);
|
const dx = Math.abs(x - insidePoint.x);
|
||||||
// const dy = Math.abs(y - insidePoint.y);
|
|
||||||
const w = node.width / 2;
|
const w = node.width / 2;
|
||||||
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
||||||
const h = node.height / 2;
|
const h = node.height / 2;
|
||||||
@@ -300,7 +283,6 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
|||||||
if (insidePoint.x < outsidePoint.x) {
|
if (insidePoint.x < outsidePoint.x) {
|
||||||
r = outsidePoint.x - w - x;
|
r = outsidePoint.x - w - x;
|
||||||
} else {
|
} else {
|
||||||
// r = outsidePoint.x - w - x;
|
|
||||||
r = x - w - outsidePoint.x;
|
r = x - w - outsidePoint.x;
|
||||||
}
|
}
|
||||||
let q = (Q * r) / R;
|
let q = (Q * r) / R;
|
||||||
@@ -530,8 +512,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
lineData.splice(-1, 0, midPoint);
|
lineData.splice(-1, 0, midPoint);
|
||||||
}
|
}
|
||||||
// This is the accessor function we talked about above
|
// This is the accessor function we talked about above
|
||||||
let curve;
|
let curve = curveBasis;
|
||||||
curve = curveBasis;
|
|
||||||
// curve = curveCardinal;
|
// curve = curveCardinal;
|
||||||
// curve = curveLinear;
|
// curve = curveLinear;
|
||||||
// curve = curveNatural;
|
// curve = curveNatural;
|
||||||
@@ -540,6 +521,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
// curve = curveCardinal.tension(0.7);
|
// curve = curveCardinal.tension(0.7);
|
||||||
// curve = curveMonotoneY;
|
// curve = curveMonotoneY;
|
||||||
// let curve = interpolateToCurve([5], curveNatural, 0.01, 10);
|
// let curve = interpolateToCurve([5], curveNatural, 0.01, 10);
|
||||||
|
|
||||||
// Currently only flowcharts get the curve from the settings, perhaps this should
|
// Currently only flowcharts get the curve from the settings, perhaps this should
|
||||||
// be expanded to a common setting? Restricting it for now in order not to cause side-effects that
|
// be expanded to a common setting? Restricting it for now in order not to cause side-effects that
|
||||||
// have not been thought through
|
// have not been thought through
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
import intersectEllipse from './intersect-ellipse.js';
|
import intersectEllipse from './intersect-ellipse.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @param node
|
|
||||||
* @param rx
|
|
||||||
* @param point
|
|
||||||
*/
|
|
||||||
function intersectCircle(node, rx, point) {
|
function intersectCircle(node, rx, point) {
|
||||||
return intersectEllipse(node, rx, rx, point);
|
return intersectEllipse(node, rx, rx, point);
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,3 @@
|
|||||||
/**
|
|
||||||
* @param node
|
|
||||||
* @param rx
|
|
||||||
* @param ry
|
|
||||||
* @param point
|
|
||||||
*/
|
|
||||||
function intersectEllipse(node, rx, ry, point) {
|
function intersectEllipse(node, rx, ry, point) {
|
||||||
// Formulae from: https://mathworld.wolfram.com/Ellipse-LineIntersection.html
|
// Formulae from: https://mathworld.wolfram.com/Ellipse-LineIntersection.html
|
||||||
|
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Returns the point at which two lines, p and q, intersect or returns undefined if they do not intersect.
|
* Returns the point at which two lines, p and q, intersect or returns undefined if they do not intersect.
|
||||||
*
|
|
||||||
* @param p1
|
|
||||||
* @param p2
|
|
||||||
* @param q1
|
|
||||||
* @param q2
|
|
||||||
*/
|
*/
|
||||||
function intersectLine(p1, p2, q1, q2) {
|
function intersectLine(p1, p2, q1, q2) {
|
||||||
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
||||||
@@ -67,10 +62,6 @@ function intersectLine(p1, p2, q1, q2) {
|
|||||||
return { x: x, y: y };
|
return { x: x, y: y };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param r1
|
|
||||||
* @param r2
|
|
||||||
*/
|
|
||||||
function sameSign(r1, r2) {
|
function sameSign(r1, r2) {
|
||||||
return r1 * r2 > 0;
|
return r1 * r2 > 0;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* @param node
|
|
||||||
* @param point
|
|
||||||
*/
|
|
||||||
function intersectNode(node, point) {
|
function intersectNode(node, point) {
|
||||||
return node.intersect(point);
|
return node.intersect(point);
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,17 @@
|
|||||||
/* eslint "no-console": off */
|
|
||||||
|
|
||||||
import intersectLine from './intersect-line.js';
|
import intersectLine from './intersect-line.js';
|
||||||
|
|
||||||
export default intersectPolygon;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the point ({x, y}) at which the point argument intersects with the node argument assuming
|
* Returns the point ({x, y}) at which the point argument intersects with the node argument assuming
|
||||||
* that it has the shape specified by polygon.
|
* that it has the shape specified by polygon.
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @param polyPoints
|
|
||||||
* @param point
|
|
||||||
*/
|
*/
|
||||||
function intersectPolygon(node, polyPoints, point) {
|
function intersectPolygon(node, polyPoints, point) {
|
||||||
var x1 = node.x;
|
let x1 = node.x;
|
||||||
var y1 = node.y;
|
let y1 = node.y;
|
||||||
|
|
||||||
var intersections = [];
|
let intersections = [];
|
||||||
|
|
||||||
var minX = Number.POSITIVE_INFINITY;
|
let minX = Number.POSITIVE_INFINITY;
|
||||||
var minY = Number.POSITIVE_INFINITY;
|
let minY = Number.POSITIVE_INFINITY;
|
||||||
if (typeof polyPoints.forEach === 'function') {
|
if (typeof polyPoints.forEach === 'function') {
|
||||||
polyPoints.forEach(function (entry) {
|
polyPoints.forEach(function (entry) {
|
||||||
minX = Math.min(minX, entry.x);
|
minX = Math.min(minX, entry.x);
|
||||||
@@ -30,13 +22,13 @@ function intersectPolygon(node, polyPoints, point) {
|
|||||||
minY = Math.min(minY, polyPoints.y);
|
minY = Math.min(minY, polyPoints.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
var left = x1 - node.width / 2 - minX;
|
let left = x1 - node.width / 2 - minX;
|
||||||
var top = y1 - node.height / 2 - minY;
|
let top = y1 - node.height / 2 - minY;
|
||||||
|
|
||||||
for (var i = 0; i < polyPoints.length; i++) {
|
for (let i = 0; i < polyPoints.length; i++) {
|
||||||
var p1 = polyPoints[i];
|
let p1 = polyPoints[i];
|
||||||
var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
let p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
||||||
var intersect = intersectLine(
|
let intersect = intersectLine(
|
||||||
node,
|
node,
|
||||||
point,
|
point,
|
||||||
{ x: left + p1.x, y: top + p1.y },
|
{ x: left + p1.x, y: top + p1.y },
|
||||||
@@ -54,16 +46,18 @@ function intersectPolygon(node, polyPoints, point) {
|
|||||||
if (intersections.length > 1) {
|
if (intersections.length > 1) {
|
||||||
// More intersections, find the one nearest to edge end point
|
// More intersections, find the one nearest to edge end point
|
||||||
intersections.sort(function (p, q) {
|
intersections.sort(function (p, q) {
|
||||||
var pdx = p.x - point.x;
|
let pdx = p.x - point.x;
|
||||||
var pdy = p.y - point.y;
|
let pdy = p.y - point.y;
|
||||||
var distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
let distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
||||||
|
|
||||||
var qdx = q.x - point.x;
|
let qdx = q.x - point.x;
|
||||||
var qdy = q.y - point.y;
|
let qdy = q.y - point.y;
|
||||||
var distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
let distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
||||||
|
|
||||||
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return intersections[0];
|
return intersections[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default intersectPolygon;
|
||||||
|
@@ -49,7 +49,7 @@ const shapes = {
|
|||||||
labelRect,
|
labelRect,
|
||||||
};
|
};
|
||||||
|
|
||||||
let nodeElems = {};
|
const nodeElems = new Map();
|
||||||
|
|
||||||
export const insertNode = async (elem, node, dir) => {
|
export const insertNode = async (elem, node, dir) => {
|
||||||
let newEl;
|
let newEl;
|
||||||
@@ -81,26 +81,23 @@ export const insertNode = async (elem, node, dir) => {
|
|||||||
if (node.tooltip) {
|
if (node.tooltip) {
|
||||||
el.attr('title', node.tooltip);
|
el.attr('title', node.tooltip);
|
||||||
}
|
}
|
||||||
// if (node.class) {
|
|
||||||
// el.attr('class', 'node default ' + node.class);
|
|
||||||
// }
|
|
||||||
|
|
||||||
nodeElems[node.id] = newEl;
|
nodeElems.set(node.id, newEl);
|
||||||
|
|
||||||
if (node.haveCallback) {
|
if (node.haveCallback) {
|
||||||
nodeElems[node.id].attr('class', nodeElems[node.id].attr('class') + ' clickable');
|
nodeElems.get(node.id).attr('class', nodeElems.get(node.id).attr('class') + ' clickable');
|
||||||
}
|
}
|
||||||
return newEl;
|
return newEl;
|
||||||
};
|
};
|
||||||
export const setNodeElem = (elem, node) => {
|
export const setNodeElem = (elem, node) => {
|
||||||
nodeElems[node.id] = elem;
|
nodeElems.set(node.id, elem);
|
||||||
};
|
};
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
nodeElems = {};
|
nodeElems.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const positionNode = (node) => {
|
export const positionNode = (node) => {
|
||||||
const el = nodeElems[node.id];
|
const el = nodeElems.get(node.id);
|
||||||
log.trace(
|
log.trace(
|
||||||
'Transforming node',
|
'Transforming node',
|
||||||
node.diff,
|
node.diff,
|
||||||
|
36
packages/mermaid/src/rendering-util/types.d.ts
vendored
36
packages/mermaid/src/rendering-util/types.d.ts
vendored
@@ -136,39 +136,3 @@ export type LayoutMethod =
|
|||||||
| 'fdp'
|
| 'fdp'
|
||||||
| 'osage'
|
| 'osage'
|
||||||
| 'grid';
|
| 'grid';
|
||||||
|
|
||||||
export function createDomElement(node: Node): Node {
|
|
||||||
// Create a new DOM element. Assuming we're creating a div as an example
|
|
||||||
const element = document.createElement('div');
|
|
||||||
|
|
||||||
// Check if node.domId is set, if not generate a unique identifier for it
|
|
||||||
if (!node.domId) {
|
|
||||||
// This is a simplistic approach to generate a unique ID
|
|
||||||
// In a real application, you might want to use a more robust method
|
|
||||||
node.domId = `node-${Math.random().toString(36).substr(2, 9)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the ID of the DOM element
|
|
||||||
element.id = node.domId;
|
|
||||||
|
|
||||||
// Optional: Apply styles and classes to the element
|
|
||||||
if (node.cssStyles) {
|
|
||||||
element.style.cssText = node.cssStyles;
|
|
||||||
}
|
|
||||||
if (node.classes) {
|
|
||||||
element.className = node.classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional: Add content or additional attributes to the element
|
|
||||||
// This can be based on other properties of the node
|
|
||||||
if (node.label) {
|
|
||||||
element.textContent = node.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the newly created element to the document body or a specific container
|
|
||||||
// This is just an example; in a real application, you might append it somewhere specific
|
|
||||||
document.body.appendChild(element);
|
|
||||||
|
|
||||||
// Return the updated node with its domId set
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user