Files
kevisual-center-v1/src/pages/prompt/graph/d3.ts

123 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @ts-nocheck
import * as d3 from 'd3';
import './d3.css';
export const drawGraph = (graphData) => {
// 初始配置:宽度和高度通过容器自适应
const svg = d3.select('.ai-graph');
const margin = { top: 20, right: 20, bottom: 20, left: 20 };
const updateChartSize = () => {
const width = svg.node().clientWidth - margin.left - margin.right;
const height = svg.node().clientHeight - margin.top - margin.bottom;
svg.attr('viewBox', `0 0 ${width} ${height}`);
return { width, height };
};
let { width, height } = updateChartSize();
// 使用力导向布局
const simulation = d3
.forceSimulation(graphData.nodes)
.force(
'link',
d3
.forceLink(graphData.links)
.id((d) => d.id)
.distance(100)
)
.force('charge', d3.forceManyBody().strength(-300))
.force('center', d3.forceCenter(width / 2, height / 2))
.force('collide', d3.forceCollide(20)); // 防止节点重叠半径设置为20
// 绘制连线
const link = svg.append('g')
.selectAll('line')
.data(graphData.links)
.enter()
.append('line')
.attr('class', 'link');
// 绘制节点
const node = svg.append('g')
.selectAll('g')
.data(graphData.nodes)
.enter()
.append('g')
.attr('class', 'node');
node.append('circle').attr('r', 10);
// 添加节点标签
node
.append('text')
.attr('dx', 12)
.attr('dy', '.35em')
.text((d) => d.label);
// 限制节点在SVG范围内
const clampPosition = (d, width, height) => {
d.x = Math.max(10, Math.min(width - 10, d.x)); // 10为节点半径
d.y = Math.max(10, Math.min(height - 10, d.y));
};
// 更新节点和连线位置
simulation.on('tick', () => {
link
.attr('x1', (d) => d.source.x)
.attr('y1', (d) => d.source.y)
.attr('x2', (d) => d.target.x)
.attr('y2', (d) => d.target.y);
node.attr('transform', (d) => {
// 限制节点在SVG内部
clampPosition(d, width, height);
return `translate(${d.x},${d.y})`;
});
});
// 添加拖拽事件
node.call(
d3
.drag()
.on('start', (event, d) => {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
})
.on('drag', (event, d) => {
d.fx = event.x;
d.fy = event.y;
})
.on('end', (event, d) => {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
})
);
// 添加双击事件
node.on('dblclick', (event, d) => {
d.fx = null;
d.fy = null;
console.log('dblclick', d);
});
// 监听窗口大小变化时更新图表
const resize = () => {
const { width, height } = updateChartSize();
simulation.force('center', d3.forceCenter(width / 2, height / 2));
simulation.alpha(1).restart(); // 重启仿真以更新布局
};
window.addEventListener('resize', resize);
// 在需要的时候手动调用,销毁图表时可以移除监听
return () => {
window.removeEventListener('resize', resize);
};
};