yangdx commited on
Commit
f245cd6
·
1 Parent(s): dc36e22

Optimize node color by pre-set colors

Browse files
lightrag_webui/src/hooks/useLightragGraph.tsx CHANGED
@@ -1,7 +1,7 @@
1
  import Graph, { DirectedGraph } from 'graphology'
2
  import { useCallback, useEffect, useRef } from 'react'
3
  import { useTranslation } from 'react-i18next'
4
- import { randomColor, errorMessage } from '@/lib/utils'
5
  import * as Constants from '@/lib/constants'
6
  import { useGraphStore, RawGraph, RawNodeType, RawEdgeType } from '@/stores/graph'
7
  import { toast } from 'sonner'
@@ -11,32 +11,115 @@ import { useSettingsStore } from '@/stores/settings'
11
 
12
  import seedrandom from 'seedrandom'
13
 
14
- // Helper function to generate a color based on type
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  const getNodeColorByType = (nodeType: string | undefined): string => {
16
- const defaultColor = '#CCCCCC'; // Default color for nodes without a type or undefined type
 
 
17
  if (!nodeType) {
18
  return defaultColor;
19
  }
20
 
 
21
  const typeColorMap = useGraphStore.getState().typeColorMap;
22
 
23
- if (!typeColorMap.has(nodeType)) {
24
- // Generate a color based on the type string itself for consistency
25
- // Seed the global random number generator based on the node type
26
- seedrandom(nodeType, { global: true });
27
- // Call randomColor without arguments; it will use the globally seeded Math.random()
28
- const newColor = randomColor();
29
 
30
- const newMap = new Map(typeColorMap);
31
- newMap.set(nodeType, newColor);
32
- useGraphStore.setState({ typeColorMap: newMap });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- return newColor;
 
 
 
 
 
 
 
 
 
 
35
  }
36
 
37
- // Restore the default random seed if necessary, though usually not required for this use case
38
- // seedrandom(Date.now().toString(), { global: true });
39
- return typeColorMap.get(nodeType) || defaultColor; // Add fallback just in case
 
 
 
 
 
 
40
  };
41
 
42
 
@@ -408,7 +491,7 @@ const useLightrangeGraph = () => {
408
  // Add a single node with "Graph Is Empty" label
409
  emptyGraph.addNode('empty-graph-node', {
410
  label: t('graphPanel.emptyGraph'),
411
- color: '#cccccc', // gray color
412
  x: 0.5,
413
  y: 0.5,
414
  size: 15,
@@ -836,25 +919,25 @@ const useLightrangeGraph = () => {
836
  try {
837
  const state = useGraphStore.getState();
838
 
839
- // 1. 检查节点是否存在
840
  if (!sigmaGraph.hasNode(nodeId)) {
841
  console.error('Node not found:', nodeId);
842
  return;
843
  }
844
 
845
- // 2. 获取要删除的节点
846
  const nodesToDelete = getNodesThatWillBeDeleted(nodeId, sigmaGraph);
847
 
848
- // 3. 检查是否会删除所有节点
849
  if (nodesToDelete.size === sigmaGraph.nodes().length) {
850
  toast.error(t('graphPanel.propertiesView.node.deleteAllNodesError'));
851
  return;
852
  }
853
 
854
- // 4. 清除选中状态 - 这会导致PropertiesView立即关闭
855
  state.clearSelection();
856
 
857
- // 5. 删除节点和相关边
858
  for (const nodeToDelete of nodesToDelete) {
859
  // Remove the node from the sigma graph (this will also remove connected edges)
860
  sigmaGraph.dropNode(nodeToDelete);
 
1
  import Graph, { DirectedGraph } from 'graphology'
2
  import { useCallback, useEffect, useRef } from 'react'
3
  import { useTranslation } from 'react-i18next'
4
+ import { errorMessage } from '@/lib/utils'
5
  import * as Constants from '@/lib/constants'
6
  import { useGraphStore, RawGraph, RawNodeType, RawEdgeType } from '@/stores/graph'
7
  import { toast } from 'sonner'
 
11
 
12
  import seedrandom from 'seedrandom'
13
 
14
+ // Predefined node colors - Primary colors
15
+ const NODE_COLORS = [
16
+ '#0f5870', // Deep Cyan
17
+ '#e3493b', // Google Red - geo
18
+ '#fdd868', // Yellow - UNKNOWN
19
+ '#34A853', // Google Green
20
+ '#a64dff', // Purple
21
+ '#F39C12', // Orange
22
+ '#1ABC9C', // Turquoise - organization
23
+ '#1f42ad', // Blue
24
+ '#ee8377', // Light Red
25
+ '#bf95d0', // Light Violet
26
+ '#99cc00', // Yellow Green - tecknology
27
+ '#0f705d', // Deep Turquoise
28
+ '#E67E22', // Carrot - category
29
+ '#568be1', // Light Blue - person
30
+ '#803300' // Deep Brown
31
+ ];
32
+
33
+ // Extended colors - Used when node types exceed primary colors
34
+ const EXTENDED_COLORS = [
35
+ '#ff4da6', // Magenta
36
+ '#094338', // Deep Green
37
+ '#D35400', // Pumpkin
38
+ '#002699', // Deep Blue
39
+ '#5a2c6d', // Deep Violet
40
+ '#996600', // Brown
41
+ '#2574A9', // Steel Blue
42
+ '#912c21', // Deep Red
43
+ '#293618' // Dark Green
44
+ ];
45
+
46
+ // All available colors combined
47
+ const ALL_COLORS = [...NODE_COLORS, ...EXTENDED_COLORS];
48
+
49
+ // Helper function to get color based on node type
50
  const getNodeColorByType = (nodeType: string | undefined): string => {
51
+ const defaultColor = '#5D6D7E'; // Default color for nodes without a type or undefined type
52
+
53
+ // Return default color if node type is undefined
54
  if (!nodeType) {
55
  return defaultColor;
56
  }
57
 
58
+ // Get type color map from store
59
  const typeColorMap = useGraphStore.getState().typeColorMap;
60
 
61
+ // If this type already has an assigned color, return it
62
+ if (typeColorMap.has(nodeType)) {
63
+ return typeColorMap.get(nodeType) || defaultColor;
64
+ }
 
 
65
 
66
+ // Get all currently used colors
67
+ const usedColors = new Set<string>();
68
+ typeColorMap.forEach(color => {
69
+ usedColors.add(color);
70
+ });
71
+
72
+ // Assign color for new node type
73
+ // Use a simple hash function to map node type to color index
74
+ const getColorIndex = (str: string): number => {
75
+ let hash = 0;
76
+ for (let i = 0; i < str.length; i++) {
77
+ hash = ((hash << 5) - hash) + str.charCodeAt(i);
78
+ hash |= 0; // Convert to 32bit integer
79
+ }
80
+ // Ensure result is positive and within NODE_COLORS range only
81
+ return Math.abs(hash) % NODE_COLORS.length;
82
+ };
83
+
84
+ // Get initial color index from hash
85
+ const colorIndex = getColorIndex(nodeType);
86
+ let newColor = NODE_COLORS[colorIndex];
87
+
88
+ // If the color is already used, find the next available color
89
+ if (usedColors.has(newColor) && usedColors.size < ALL_COLORS.length) {
90
+ // First try to find an unused color in NODE_COLORS
91
+ let foundUnused = false;
92
+ for (let i = 0; i < NODE_COLORS.length; i++) {
93
+ const candidateColor = NODE_COLORS[i];
94
+ if (!usedColors.has(candidateColor)) {
95
+ newColor = candidateColor;
96
+ foundUnused = true;
97
+ break;
98
+ }
99
+ }
100
 
101
+ // If all NODE_COLORS are used, then try EXTENDED_COLORS
102
+ if (!foundUnused) {
103
+ newColor = defaultColor;
104
+ for (let i = 0; i < EXTENDED_COLORS.length; i++) {
105
+ const candidateColor = EXTENDED_COLORS[i];
106
+ if (!usedColors.has(candidateColor)) {
107
+ newColor = candidateColor;
108
+ break;
109
+ }
110
+ }
111
+ }
112
  }
113
 
114
+ // If all colors are used, we'll still use the hashed color
115
+ // In a more advanced implementation, we could create color variants here
116
+
117
+ // Update color mapping
118
+ const newMap = new Map(typeColorMap);
119
+ newMap.set(nodeType, newColor);
120
+ useGraphStore.setState({ typeColorMap: newMap });
121
+
122
+ return newColor;
123
  };
124
 
125
 
 
491
  // Add a single node with "Graph Is Empty" label
492
  emptyGraph.addNode('empty-graph-node', {
493
  label: t('graphPanel.emptyGraph'),
494
+ color: '#5D6D7E', // gray color
495
  x: 0.5,
496
  y: 0.5,
497
  size: 15,
 
919
  try {
920
  const state = useGraphStore.getState();
921
 
922
+ // 1. Check if node exists
923
  if (!sigmaGraph.hasNode(nodeId)) {
924
  console.error('Node not found:', nodeId);
925
  return;
926
  }
927
 
928
+ // 2. Get nodes to delete
929
  const nodesToDelete = getNodesThatWillBeDeleted(nodeId, sigmaGraph);
930
 
931
+ // 3. Check if this would delete all nodes
932
  if (nodesToDelete.size === sigmaGraph.nodes().length) {
933
  toast.error(t('graphPanel.propertiesView.node.deleteAllNodesError'));
934
  return;
935
  }
936
 
937
+ // 4. Clear selection - this will cause PropertiesView to close immediately
938
  state.clearSelection();
939
 
940
+ // 5. Delete nodes and related edges
941
  for (const nodeToDelete of nodesToDelete) {
942
  // Remove the node from the sigma graph (this will also remove connected edges)
943
  sigmaGraph.dropNode(nodeToDelete);