mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-14 12:59:46 +02:00
fix: edge intersection issue in tidy tree layout
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
This commit is contained in:
@@ -101,14 +101,7 @@
|
|||||||
C
|
C
|
||||||
D
|
D
|
||||||
</pre>
|
</pre>
|
||||||
<pre class="mermaid">
|
|
||||||
mindmap
|
|
||||||
root((mindmap is a long thing))
|
|
||||||
A
|
|
||||||
B
|
|
||||||
C
|
|
||||||
D
|
|
||||||
</pre>
|
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
@@ -369,6 +362,10 @@
|
|||||||
<hr />
|
<hr />
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import mermaid from '/mermaid.esm.mjs';
|
import mermaid from '/mermaid.esm.mjs';
|
||||||
|
import tidytree from '/mermaid-layout-tidy-tree.esm.mjs';
|
||||||
|
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||||
|
mermaid.registerLayoutLoaders(layouts);
|
||||||
|
mermaid.registerLayoutLoaders(tidytree);
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
logLevel: 3,
|
logLevel: 3,
|
||||||
|
@@ -8,6 +8,8 @@ import type {
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
|
import { log } from 'mermaid/src/logger.js';
|
||||||
|
import { intersection } from 'mermaid/src/rendering-util/rendering-elements/edges.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the tidy-tree layout algorithm on generic layout data
|
* Execute the tidy-tree layout algorithm on generic layout data
|
||||||
@@ -23,8 +25,6 @@ export function executeTidyTreeLayout(
|
|||||||
data: LayoutData,
|
data: LayoutData,
|
||||||
_config: MermaidConfig
|
_config: MermaidConfig
|
||||||
): Promise<LayoutResult> {
|
): Promise<LayoutResult> {
|
||||||
let intersectionShift = 50;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
if (!data.nodes || !Array.isArray(data.nodes) || data.nodes.length === 0) {
|
if (!data.nodes || !Array.isArray(data.nodes) || data.nodes.length === 0) {
|
||||||
@@ -39,7 +39,7 @@ export function executeTidyTreeLayout(
|
|||||||
|
|
||||||
const gap = 20;
|
const gap = 20;
|
||||||
const bottomPadding = 40;
|
const bottomPadding = 40;
|
||||||
intersectionShift = 30;
|
const intersectionShift = 30;
|
||||||
|
|
||||||
const bb = new BoundingBox(gap, bottomPadding);
|
const bb = new BoundingBox(gap, bottomPadding);
|
||||||
const layout = new Layout(bb);
|
const layout = new Layout(bb);
|
||||||
@@ -74,7 +74,6 @@ export function executeTidyTreeLayout(
|
|||||||
positionedNodes,
|
positionedNodes,
|
||||||
intersectionShift
|
intersectionShift
|
||||||
);
|
);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
nodes: positionedNodes,
|
nodes: positionedNodes,
|
||||||
edges: positionedEdges,
|
edges: positionedEdges,
|
||||||
@@ -118,8 +117,12 @@ function convertToDualTreeFormat(data: LayoutData): {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rootNodeData = nodes.find((node) => !parents.has(node.id));
|
const rootNodeData = nodes.find((node) => !parents.has(node.id));
|
||||||
if (!rootNodeData && nodes.length === 0) {
|
if (!rootNodeData) {
|
||||||
throw new Error('No nodes available to create tree');
|
// If no clear root, use the first node
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
throw new Error('No nodes available to create tree');
|
||||||
|
}
|
||||||
|
log.warn('No root node found, using first node as root');
|
||||||
}
|
}
|
||||||
|
|
||||||
const actualRoot = rootNodeData ?? nodes[0];
|
const actualRoot = rootNodeData ?? nodes[0];
|
||||||
@@ -408,53 +411,6 @@ function computeCircleEdgeIntersection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate intersection point of a line with a rectangle
|
|
||||||
* This is a simplified version that we'll use instead of importing from mermaid
|
|
||||||
*/
|
|
||||||
function intersection(
|
|
||||||
node: { x: number; y: number; width?: number; height?: number },
|
|
||||||
point1: { x: number; y: number },
|
|
||||||
point2: { x: number; y: number }
|
|
||||||
): { x: number; y: number } {
|
|
||||||
const nodeWidth = node.width ?? 100;
|
|
||||||
const nodeHeight = node.height ?? 50;
|
|
||||||
|
|
||||||
const centerX = node.x;
|
|
||||||
const centerY = node.y;
|
|
||||||
|
|
||||||
const dx = point2.x - point1.x;
|
|
||||||
const dy = point2.y - point1.y;
|
|
||||||
|
|
||||||
if (dx === 0 && dy === 0) {
|
|
||||||
return { x: centerX, y: centerY };
|
|
||||||
}
|
|
||||||
|
|
||||||
const halfWidth = nodeWidth / 2;
|
|
||||||
const halfHeight = nodeHeight / 2;
|
|
||||||
|
|
||||||
let intersectionX = centerX;
|
|
||||||
let intersectionY = centerY;
|
|
||||||
|
|
||||||
if (Math.abs(dx) > Math.abs(dy)) {
|
|
||||||
if (dx > 0) {
|
|
||||||
intersectionX = centerX + halfWidth;
|
|
||||||
intersectionY = centerY + (halfWidth * dy) / dx;
|
|
||||||
} else {
|
|
||||||
intersectionX = centerX - halfWidth;
|
|
||||||
intersectionY = centerY - (halfWidth * dy) / dx;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dy > 0) {
|
|
||||||
intersectionY = centerY + halfHeight;
|
|
||||||
intersectionX = centerX + (halfHeight * dx) / dy;
|
|
||||||
} else {
|
|
||||||
intersectionY = centerY - halfHeight;
|
|
||||||
intersectionX = centerX - (halfHeight * dx) / dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { x: intersectionX, y: intersectionY };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate edge positions based on positioned nodes
|
* Calculate edge positions based on positioned nodes
|
||||||
|
Reference in New Issue
Block a user