1
This commit is contained in:
parent
8186bdfba5
commit
4889312eb3
@ -2,6 +2,7 @@ import { Graph } from '@antv/x6';
|
|||||||
import dagre from 'dagre';
|
import dagre from 'dagre';
|
||||||
|
|
||||||
interface NodeData {
|
interface NodeData {
|
||||||
|
id: string;
|
||||||
graph: {
|
graph: {
|
||||||
position?: {
|
position?: {
|
||||||
x: number;
|
x: number;
|
||||||
@ -10,17 +11,24 @@ interface NodeData {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RelativePosition {
|
||||||
|
id: string;
|
||||||
|
position: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否所有节点都有位置信息
|
* 检查是否所有节点都有位置信息
|
||||||
* @param nodes 节点列表
|
* @param nodes 节点列表
|
||||||
* @returns 是否所有节点都有位置信息
|
* @returns 是否所有节点都有位置信息
|
||||||
*/
|
*/
|
||||||
const hasAllNodesPosition = (nodes: NodeData[]) => {
|
const hasAllNodesPosition = (nodes: NodeData[]): boolean => {
|
||||||
return nodes.every(node => {
|
return nodes.every(node => {
|
||||||
const graphData = node.graph;
|
const graphData = node.graph;
|
||||||
return graphData && graphData.position &&
|
return graphData?.position?.x != null &&
|
||||||
typeof graphData.position.x === 'number' &&
|
graphData?.position?.y != null;
|
||||||
typeof graphData.position.y === 'number';
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,29 +36,83 @@ const hasAllNodesPosition = (nodes: NodeData[]) => {
|
|||||||
* 居中显示并适应画布大小
|
* 居中显示并适应画布大小
|
||||||
* @param graph 图形实例
|
* @param graph 图形实例
|
||||||
*/
|
*/
|
||||||
const centerAndFit = (graph: Graph) => {
|
const centerAndFit = (graph: Graph): void => {
|
||||||
|
const nodes = graph.getNodes();
|
||||||
|
if (nodes.length === 0) return;
|
||||||
|
|
||||||
|
// 计算所有节点的边界
|
||||||
|
let minX = Infinity;
|
||||||
|
let minY = Infinity;
|
||||||
|
let maxX = -Infinity;
|
||||||
|
let maxY = -Infinity;
|
||||||
|
|
||||||
|
nodes.forEach(node => {
|
||||||
|
const position = node.getPosition();
|
||||||
|
const size = node.getSize();
|
||||||
|
minX = Math.min(minX, position.x);
|
||||||
|
minY = Math.min(minY, position.y);
|
||||||
|
maxX = Math.max(maxX, position.x + size.width);
|
||||||
|
maxY = Math.max(maxY, position.y + size.height);
|
||||||
|
});
|
||||||
|
|
||||||
// 获取画布大小
|
// 获取画布大小
|
||||||
const container = graph.container;
|
const container = graph.container;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const containerBBox = container.getBoundingClientRect();
|
const containerBBox = container.getBoundingClientRect();
|
||||||
const padding = 40; // 设置更大的内边距
|
const padding = 40;
|
||||||
|
|
||||||
// 居中并缩放
|
// 计算图形的宽度和高度
|
||||||
graph.centerContent();
|
const graphWidth = maxX - minX;
|
||||||
graph.zoomToFit({
|
const graphHeight = maxY - minY;
|
||||||
padding,
|
|
||||||
maxScale: 1, // 限制最大缩放比例
|
// 计算缩放比例
|
||||||
minScale: 0.5, // 限制最小缩放比例
|
const scaleX = (containerBBox.width - padding * 2) / graphWidth;
|
||||||
|
const scaleY = (containerBBox.height - padding * 2) / graphHeight;
|
||||||
|
const scale = Math.min(Math.min(scaleX, scaleY), 1);
|
||||||
|
|
||||||
|
// 计算居中位置
|
||||||
|
const tx = (containerBBox.width - graphWidth * scale) / 2 - minX * scale;
|
||||||
|
const ty = (containerBBox.height - graphHeight * scale) / 2 - minY * scale;
|
||||||
|
|
||||||
|
// 应用变换
|
||||||
|
graph.scale(scale);
|
||||||
|
graph.translate(tx, ty);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算节点的相对位置
|
||||||
|
* @param nodes 节点列表
|
||||||
|
* @returns 节点的相对位置数组
|
||||||
|
*/
|
||||||
|
const calculateRelativePositions = (nodes: NodeData[]): RelativePosition[] | null => {
|
||||||
|
if (nodes.length === 0) return null;
|
||||||
|
|
||||||
|
// 计算所有节点的最小坐标
|
||||||
|
let minX = Infinity;
|
||||||
|
let minY = Infinity;
|
||||||
|
nodes.forEach(node => {
|
||||||
|
if (node.graph?.position) {
|
||||||
|
minX = Math.min(minX, node.graph.position.x);
|
||||||
|
minY = Math.min(minY, node.graph.position.y);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 确保在视口中心
|
// 计算相对位置
|
||||||
const graphBBox = graph.getBBox();
|
const positions = nodes.map(node => {
|
||||||
if (graphBBox) {
|
if (node.graph?.position) {
|
||||||
const tx = (containerBBox.width - graphBBox.width) / 2;
|
return {
|
||||||
const ty = (containerBBox.height - graphBBox.height) / 2;
|
id: node.id,
|
||||||
graph.translate(tx, ty);
|
position: {
|
||||||
}
|
x: node.graph.position.x - minX,
|
||||||
|
y: node.graph.position.y - minY
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).filter((pos): pos is RelativePosition => pos !== null);
|
||||||
|
|
||||||
|
return positions.length > 0 ? positions : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,23 +120,32 @@ const centerAndFit = (graph: Graph) => {
|
|||||||
* @param graph 图形实例
|
* @param graph 图形实例
|
||||||
* @param nodes 节点数据列表
|
* @param nodes 节点数据列表
|
||||||
*/
|
*/
|
||||||
export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []) => {
|
export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []): void => {
|
||||||
// 如果所有节点都有位置信息,只进行居中显示
|
// 如果所有节点都有位置信息,计算并应用相对位置
|
||||||
if (nodes.length > 0 && hasAllNodesPosition(nodes)) {
|
if (nodes.length > 0 && hasAllNodesPosition(nodes)) {
|
||||||
// 等待所有节点渲染完成后再居中
|
const relativePositions = calculateRelativePositions(nodes);
|
||||||
setTimeout(() => {
|
if (relativePositions) {
|
||||||
|
// 应用相对位置
|
||||||
|
graph.getNodes().forEach(node => {
|
||||||
|
const nodePosition = relativePositions.find(pos => pos.id === node.id);
|
||||||
|
if (nodePosition) {
|
||||||
|
node.position(nodePosition.position.x, nodePosition.position.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 立即居中显示
|
||||||
centerAndFit(graph);
|
centerAndFit(graph);
|
||||||
}, 100);
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建布局图
|
||||||
const g = new dagre.graphlib.Graph();
|
const g = new dagre.graphlib.Graph();
|
||||||
g.setGraph({
|
g.setGraph({
|
||||||
rankdir: 'LR',
|
rankdir: 'LR',
|
||||||
align: 'UL',
|
align: 'UL',
|
||||||
ranksep: 100, // 增加节点间距
|
ranksep: 100,
|
||||||
nodesep: 60, // 增加节点间距
|
nodesep: 60,
|
||||||
marginx: 40, // 增加边距
|
marginx: 40,
|
||||||
marginy: 40,
|
marginy: 40,
|
||||||
});
|
});
|
||||||
g.setDefaultEdgeLabel(() => ({}));
|
g.setDefaultEdgeLabel(() => ({}));
|
||||||
@ -108,6 +179,6 @@ export const applyAutoLayout = (graph: Graph, nodes: NodeData[] = []) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 居中显示并适应画布
|
// 立即居中显示
|
||||||
centerAndFit(graph);
|
centerAndFit(graph);
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user