mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-19 04:04:28 +01:00
Merge remote-tracking branch 'os_repo/5237-unified-layout-common-renderer' into alanaV11
This commit is contained in:
@@ -17,7 +17,7 @@ const {
|
|||||||
log,
|
log,
|
||||||
positionEdgeLabel,
|
positionEdgeLabel,
|
||||||
} = mermaid.internalHelpers;
|
} = mermaid.internalHelpers;
|
||||||
|
// import { insertEdge } from '../../mermaid/src/rendering-util/rendering-elements/edges.js';
|
||||||
const nodeDb = {};
|
const nodeDb = {};
|
||||||
const portPos = {};
|
const portPos = {};
|
||||||
const clusterDb = {};
|
const clusterDb = {};
|
||||||
@@ -54,7 +54,7 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
|
|||||||
let boundingBox;
|
let boundingBox;
|
||||||
const child = {
|
const child = {
|
||||||
...node,
|
...node,
|
||||||
ports: node.shape === 'diamond' ? ports : [],
|
// ports: node.shape === 'diamond' ? ports : [],
|
||||||
};
|
};
|
||||||
graph.children.push(child);
|
graph.children.push(child);
|
||||||
nodeDb[node.id] = child;
|
nodeDb[node.id] = child;
|
||||||
@@ -102,47 +102,49 @@ export const addVertices = async function (nodeEl, nodeArr, graph, parentId) {
|
|||||||
return graph;
|
return graph;
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, depth) => {
|
const drawNodes = async (relX, relY, nodeArray, svg, subgraphsEl, depth) => {
|
||||||
nodeArray.forEach(function (node) {
|
Promise.all(
|
||||||
if (node) {
|
nodeArray.map(async function (node) {
|
||||||
nodeDb[node.id] = node;
|
if (node) {
|
||||||
nodeDb[node.id].offset = {
|
nodeDb[node.id] = node;
|
||||||
posX: node.x + relX,
|
nodeDb[node.id].offset = {
|
||||||
posY: node.y + relY,
|
posX: node.x + relX,
|
||||||
x: relX,
|
posY: node.y + relY,
|
||||||
y: relY,
|
x: relX,
|
||||||
depth,
|
y: relY,
|
||||||
width: node.width,
|
depth,
|
||||||
height: node.height,
|
width: Math.max(node.width, node.labels ? node.labels[0]?.width || 0 : 0),
|
||||||
};
|
height: node.height,
|
||||||
if (node.isGroup) {
|
};
|
||||||
log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
if (node.isGroup) {
|
||||||
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
console.log('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
||||||
// TODO use faster way of cloning
|
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
||||||
const clusterNode = JSON.parse(JSON.stringify(node));
|
// TODO use faster way of cloning
|
||||||
clusterNode.x = node.offset.posX + node.width / 2;
|
const clusterNode = JSON.parse(JSON.stringify(node));
|
||||||
clusterNode.y = node.offset.posY + node.height / 2;
|
clusterNode.x = node.offset.posX + node.width / 2;
|
||||||
insertCluster(subgraphEl, clusterNode);
|
clusterNode.y = node.offset.posY + node.height / 2;
|
||||||
|
await insertCluster(subgraphEl, clusterNode);
|
||||||
|
|
||||||
log.info('Id (UGH)= ', node.shape, node.labels);
|
console.log('Id (UIO)= ', node.id, node.width, node.shape, node.labels);
|
||||||
} else {
|
} else {
|
||||||
log.info(
|
log.info(
|
||||||
'Id NODE = ',
|
'Id NODE = ',
|
||||||
node.id,
|
node.id,
|
||||||
node.x,
|
node.x,
|
||||||
node.y,
|
node.y,
|
||||||
relX,
|
relX,
|
||||||
relY,
|
relY,
|
||||||
node.domId.node(),
|
node.domId.node(),
|
||||||
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
|
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
|
||||||
);
|
);
|
||||||
node.domId.attr(
|
node.domId.attr(
|
||||||
'transform',
|
'transform',
|
||||||
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
|
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
);
|
||||||
nodeArray.forEach(function (node) {
|
nodeArray.forEach(function (node) {
|
||||||
if (node?.isGroup) {
|
if (node?.isGroup) {
|
||||||
drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, depth + 1);
|
drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, depth + 1);
|
||||||
@@ -393,7 +395,7 @@ export const addEdges = async function (dataForLayout, graph, svg) {
|
|||||||
// calculate start and end points of the edge, note that the source and target
|
// calculate start and end points of the edge, note that the source and target
|
||||||
// can be modified for shapes that have ports
|
// can be modified for shapes that have ports
|
||||||
const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);
|
const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);
|
||||||
log.debug('abc78 source and target', source, target);
|
console.log('abc78 source and target', source, target);
|
||||||
// Add the edge to the graph
|
// Add the edge to the graph
|
||||||
graph.edges.push({
|
graph.edges.push({
|
||||||
id: 'e' + edge.start + edge.end,
|
id: 'e' + edge.start + edge.end,
|
||||||
@@ -494,6 +496,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
// Add elements in the svg to be used to hold the subgraphs container
|
// Add elements in the svg to be used to hold the subgraphs container
|
||||||
// elements and the nodes
|
// elements and the nodes
|
||||||
const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');
|
const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');
|
||||||
|
|
||||||
const nodeEl = svg.insert('g').attr('class', 'nodes');
|
const nodeEl = svg.insert('g').attr('class', 'nodes');
|
||||||
|
|
||||||
// Add the nodes to the graph, this will entail creating the actual nodes
|
// Add the nodes to the graph, this will entail creating the actual nodes
|
||||||
@@ -516,21 +519,24 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
||||||
node.labels = [
|
node.labels = [
|
||||||
{
|
{
|
||||||
text: node.labelText,
|
text: node.label,
|
||||||
layoutOptions: {
|
width: node?.labelData?.width || 50,
|
||||||
'nodeLabels.placement': '[H_CENTER, V_TOP, INSIDE]',
|
height: node?.labelData?.height || 50,
|
||||||
},
|
|
||||||
width: node?.labelData?.width || 0,
|
|
||||||
height: node?.labelData?.height || 0,
|
|
||||||
},
|
},
|
||||||
|
(node.width = node.width + 2 * node.paddding),
|
||||||
|
console.log('UIO node label', node?.labelData?.width, node.padding),
|
||||||
];
|
];
|
||||||
node.layoutOptions = {
|
node.layoutOptions = {
|
||||||
'spacing.baseValue': 30,
|
'spacing.baseValue': 30,
|
||||||
|
'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
|
||||||
};
|
};
|
||||||
if (node.dir) {
|
if (node.dir) {
|
||||||
node.layoutOptions = {
|
node.layoutOptions = {
|
||||||
...node.layoutOptions,
|
...node.layoutOptions,
|
||||||
|
'elk.algorithm': algorithm,
|
||||||
'elk.direction': dir2ElkDirection(node.dir),
|
'elk.direction': dir2ElkDirection(node.dir),
|
||||||
|
'nodePlacement.strategy': data4Layout.config['elk.nodePlacement.strategy'],
|
||||||
|
'elk.layered.mergeEdges': data4Layout.config['elk.mergeEdges'],
|
||||||
'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
|
'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -561,12 +567,24 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
g.edges?.map((edge) => {
|
g.edges?.map((edge) => {
|
||||||
// (elem, edge, clusterDb, diagramType, graph, id)
|
// (elem, edge, clusterDb, diagramType, graph, id)
|
||||||
const startNode = nodeDb[edge.sources[0]];
|
const startNode = nodeDb[edge.sources[0]];
|
||||||
|
const startCluster = parentLookupDb[edge.sources[0]];
|
||||||
const endNode = nodeDb[edge.targets[0]];
|
const endNode = nodeDb[edge.targets[0]];
|
||||||
const sourceId = edge.start;
|
const sourceId = edge.start;
|
||||||
const targetId = edge.end;
|
const targetId = edge.end;
|
||||||
|
|
||||||
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
||||||
log.info('APA12 offset', offset, sourceId, targetId, edge);
|
console.log(
|
||||||
|
'offset',
|
||||||
|
offset,
|
||||||
|
sourceId,
|
||||||
|
' ==> ',
|
||||||
|
targetId,
|
||||||
|
'edge:',
|
||||||
|
edge,
|
||||||
|
'cluster:',
|
||||||
|
startCluster,
|
||||||
|
startNode
|
||||||
|
);
|
||||||
if (edge.sections) {
|
if (edge.sections) {
|
||||||
const src = edge.sections[0].startPoint;
|
const src = edge.sections[0].startPoint;
|
||||||
const dest = edge.sections[0].endPoint;
|
const dest = edge.sections[0].endPoint;
|
||||||
@@ -576,10 +594,84 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
return { x: segment.x + offset.x, y: segment.y + offset.y };
|
return { x: segment.x + offset.x, y: segment.y + offset.y };
|
||||||
});
|
});
|
||||||
edge.points = [
|
edge.points = [
|
||||||
|
{
|
||||||
|
x: startNode.x + startNode.width / 2 + offset.x,
|
||||||
|
y: startNode.y + startNode.height / 2 + offset.y,
|
||||||
|
},
|
||||||
{ x: src.x + offset.x, y: src.y + offset.y },
|
{ x: src.x + offset.x, y: src.y + offset.y },
|
||||||
...segPoints,
|
...segPoints,
|
||||||
{ x: dest.x + offset.x, y: dest.y + offset.y },
|
{ x: dest.x + offset.x, y: dest.y + offset.y },
|
||||||
|
{
|
||||||
|
x: endNode.x + endNode.width / 2 + offset.x,
|
||||||
|
y: endNode.y + endNode.height / 2 + offset.y,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
let sw = startNode.width;
|
||||||
|
let ew = endNode.width;
|
||||||
|
if (startNode.isGroup) {
|
||||||
|
const bbox = startNode.domId.node().getBBox();
|
||||||
|
// sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);
|
||||||
|
sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);
|
||||||
|
// sw = startNode.width;
|
||||||
|
console.log(
|
||||||
|
'UIO width',
|
||||||
|
startNode.id,
|
||||||
|
startNode.with,
|
||||||
|
'bbox.width=',
|
||||||
|
bbox.width,
|
||||||
|
'lw=',
|
||||||
|
startNode.labels[0].width,
|
||||||
|
'node:',
|
||||||
|
startNode.width,
|
||||||
|
'SW = ',
|
||||||
|
sw
|
||||||
|
// 'HTML:',
|
||||||
|
// startNode.domId.node().innerHTML
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (endNode.isGroup) {
|
||||||
|
const bbox = endNode.domId.node().getBBox();
|
||||||
|
ew = Math.max(startNode.width, endNode.labels[0].width + endNode.padding);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'UIO width',
|
||||||
|
startNode.id,
|
||||||
|
startNode.with,
|
||||||
|
bbox.width,
|
||||||
|
'EW = ',
|
||||||
|
ew,
|
||||||
|
'HTML:',
|
||||||
|
startNode.innerHTML
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
edge.points = cutPathAtIntersect(
|
||||||
|
edge.points.reverse(),
|
||||||
|
{
|
||||||
|
x: startNode.x + startNode.width / 2 + offset.x,
|
||||||
|
y: startNode.y + startNode.height / 2 + offset.y,
|
||||||
|
width: sw,
|
||||||
|
height: startNode.height,
|
||||||
|
intersection: startNode.intersect,
|
||||||
|
padding: startNode.padding,
|
||||||
|
},
|
||||||
|
startNode.shape === 'diamond'
|
||||||
|
).reverse();
|
||||||
|
|
||||||
|
edge.points = cutPathAtIntersect(
|
||||||
|
edge.points,
|
||||||
|
{
|
||||||
|
x: endNode.x + ew / 2 + offset.x,
|
||||||
|
y: endNode.y + endNode.height / 2 + offset.y,
|
||||||
|
width: ew,
|
||||||
|
height: endNode.height,
|
||||||
|
intersection: endNode.intersect,
|
||||||
|
padding: endNode.padding,
|
||||||
|
},
|
||||||
|
endNode.shape === 'diamond'
|
||||||
|
);
|
||||||
|
// cutPathAtIntersect(edge.points, endNode);
|
||||||
|
// }
|
||||||
const paths = insertEdge(
|
const paths = insertEdge(
|
||||||
edgesEl,
|
edgesEl,
|
||||||
edge,
|
edge,
|
||||||
@@ -597,3 +689,280 @@ export const render = async (data4Layout, svg, element, algorithm) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function intersectLine(p1, p2, q1, q2) {
|
||||||
|
console.log('UIO intersectLine', p1, p2, q1, q2);
|
||||||
|
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
||||||
|
// p7 and p473.
|
||||||
|
|
||||||
|
var a1, a2, b1, b2, c1, c2;
|
||||||
|
var r1, r2, r3, r4;
|
||||||
|
var denom, offset, num;
|
||||||
|
var x, y;
|
||||||
|
|
||||||
|
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
|
||||||
|
// b1 y + c1 = 0.
|
||||||
|
a1 = p2.y - p1.y;
|
||||||
|
b1 = p1.x - p2.x;
|
||||||
|
c1 = p2.x * p1.y - p1.x * p2.y;
|
||||||
|
|
||||||
|
// Compute r3 and r4.
|
||||||
|
r3 = a1 * q1.x + b1 * q1.y + c1;
|
||||||
|
r4 = a1 * q2.x + b1 * q2.y + c1;
|
||||||
|
|
||||||
|
// Check signs of r3 and r4. If both point 3 and point 4 lie on
|
||||||
|
// same side of line 1, the line segments do not intersect.
|
||||||
|
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
|
||||||
|
return /*DON'T_INTERSECT*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
|
||||||
|
a2 = q2.y - q1.y;
|
||||||
|
b2 = q1.x - q2.x;
|
||||||
|
c2 = q2.x * q1.y - q1.x * q2.y;
|
||||||
|
|
||||||
|
// Compute r1 and r2
|
||||||
|
r1 = a2 * p1.x + b2 * p1.y + c2;
|
||||||
|
r2 = a2 * p2.x + b2 * p2.y + c2;
|
||||||
|
|
||||||
|
// Check signs of r1 and r2. If both point 1 and point 2 lie
|
||||||
|
// on same side of second line segment, the line segments do
|
||||||
|
// not intersect.
|
||||||
|
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
||||||
|
return /*DON'T_INTERSECT*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line segments intersect: compute intersection point.
|
||||||
|
denom = a1 * b2 - a2 * b1;
|
||||||
|
if (denom === 0) {
|
||||||
|
return /*COLLINEAR*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = Math.abs(denom / 2);
|
||||||
|
|
||||||
|
// The denom/2 is to get rounding instead of truncating. It
|
||||||
|
// is added or subtracted to the numerator, depending upon the
|
||||||
|
// sign of the numerator.
|
||||||
|
num = b1 * c2 - b2 * c1;
|
||||||
|
x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
||||||
|
|
||||||
|
num = a2 * c1 - a1 * c2;
|
||||||
|
y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
||||||
|
|
||||||
|
return { x: x, y: y };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param r1
|
||||||
|
* @param r2
|
||||||
|
*/
|
||||||
|
function sameSign(r1, r2) {
|
||||||
|
return r1 * r2 > 0;
|
||||||
|
}
|
||||||
|
const diamondIntersection = (bounds, outsidePoint, insidePoint) => {
|
||||||
|
var x1 = bounds.x;
|
||||||
|
var y1 = bounds.y;
|
||||||
|
|
||||||
|
const w = bounds.width + bounds.padding;
|
||||||
|
const h = bounds.height + bounds.padding;
|
||||||
|
const s = w + h;
|
||||||
|
|
||||||
|
const polyPoints = [
|
||||||
|
{ x: x1, y: y1 - h / 2 },
|
||||||
|
{ x: x1 + w / 2, y: y1 },
|
||||||
|
{ x: x1, y: y1 + h / 2 },
|
||||||
|
{ x: x1 - w / 2, y: y1 },
|
||||||
|
];
|
||||||
|
log.debug(
|
||||||
|
`UIO diamondIntersection calc abc89:
|
||||||
|
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||||
|
insidePoint : ${JSON.stringify(insidePoint)}
|
||||||
|
node : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||||
|
polyPoints
|
||||||
|
);
|
||||||
|
|
||||||
|
var intersections = [];
|
||||||
|
|
||||||
|
var minX = Number.POSITIVE_INFINITY;
|
||||||
|
var minY = Number.POSITIVE_INFINITY;
|
||||||
|
if (typeof polyPoints.forEach === 'function') {
|
||||||
|
polyPoints.forEach(function (entry) {
|
||||||
|
minX = Math.min(minX, entry.x);
|
||||||
|
minY = Math.min(minY, entry.y);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
minX = Math.min(minX, polyPoints.x);
|
||||||
|
minY = Math.min(minY, polyPoints.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = x1 - w / 2;
|
||||||
|
var top = y1 + h / 2;
|
||||||
|
|
||||||
|
for (var i = 0; i < polyPoints.length; i++) {
|
||||||
|
var p1 = polyPoints[i];
|
||||||
|
var 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 });
|
||||||
|
|
||||||
|
if (intersect) {
|
||||||
|
intersections.push(intersect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!intersections.length) {
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersections.length > 1) {
|
||||||
|
// More intersections, find the one nearest to edge end point
|
||||||
|
intersections.sort(function (p, q) {
|
||||||
|
var pdx = p.x - point.x;
|
||||||
|
var pdy = p.y - point.y;
|
||||||
|
var distp = Math.sqrt(pdx * pdx + pdy * pdy);
|
||||||
|
|
||||||
|
var qdx = q.x - point.x;
|
||||||
|
var qdy = q.y - point.y;
|
||||||
|
var distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
||||||
|
|
||||||
|
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const intersection = (node, outsidePoint, insidePoint) => {
|
||||||
|
log.debug(`intersection calc abc89:
|
||||||
|
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||||
|
insidePoint : ${JSON.stringify(insidePoint)}
|
||||||
|
node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
|
||||||
|
const x = node.x;
|
||||||
|
const y = node.y;
|
||||||
|
|
||||||
|
const dx = Math.abs(x - insidePoint.x);
|
||||||
|
// const dy = Math.abs(y - insidePoint.y);
|
||||||
|
const w = node.width / 2;
|
||||||
|
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
||||||
|
const h = node.height / 2;
|
||||||
|
|
||||||
|
const Q = Math.abs(outsidePoint.y - insidePoint.y);
|
||||||
|
const R = Math.abs(outsidePoint.x - insidePoint.x);
|
||||||
|
|
||||||
|
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
||||||
|
// Intersection is top or bottom of rect.
|
||||||
|
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||||
|
r = (R * q) / Q;
|
||||||
|
const res = {
|
||||||
|
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
|
||||||
|
y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (r === 0) {
|
||||||
|
res.x = outsidePoint.x;
|
||||||
|
res.y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
if (R === 0) {
|
||||||
|
res.x = outsidePoint.x;
|
||||||
|
}
|
||||||
|
if (Q === 0) {
|
||||||
|
res.y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); // cspell: disable-line
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
// Intersection onn sides of rect
|
||||||
|
if (insidePoint.x < outsidePoint.x) {
|
||||||
|
r = outsidePoint.x - w - x;
|
||||||
|
} else {
|
||||||
|
// r = outsidePoint.x - w - x;
|
||||||
|
r = x - w - outsidePoint.x;
|
||||||
|
}
|
||||||
|
let 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 : 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 : outsidePoint.x + r;
|
||||||
|
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
|
||||||
|
log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
|
||||||
|
if (r === 0) {
|
||||||
|
_x = outsidePoint.x;
|
||||||
|
_y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
if (R === 0) {
|
||||||
|
_x = outsidePoint.x;
|
||||||
|
}
|
||||||
|
if (Q === 0) {
|
||||||
|
_y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { x: _x, y: _y };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const outsideNode = (node, point) => {
|
||||||
|
console.log('Checking bounds ', node, point);
|
||||||
|
const x = node.x;
|
||||||
|
const y = node.y;
|
||||||
|
const dx = Math.abs(point.x - x);
|
||||||
|
const dy = Math.abs(point.y - y);
|
||||||
|
const w = node.width / 2;
|
||||||
|
const h = node.height / 2;
|
||||||
|
if (dx >= w || dy >= h) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This function will page a path and node where the last point(s) in the path is inside the node
|
||||||
|
* and return an update path ending by the border of the node.
|
||||||
|
*
|
||||||
|
* @param {Array} _points
|
||||||
|
* @param {any} bounds
|
||||||
|
* @returns {Array} Points
|
||||||
|
*/
|
||||||
|
const cutPathAtIntersect = (_points, bounds, isDiamond: boolean) => {
|
||||||
|
console.log('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||||
|
let points = [];
|
||||||
|
let lastPointOutside = _points[0];
|
||||||
|
let isInside = false;
|
||||||
|
_points.forEach((point) => {
|
||||||
|
// const node = clusterDb[edge.toCluster].node;
|
||||||
|
console.log(' checking point', point, bounds);
|
||||||
|
|
||||||
|
// check if point is inside the boundary rect
|
||||||
|
if (!outsideNode(bounds, point) && !isInside) {
|
||||||
|
// First point inside the rect found
|
||||||
|
// Calc the intersection coord between the point anf the last point outside the rect
|
||||||
|
const inter = !isDiamond
|
||||||
|
? intersection(bounds, lastPointOutside, point)
|
||||||
|
: diamondIntersection(bounds, lastPointOutside, point);
|
||||||
|
|
||||||
|
console.log('abc88 inside', point, lastPointOutside, inter);
|
||||||
|
console.log('abc88 intersection', inter, bounds);
|
||||||
|
|
||||||
|
// // Check case where the intersection is the same as the last point
|
||||||
|
let pointPresent = false;
|
||||||
|
points.forEach((p) => {
|
||||||
|
pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
|
||||||
|
});
|
||||||
|
// if (!pointPresent) {
|
||||||
|
if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
|
||||||
|
points.push(inter);
|
||||||
|
} else {
|
||||||
|
console.log('abc88 no intersect', inter, points);
|
||||||
|
}
|
||||||
|
// points.push(inter);
|
||||||
|
isInside = true;
|
||||||
|
} else {
|
||||||
|
// Outside
|
||||||
|
console.log('abc88 outside', point, lastPointOutside, points);
|
||||||
|
lastPointOutside = point;
|
||||||
|
// points.push(point);
|
||||||
|
if (!isInside) {
|
||||||
|
points.push(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('returning points', points);
|
||||||
|
return points;
|
||||||
|
};
|
||||||
|
|||||||
@@ -870,7 +870,7 @@ export const getData = () => {
|
|||||||
label: subGraph.title,
|
label: subGraph.title,
|
||||||
labelStyle: '',
|
labelStyle: '',
|
||||||
parentId: parentDB.get(subGraph.id),
|
parentId: parentDB.get(subGraph.id),
|
||||||
padding: config.flowchart?.padding ?? 8,
|
padding: 8,
|
||||||
cssCompiledStyles: getCompiledStyles(subGraph.classes),
|
cssCompiledStyles: getCompiledStyles(subGraph.classes),
|
||||||
cssClasses: subGraph.classes.join(' '),
|
cssClasses: subGraph.classes.join(' '),
|
||||||
shape: 'rect',
|
shape: 'rect',
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
|||||||
data4Layout.diagramId = id;
|
data4Layout.diagramId = id;
|
||||||
log.debug('REF1:', data4Layout);
|
log.debug('REF1:', data4Layout);
|
||||||
await render(data4Layout, svg, element);
|
await render(data4Layout, svg, element);
|
||||||
const padding = 8;
|
const padding = data4Layout.config.flowchart?.padding ?? 8;
|
||||||
utils.insertTitle(
|
utils.insertTitle(
|
||||||
element,
|
element,
|
||||||
'statediagramTitleText',
|
'statediagramTitleText',
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ export const dataFetcher = (
|
|||||||
groupData.id = parentNodeId;
|
groupData.id = parentNodeId;
|
||||||
//add parent id to noteData
|
//add parent id to noteData
|
||||||
noteData.parentId = parentNodeId;
|
noteData.parentId = parentNodeId;
|
||||||
nodeData.parentId = parentNodeId;
|
//nodeData.parentId = parentNodeId;
|
||||||
|
|
||||||
//insert groupData
|
//insert groupData
|
||||||
insertOrUpdateNode(nodes, groupData, classes);
|
insertOrUpdateNode(nodes, groupData, classes);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
getDiagramTitle,
|
getDiagramTitle,
|
||||||
} from '../common/commonDb.js';
|
} from '../common/commonDb.js';
|
||||||
import { dataFetcher, reset as resetDataFetching } from './dataFetcher.js';
|
import { dataFetcher, reset as resetDataFetching } from './dataFetcher.js';
|
||||||
|
import { getDir } from './stateRenderer-v3-unified.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_DIAGRAM_DIRECTION,
|
DEFAULT_DIAGRAM_DIRECTION,
|
||||||
@@ -588,7 +589,7 @@ const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.t
|
|||||||
|
|
||||||
export const getData = () => {
|
export const getData = () => {
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
return { nodes, edges, other: {}, config };
|
return { nodes, edges, other: {}, config, direction: getDir(getRootDocV2()) };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { lookUpDomId } from '../flowchart/flowDb';
|
|||||||
* @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
|
||||||
*/
|
*/
|
||||||
const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
export const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
||||||
let dir = defaultDir;
|
let dir = defaultDir;
|
||||||
if (parsedItem.doc) {
|
if (parsedItem.doc) {
|
||||||
for (const parsedItemDoc of parsedItem.doc) {
|
for (const parsedItemDoc of parsedItem.doc) {
|
||||||
@@ -52,7 +52,7 @@ export const draw = async function (
|
|||||||
// Not related to the refactoring, but this is the first step in the rendering process
|
// Not related to the refactoring, but this is the first step in the rendering process
|
||||||
diag.db.extract(diag.db.getRootDocV2());
|
diag.db.extract(diag.db.getRootDocV2());
|
||||||
|
|
||||||
const DIR = getDir(diag.db.getRootDocV2());
|
//const DIR = getDir(diag.db.getRootDocV2());
|
||||||
|
|
||||||
// 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
|
||||||
@@ -74,7 +74,6 @@ export const draw = async function (
|
|||||||
|
|
||||||
data4Layout.type = diag.type;
|
data4Layout.type = diag.type;
|
||||||
data4Layout.layoutAlgorithm = layout;
|
data4Layout.layoutAlgorithm = layout;
|
||||||
data4Layout.direction = DIR;
|
|
||||||
|
|
||||||
// TODO: Should we move these two to baseConfig? These types are not there in StateConfig.
|
// TODO: Should we move these two to baseConfig? These types are not there in StateConfig.
|
||||||
|
|
||||||
@@ -102,4 +101,5 @@ export const draw = async function (
|
|||||||
export default {
|
export default {
|
||||||
getClasses,
|
getClasses,
|
||||||
draw,
|
draw,
|
||||||
|
getDir,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,18 +54,20 @@ const rect = async (parent, node) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const padding = 0 * node.padding;
|
const padding = 0 * node.padding;
|
||||||
|
const halfPadding = padding / 2;
|
||||||
|
|
||||||
const width = node.width <= bbox.width + padding ? bbox.width + padding : node.width;
|
const width =
|
||||||
if (node.width <= bbox.width + padding) {
|
(node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding;
|
||||||
node.diff = (bbox.width - node.width) / 2 - node.padding / 2;
|
if (node.width <= bbox.width + node.padding) {
|
||||||
|
node.diff = (width - node.width) / 2 - node.padding;
|
||||||
} else {
|
} else {
|
||||||
node.diff = -node.padding / 2;
|
node.diff = -node.padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalWidth = width + padding;
|
const height = node.height;
|
||||||
const totalHeight = node.height + padding;
|
const x = node.x - width / 2;
|
||||||
const x = node.x - totalWidth / 2;
|
const y = node.y - height / 2;
|
||||||
const y = node.y - totalHeight / 2;
|
// console.log('UIO diff 2', node.id, node.diff, 'totalWidth: ', width);
|
||||||
|
|
||||||
log.trace('Data ', node, JSON.stringify(node));
|
log.trace('Data ', node, JSON.stringify(node));
|
||||||
let rect;
|
let rect;
|
||||||
@@ -80,9 +82,8 @@ const rect = async (parent, node) => {
|
|||||||
fillWeight: 3,
|
fillWeight: 3,
|
||||||
seed: handdrawnSeed,
|
seed: handdrawnSeed,
|
||||||
});
|
});
|
||||||
const roughNode = rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, 0), options);
|
const roughNode = rc.path(createRoundedRectPathD(x, y, width, height, 0), options);
|
||||||
// console.log('Rough node insert CXC', roughNode);
|
// console.log('Rough node insert CXC', roughNode);
|
||||||
|
|
||||||
rect = shapeSvg.insert(() => {
|
rect = shapeSvg.insert(() => {
|
||||||
log.debug('Rough node insert CXC', roughNode);
|
log.debug('Rough node insert CXC', roughNode);
|
||||||
return roughNode;
|
return roughNode;
|
||||||
@@ -97,8 +98,8 @@ const rect = async (parent, node) => {
|
|||||||
.attr('ry', node.ry)
|
.attr('ry', node.ry)
|
||||||
.attr('x', x)
|
.attr('x', x)
|
||||||
.attr('y', y)
|
.attr('y', y)
|
||||||
.attr('width', totalWidth)
|
.attr('width', width)
|
||||||
.attr('height', totalHeight);
|
.attr('height', height);
|
||||||
}
|
}
|
||||||
const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
|
const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
|
||||||
labelEl.attr(
|
labelEl.attr(
|
||||||
@@ -116,8 +117,11 @@ const rect = async (parent, node) => {
|
|||||||
// Center the label
|
// Center the label
|
||||||
|
|
||||||
const rectBox = rect.node().getBBox();
|
const rectBox = rect.node().getBBox();
|
||||||
|
node.offsetX = 0;
|
||||||
node.width = rectBox.width;
|
node.width = rectBox.width;
|
||||||
node.height = rectBox.height;
|
node.height = rectBox.height;
|
||||||
|
// Used by layout engine to position subgraph in parent
|
||||||
|
node.offsetY = bbox.height - node.padding / 2;
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
return intersectRect(node, point);
|
return intersectRect(node, point);
|
||||||
@@ -163,6 +167,7 @@ const noteGroup = (parent, node) => {
|
|||||||
|
|
||||||
return { cluster: shapeSvg, labelBBox: { width: 0, height: 0 } };
|
return { cluster: shapeSvg, labelBBox: { width: 0, height: 0 } };
|
||||||
};
|
};
|
||||||
|
|
||||||
const roundedWithTitle = async (parent, node) => {
|
const roundedWithTitle = async (parent, node) => {
|
||||||
const siteConfig = getConfig();
|
const siteConfig = getConfig();
|
||||||
|
|
||||||
@@ -202,6 +207,7 @@ const roundedWithTitle = async (parent, node) => {
|
|||||||
dv.attr('height', bbox.height);
|
dv.attr('height', bbox.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rounded With Title
|
||||||
const padding = 0 * node.padding;
|
const padding = 0 * node.padding;
|
||||||
const halfPadding = padding / 2;
|
const halfPadding = padding / 2;
|
||||||
|
|
||||||
@@ -213,12 +219,6 @@ const roundedWithTitle = async (parent, node) => {
|
|||||||
node.diff = -node.padding;
|
node.diff = -node.padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (node.id === 'Apa0') {
|
|
||||||
// console.log('XBX here', node);
|
|
||||||
// node.y += 10;
|
|
||||||
// } else {
|
|
||||||
// console.log('XBX there', node);
|
|
||||||
// }
|
|
||||||
const height = node.height + padding;
|
const height = node.height + padding;
|
||||||
// const height = node.height + padding;
|
// const height = node.height + padding;
|
||||||
const innerHeight = node.height + padding - bbox.height - 6;
|
const innerHeight = node.height + padding - bbox.height - 6;
|
||||||
|
|||||||
@@ -483,13 +483,6 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
const tail = startNode;
|
const tail = startNode;
|
||||||
var head = endNode;
|
var head = endNode;
|
||||||
|
|
||||||
log.info(
|
|
||||||
'abc88 InsertEdge Start: ',
|
|
||||||
edge.start,
|
|
||||||
'-->',
|
|
||||||
edge.end,
|
|
||||||
JSON.stringify(points, null, 2)
|
|
||||||
);
|
|
||||||
if (head.intersect && tail.intersect) {
|
if (head.intersect && tail.intersect) {
|
||||||
// log.info('abc88 InsertEdge: 0.5', edge.start, '-->', edge.end, JSON.stringify(points));
|
// log.info('abc88 InsertEdge: 0.5', edge.start, '-->', edge.end, JSON.stringify(points));
|
||||||
points = points.slice(1, edge.points.length - 1);
|
points = points.slice(1, edge.points.length - 1);
|
||||||
|
|||||||
17947
pnpm-lock.yaml
generated
17947
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user