diff --git a/.cspell/libraries.txt b/.cspell/libraries.txt index 185d284f7..10be49ad4 100644 --- a/.cspell/libraries.txt +++ b/.cspell/libraries.txt @@ -47,6 +47,7 @@ mdbook Mermerd mkdocs Nextra +NODECOUNT nodenext npmjs pageview @@ -58,6 +59,7 @@ presetAttributify pyplot redmine rehype +RIGHTDOWN roughjs rscratch shiki @@ -67,6 +69,7 @@ sphinxcontrib ssim stylis Swimm +topdown tsbuildinfo tseslint Tuleap diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index bc624ad0c..da92fde25 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -93,14 +93,14 @@ config: look: classic theme: forest - layout: elk + layout: dagre --- flowchart LR A["A"] --> C B("B B B B B") --> C[/"C C C C C"/] C@{ shape: circle } %%C@{ shape: question } - %%C@{ shape: stadium } + C@{ shape: stadium }
---
@@ -114,6 +114,7 @@ flowchart LR
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
+ C@{ shape: db }
---
diff --git a/packages/mermaid-layout-elk/src/render.ts b/packages/mermaid-layout-elk/src/render.ts
index cc373f700..82b271fa8 100644
--- a/packages/mermaid-layout-elk/src/render.ts
+++ b/packages/mermaid-layout-elk/src/render.ts
@@ -484,317 +484,6 @@ export const render = async (
}
}
- function intersectLine(
- p1: { y: number; x: number },
- p2: { y: number; x: number },
- q1: { x: any; y: any },
- q2: { x: any; y: any }
- ) {
- log.debug('UIO intersectLine', p1, p2, q1, q2);
- // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
- // p7 and p473.
-
- // let a1, a2, b1, b2, c1, c2;
- // let r1, r2, r3, r4;
- // let denom, offset, num;
- // let x, y;
-
- // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
- // b1 y + c1 = 0.
- const a1 = p2.y - p1.y;
- const b1 = p1.x - p2.x;
- const c1 = p2.x * p1.y - p1.x * p2.y;
-
- // Compute r3 and r4.
- const r3 = a1 * q1.x + b1 * q1.y + c1;
- const r4 = a1 * q2.x + b1 * q2.y + c1;
-
- const epsilon = 1e-6;
-
- // 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
- const a2 = q2.y - q1.y;
- const b2 = q1.x - q2.x;
- const c2 = q2.x * q1.y - q1.x * q2.y;
-
- // Compute r1 and r2
- const r1 = a2 * p1.x + b2 * p1.y + c2;
- const 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 (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
- return /*DON'T_INTERSECT*/;
- }
-
- // Line segments intersect: compute intersection point.
- const denom = a1 * b2 - a2 * b1;
- if (denom === 0) {
- return /*COLLINEAR*/;
- }
-
- const 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.
- let num = b1 * c2 - b2 * c1;
- const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
-
- num = a2 * c1 - a1 * c2;
- const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
-
- return { x: x, y: y };
- }
-
- function sameSign(r1: number, r2: number) {
- return r1 * r2 > 0;
- }
- const diamondIntersection = (
- bounds: { x: any; y: any; width: any; height: any },
- outsidePoint: { x: number; y: number },
- insidePoint: any
- ) => {
- const x1 = bounds.x;
- const y1 = bounds.y;
-
- const w = bounds.width - 0.1; //+ bounds.padding;
- const h = bounds.height - 0.1; // + bounds.padding;
-
- 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(
- `APA16 diamondIntersection calc abc89:
- outsidePoint: ${JSON.stringify(outsidePoint)}
- insidePoint : ${JSON.stringify(insidePoint)}
- node-bounds : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
- JSON.stringify(polyPoints)
- );
-
- const intersections = [];
-
- let minX = Number.POSITIVE_INFINITY;
- let minY = Number.POSITIVE_INFINITY;
-
- polyPoints.forEach(function (entry) {
- minX = Math.min(minX, entry.x);
- minY = Math.min(minY, entry.y);
- });
-
- const left = x1 - w / 2 - minX;
- const top = y1 - h / 2 - minY;
-
- for (let i = 0; i < polyPoints.length; i++) {
- const p1 = polyPoints[i];
- const p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
- const intersect = intersectLine(
- bounds,
- outsidePoint,
- { x: left + p1.x, y: top + p1.y },
- { x: left + p2.x, y: top + p2.y }
- );
-
- if (intersect) {
- intersections.push(intersect);
- }
- }
-
- if (!intersections.length) {
- return bounds;
- }
-
- log.debug('UIO intersections', intersections);
-
- if (intersections.length > 1) {
- // More intersections, find the one nearest to edge end point
- intersections.sort(function (p, q) {
- const pdx = p.x - outsidePoint.x;
- const pdy = p.y - outsidePoint.y;
- const distp = Math.sqrt(pdx * pdx + pdy * pdy);
-
- const qdx = q.x - outsidePoint.x;
- const qdy = q.y - outsidePoint.y;
- const distq = Math.sqrt(qdx * qdx + qdy * qdy);
-
- return distp < distq ? -1 : distp === distq ? 0 : 1;
- });
- }
-
- return intersections[0];
- };
-
- const intersection = (
- node: { x: any; y: any; width: number; height: number },
- outsidePoint: { x: number; y: number },
- insidePoint: { x: number; y: number }
- ) => {
- 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.
- const 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;
- }
- 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 : 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: { x: any; y: any; width: number; height: number },
- point: { x: number; y: number }
- ) => {
- 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 take 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.
- */
- // const cutPathAtIntersect2 = (node: any, _points: any[], offset: any, bounds: any) => {
- // // Iterate over the points in the path and check if the point is inside the node
- // const points: any[] = [];
- // let lastPointOutside = _points[0];
- // let isInside = false;
- // _points.forEach((point: any) => {
- // const int = node.intersect(point);
- // // console.log('UIO cutPathAtIntersect2 Points:', point, 'int', int);
- // });
- // return points;
- // };
- /**
- * This function will take 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.
- */
- const cutPathAtIntersect = (
- _points: any[],
- bounds: { x: any; y: any; width: any; height: any; padding: any },
- isDiamond: boolean
- ) => {
- log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
- const points: any[] = [];
- let lastPointOutside = _points[0];
- let isInside = false;
- _points.forEach((point: any) => {
- // 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
- let inter;
-
- if (isDiamond) {
- const inter2 = diamondIntersection(bounds, lastPointOutside, point);
- const distance = Math.sqrt(
- (lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
- );
- if (distance > 1) {
- inter = inter2;
- }
- }
- if (!inter) {
- inter = intersection(bounds, lastPointOutside, point);
- }
-
- // 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 {
- log.debug('abc88 no intersect', inter, points);
- }
- // points.push(inter);
- isInside = true;
- } else {
- // Outside
- log.debug('abc88 outside', point, lastPointOutside, points);
- lastPointOutside = point;
- // points.push(point);
- if (!isInside) {
- points.push(point);
- }
- }
- });
- return points;
- };
-
// @ts-ignore - ELK is not typed
const elk = new ELK();
const element = svg.select('g');
@@ -1026,82 +715,40 @@ export const render = async (
}
if (startNode.intersect) {
// Remove the first point of the edge points
- edge.points.shift();
+ // edge.points.shift();
+ const firstPoint = edge.points[0];
+ // Transpose points to adjust for elk standard
+ const adjustedFirstPoint = {
+ x: firstPoint.x - startNode.width / 2,
+ y: firstPoint.y - startNode.height / 2,
+ };
+ const intersectionRaw = startNode.intersect(adjustedFirstPoint);
+ const intersection = {
+ x: intersectionRaw.x + startNode.width / 2,
+ y: intersectionRaw.y + startNode.height / 2,
+ };
- // console.log(
- // 'APA13 calculating start intersection start node',
- // startNode.id,
- // startNode.x,
- // startNode.y,
- // 'w:',
- // startNode.width,
- // 'h:',
- // startNode.height,
- // '\nPos',
- // edge.points[0]
- // );
- const intersection2 = startNode.calcIntersect(
- {
- x: startNode.offset.posX + startNode.width / 2,
- y: startNode.offset.posY + startNode.height / 2,
- width: startNode.width,
- height: startNode.height,
- },
- edge.points[0]
- );
- const intersection = startNode.intersect(edge.points[0]);
-
- if (distance(intersection2, edge.points[0]) > epsilon) {
- // intersection.x = -startNode.offset.posX + intersection.x + startNode.width / 2;
- // intersection.y = intersection.y + startNode.height / 2 + 5;
- edge.points.unshift(intersection2);
+ if (distance(intersection, firstPoint) > epsilon) {
+ edge.points.unshift(intersection);
}
}
if (endNode.intersect) {
// Remove the last point of the edge points
// edge.points.pop();
- const intersection2 = endNode.calcIntersect(
- {
- x: endNode.offset.posX + endNode.width / 2,
- y: endNode.offset.posY + endNode.height / 2,
- width: endNode.width,
- height: endNode.height,
- },
- edge.points[edge.points.length - 1]
- );
- console.log('APA13 intersection2', endNode);
- const intersection = endNode.intersect(edge.points[edge.points.length - 1]);
- // if (edge.id === 'L_n4_C_10_0') {
- // console.log('APA14 lineData', edge.points, 'intersection:', intersection);
- // console.log(
- // 'APA14! calculating end intersection\ndistance:',
- // distance(intersection, edge.points[edge.points.length - 1])
- // );
- // }
- console.log('APA13 intersection2.2', intersection, intersection2);
- if (distance(intersection2, edge.points[edge.points.length - 1]) > epsilon) {
- console.log(
- 'APA13! distance ok\nintersection:',
- intersection,
- '\nstartNode:',
- startNode.id,
- '\nendNode:',
- endNode.id,
- '\n distance',
- distance(intersection2, edge.points[edge.points.length - 1])
- );
- edge.points.push(intersection2);
- // console.log('APA13! distance ok\npoints:', edge.points);
- } else {
- console.log(
- 'APA13! distance not ok\nintersection:',
- intersection,
- '\nstartNode:',
- startNode.id,
- '\nendNode:',
- endNode.id
- );
+ const lastPoint = edge.points[edge.points.length - 1];
+ // Transpose points to adjust for elk standard
+ const adjustedLastPoint = {
+ x: lastPoint.x - endNode.width / 2,
+ y: lastPoint.y - endNode.height / 2,
+ };
+ const intersectionRaw = endNode.intersect(adjustedLastPoint);
+ const intersection = {
+ x: intersectionRaw.x + endNode.width / 2,
+ y: intersectionRaw.y + endNode.height / 2,
+ };
+ if (distance(intersection, lastPoint) > epsilon) {
+ edge.points.push(intersection);
}
}
diff --git a/packages/mermaid/src/rendering-util/rendering-elements/edges.js b/packages/mermaid/src/rendering-util/rendering-elements/edges.js
index 2bbf68e0f..d6bacc0cf 100644
--- a/packages/mermaid/src/rendering-util/rendering-elements/edges.js
+++ b/packages/mermaid/src/rendering-util/rendering-elements/edges.js
@@ -672,11 +672,6 @@ function generateRoundedPath(points, radius) {
// Draw the quadratic Bezier curve
path += `Q${currPoint.x},${currPoint.y} ${endX},${endY}`;
} else {
- // // Draw the line to the start of the curve
- // path += `L${startX},${startY}`;
- // path += `Q${currPoint.x},${currPoint.y} ${currPoint.x},${currPoint.y}`;
- // Draw the line to the start of the curve
- // path += `L${startX},${startY}`;
path += `L${lastPoint.x},${lastPoint.y}`;
}
}