Compare commits
2 Commits
7dd25066ad
...
59d4618c2e
| Author | SHA1 | Date | |
|---|---|---|---|
| 59d4618c2e | |||
| 5447b653d2 |
+7
-58
@@ -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",
|
||||
|
||||
@@ -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,7 +72,8 @@ export const GraphView = ({
|
||||
},
|
||||
};
|
||||
}),
|
||||
edges: data.edges.map((edge: Edge) => ({
|
||||
edges: data.edges.map((edge: Edge) => {
|
||||
return {
|
||||
id: edge.id,
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
@@ -83,12 +87,12 @@ export const GraphView = ({
|
||||
},
|
||||
style: {
|
||||
stroke: '#95A5A6',
|
||||
lineWidth: 2,
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user