Compare commits

...

2 Commits

Author SHA1 Message Date
hhs 59d4618c2e chore: 修改渲染设置 2026-04-06 16:07:43 +08:00
hhs 5447b653d2 chore: 更改data.json中内容 2026-04-06 15:47:43 +08:00
4 changed files with 122 additions and 79 deletions
+7 -58
View File
@@ -8,11 +8,6 @@
"importance": 1,
"description": "计算机科学的一个分支,致力于创建能够执行通常需要人类智能的任务的机器",
"aliases": ["机器智能", "AI"]
},
"style": {
"fill": "#FF6B6B",
"stroke": "#EE5A5A",
"lineWidth": 3
}
},
{
@@ -22,11 +17,6 @@
"properties": {
"importance": 0.9,
"description": "人工智能的一个子领域,让计算机系统能够从数据中学习和改进"
},
"style": {
"fill": "#4ECDC4",
"stroke": "#45B7B0",
"lineWidth": 2
}
},
{
@@ -36,11 +26,6 @@
"properties": {
"importance": 0.8,
"description": "基于人工神经网络的机器学习方法"
},
"style": {
"fill": "#45B7D1",
"stroke": "#3DA4BA",
"lineWidth": 2
}
},
{
@@ -60,10 +45,6 @@
"importance": 0.6,
"language": "Python, C++",
"author": "Google"
},
"style": {
"fill": "#FFA07A",
"stroke": "#FF7F50"
}
},
{
@@ -74,10 +55,6 @@
"importance": 0.6,
"language": "Python",
"author": "Meta"
},
"style": {
"fill": "#FFA07A",
"stroke": "#FF7F50"
}
},
{
@@ -160,77 +137,49 @@
"source": "1",
"target": "2",
"label": "包含",
"type": "关系",
"style": {
"stroke": "#95A5A6",
"lineWidth": 2
}
"type": "关系"
},
{
"id": "e2",
"source": "2",
"target": "3",
"label": "子领域",
"type": "关系",
"style": {
"stroke": "#95A5A6",
"lineWidth": 2
}
"type": "关系"
},
{
"id": "e3",
"source": "3",
"target": "4",
"label": "基于",
"type": "技术依赖",
"style": {
"stroke": "#3498DB",
"lineWidth": 2
}
"type": "技术依赖"
},
{
"id": "e4",
"source": "3",
"target": "5",
"label": "框架",
"type": "工具关系",
"style": {
"stroke": "#E74C3C",
"lineWidth": 1
}
"type": "工具关系"
},
{
"id": "e5",
"source": "3",
"target": "6",
"label": "框架",
"type": "工具关系",
"style": {
"stroke": "#E74C3C",
"lineWidth": 1
}
"type": "工具关系"
},
{
"id": "e6",
"source": "1",
"target": "7",
"label": "应用",
"type": "应用领域",
"style": {
"stroke": "#2ECC71",
"lineWidth": 2
}
"type": "应用领域"
},
{
"id": "e7",
"source": "1",
"target": "8",
"label": "应用",
"type": "应用领域",
"style": {
"stroke": "#2ECC71",
"lineWidth": 2
}
"type": "应用领域"
},
{
"id": "e8",
+24 -21
View File
@@ -1,9 +1,10 @@
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useMemo } from 'react';
import { Graph } from '@antv/g6';
import type { GraphData, Node, Edge, GraphLayoutConfig } from '../../types/graph';
import { getNodeColors } from '../../config/colors';
import { FORCE_LAYOUT_CONFIG, GRAPH_BEHAVIORS } from '../../config/layout';
import { GRAPH_DEFAULT_HEIGHT } from '../../config/constants';
import { getNodeStyle, getEdgeStyle } from '../../utils/graphStyle';
interface GraphViewProps {
data: GraphData;
@@ -30,6 +31,8 @@ export const GraphView = ({
const onNodeClickRef = useRef(onNodeClick);
const nodeMap = useMemo(() => new Map(data.nodes.map((node: Node) => [node.id, node])), [data.nodes]);
useEffect(() => {
onNodeClickRef.current = onNodeClick;
}, [onNodeClick]);
@@ -69,26 +72,27 @@ export const GraphView = ({
},
};
}),
edges: data.edges.map((edge: Edge) => ({
id: edge.id,
source: edge.source,
target: edge.target,
label: edge.label,
data: {
edges: data.edges.map((edge: Edge) => {
return {
id: edge.id,
source: edge.source,
target: edge.target,
label: edge.label,
type: edge.type,
properties: edge.properties,
},
style: {
stroke: '#95A5A6',
lineWidth: 2,
labelText: edge.label,
labelFill: '#666',
labelFontSize: 10,
},
})),
data: {
source: edge.source,
target: edge.target,
label: edge.label,
type: edge.type,
properties: edge.properties,
},
style: {
stroke: '#95A5A6',
labelText: edge.label,
labelFill: '#666',
labelFontSize: 10,
},
};
}),
};
// 创建图谱配置
@@ -101,8 +105,8 @@ export const GraphView = ({
node: {
type: 'circle',
style: {
size: 50,
lineWidth: 2,
...getNodeStyle(),
},
state: {
selected: {
@@ -117,13 +121,12 @@ export const GraphView = ({
edge: {
type: 'line',
style: {
lineWidth: 1,
endArrow: true,
...getEdgeStyle(nodeMap),
},
state: {
selected: {
stroke: '#1890FF',
lineWidth: 3,
},
},
},
+15
View File
@@ -5,5 +5,20 @@ export const API_TIMEOUT = 10000;
// 图谱渲染配置
export const GRAPH_DEFAULT_HEIGHT = 600;
// 节点大小配置
export const DEFAULT_NODE_SIZE = 50;
export const NODE_SIZE_MIN = 10;
export const NODE_SIZE_MAX = 60;
// 边宽度配置
export const DEFAULT_EDGE_WIDTH = 1.5;
export const EDGE_WIDTH_MIN = 1;
export const EDGE_WIDTH_MAX = 2;
// Importance 配置
export const IMPORTANCE_DEFAULT = 0.8;
export const IMPORTANCE_MIN = 0;
export const IMPORTANCE_MAX = 1;
// 搜索相关常量
export const SEARCH_RESULT_MAX_HEIGHT = 256; // 16rem
+76
View File
@@ -0,0 +1,76 @@
import type { Node } from '../types/graph';
import {
NODE_SIZE_MIN,
NODE_SIZE_MAX,
EDGE_WIDTH_MIN,
EDGE_WIDTH_MAX,
IMPORTANCE_MIN,
IMPORTANCE_MAX,
} from '../config/constants';
/**
* 归一化值到 [0,1] 范围
*/
function normalizeValue(value: number, min: number, max: number): number {
if (isNaN(value) || !isFinite(value)) {
return 0.5;
}
const clamped = Math.max(min, Math.min(max, value));
return (clamped - min) / (max - min);
}
/**
* 反归一化值从 [0,1] 到目标范围
*/
function denormalizeValue(value: number, min: number, max: number): number {
if (isNaN(value) || !isFinite(value)) {
return (min + max) / 2;
}
const clamped = Math.max(0, Math.min(1, value));
return clamped * (max - min) + min;
}
/**
* 计算节点大小
*/
export function calculateNodeSize(properties?: any): number {
const importance = properties?.importance ?? IMPORTANCE_MAX;
const normalized = normalizeValue(importance, IMPORTANCE_MIN, IMPORTANCE_MAX);
const size = denormalizeValue(normalized, NODE_SIZE_MIN, NODE_SIZE_MAX) ?? NODE_SIZE_MIN;
return Math.round(size);
}
/**
* 计算边的宽度
*/
export function calculateEdgeWidth(sourceProperties?: any, targetProperties?: any): number {
const sourceImportance = sourceProperties?.importance ?? IMPORTANCE_MAX;
const targetImportance = targetProperties?.importance ?? IMPORTANCE_MAX;
const avgImportance = (sourceImportance + targetImportance) / 2;
const normalized = normalizeValue(avgImportance, IMPORTANCE_MIN, IMPORTANCE_MAX);
const width = denormalizeValue(normalized, EDGE_WIDTH_MIN, EDGE_WIDTH_MAX) ?? EDGE_WIDTH_MIN;
return parseFloat(width.toFixed(2));
}
/**
* G6 节点动态样式配置函数
* 根据 G6 文档推荐的动态配置方式实现
*/
export const getNodeStyle = () => ({
size: (datum: any) => {
const size = calculateNodeSize(datum.data?.properties);
return size;
},
});
/**
* G6 边动态样式配置函数
* 根据 G6 文档推荐的动态配置方式实现
*/
export const getEdgeStyle = (nodeMap: Map<string, Node>) => ({
lineWidth: (datum: any) => {
const sourceNode = nodeMap.get(datum.source);
const targetNode = nodeMap.get(datum.target);
return calculateEdgeWidth(sourceNode?.properties, targetNode?.properties);
},
});