From cd3817ce30ede239fd15877d6b59002ca8d37ee5 Mon Sep 17 00:00:00 2001 From: choizhang Date: Tue, 1 Apr 2025 00:36:32 +0800 Subject: [PATCH] feat (graph settings): Add edge thickness range configuration function --- .../src/components/graph/GraphControl.tsx | 47 +++++++++++++++++++ .../src/components/graph/Settings.tsx | 36 ++++++++++++++ lightrag_webui/src/hooks/useLightragGraph.tsx | 45 +++++++++++++++++- lightrag_webui/src/lib/constants.ts | 2 +- lightrag_webui/src/locales/en.json | 1 + lightrag_webui/src/locales/zh.json | 1 + lightrag_webui/src/stores/settings.ts | 17 +++++++ 7 files changed, 146 insertions(+), 3 deletions(-) diff --git a/lightrag_webui/src/components/graph/GraphControl.tsx b/lightrag_webui/src/components/graph/GraphControl.tsx index baa98bfe..aca8a9c4 100644 --- a/lightrag_webui/src/components/graph/GraphControl.tsx +++ b/lightrag_webui/src/components/graph/GraphControl.tsx @@ -36,6 +36,8 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents() const renderEdgeLabels = useSettingsStore.use.showEdgeLabel() const renderLabels = useSettingsStore.use.showNodeLabel() + const minEdgeSize = useSettingsStore.use.minEdgeSize() + const maxEdgeSize = useSettingsStore.use.maxEdgeSize() const selectedNode = useGraphStore.use.selectedNode() const focusedNode = useGraphStore.use.focusedNode() const selectedEdge = useGraphStore.use.selectedEdge() @@ -136,6 +138,51 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean }) registerEvents(events) }, [registerEvents, enableEdgeEvents]) + /** + * When edge size settings change, recalculate edge sizes and refresh the sigma instance + * to ensure changes take effect immediately + */ + useEffect(() => { + if (sigma && sigmaGraph) { + // Get the graph from sigma + const graph = sigma.getGraph() + + // Find min and max weight values + let minWeight = Number.MAX_SAFE_INTEGER + let maxWeight = 0 + + graph.forEachEdge(edge => { + // Get original weight (before scaling) + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + if (typeof weight === 'number') { + minWeight = Math.min(minWeight, weight) + maxWeight = Math.max(maxWeight, weight) + } + }) + + // Scale edge sizes based on weight range and current min/max edge size settings + const weightRange = maxWeight - minWeight + if (weightRange > 0) { + const sizeScale = maxEdgeSize - minEdgeSize + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + if (typeof weight === 'number') { + const scaledSize = minEdgeSize + sizeScale * Math.pow((weight - minWeight) / weightRange, 0.5) + graph.setEdgeAttribute(edge, 'size', scaledSize) + } + }) + } else { + // If all weights are the same, use default size + graph.forEachEdge(edge => { + graph.setEdgeAttribute(edge, 'size', minEdgeSize) + }) + } + + // Refresh the sigma instance to apply changes + sigma.refresh() + } + }, [sigma, sigmaGraph, minEdgeSize, maxEdgeSize]) + /** * When component mount or hovered node change * => Setting the sigma reducers diff --git a/lightrag_webui/src/components/graph/Settings.tsx b/lightrag_webui/src/components/graph/Settings.tsx index 1989a01e..b2f46203 100644 --- a/lightrag_webui/src/components/graph/Settings.tsx +++ b/lightrag_webui/src/components/graph/Settings.tsx @@ -120,6 +120,8 @@ export default function Settings() { const enableNodeDrag = useSettingsStore.use.enableNodeDrag() const enableHideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges() const showEdgeLabel = useSettingsStore.use.showEdgeLabel() + const minEdgeSize = useSettingsStore.use.minEdgeSize() + const maxEdgeSize = useSettingsStore.use.maxEdgeSize() const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth() const graphMinDegree = useSettingsStore.use.graphMinDegree() const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations() @@ -269,6 +271,40 @@ export default function Settings() { label={t('graphPanel.sideBar.settings.edgeEvents')} /> +
+ +
+ { + const newValue = Number(e.target.value); + if (!isNaN(newValue) && newValue >= 1 && newValue <= maxEdgeSize) { + useSettingsStore.setState({ minEdgeSize: newValue }); + } + }} + className="h-6 w-16 min-w-0 pr-1" + min={1} + max={maxEdgeSize} + /> + - + { + const newValue = Number(e.target.value); + if (!isNaN(newValue) && newValue >= minEdgeSize && newValue >= 1) { + useSettingsStore.setState({ maxEdgeSize: newValue }); + } + }} + className="h-6 w-16 min-w-0 pr-1" + min={minEdgeSize} + /> +
+
+ { let rawData: any = null; @@ -174,6 +180,9 @@ const fetchGraph = async (label: string, maxDepth: number, minDegree: number) => // Create a new graph instance with the raw graph data const createSigmaGraph = (rawGraph: RawGraph | null) => { + // Get edge size settings from store + const minEdgeSize = useSettingsStore.getState().minEdgeSize + const maxEdgeSize = useSettingsStore.getState().maxEdgeSize // Skip graph creation if no data or empty nodes if (!rawGraph || !rawGraph.nodes.length) { console.log('No graph data available, skipping sigma graph creation'); @@ -204,8 +213,40 @@ const createSigmaGraph = (rawGraph: RawGraph | null) => { // Add edges from raw graph data for (const rawEdge of rawGraph?.edges ?? []) { + // Get weight from edge properties or default to 1 + const weight = rawEdge.properties?.weight !== undefined ? Number(rawEdge.properties.weight) : 1 + rawEdge.dynamicId = graph.addDirectedEdge(rawEdge.source, rawEdge.target, { - label: rawEdge.properties?.keywords || undefined + label: rawEdge.properties?.keywords || undefined, + size: weight, // Set initial size based on weight + originalWeight: weight, // Store original weight for recalculation + }) + } + + // Calculate edge size based on weight range, similar to node size calculation + let minWeight = Number.MAX_SAFE_INTEGER + let maxWeight = 0 + + // Find min and max weight values + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + minWeight = Math.min(minWeight, weight) + maxWeight = Math.max(maxWeight, weight) + }) + + // Scale edge sizes based on weight range + const weightRange = maxWeight - minWeight + if (weightRange > 0) { + const sizeScale = maxEdgeSize - minEdgeSize + graph.forEachEdge(edge => { + const weight = graph.getEdgeAttribute(edge, 'originalWeight') || 1 + const scaledSize = minEdgeSize + sizeScale * Math.pow((weight - minWeight) / weightRange, 0.5) + graph.setEdgeAttribute(edge, 'size', scaledSize) + }) + } else { + // If all weights are the same, use default size + graph.forEachEdge(edge => { + graph.setEdgeAttribute(edge, 'size', minEdgeSize) }) } diff --git a/lightrag_webui/src/lib/constants.ts b/lightrag_webui/src/lib/constants.ts index 048ae8f7..87db8cea 100644 --- a/lightrag_webui/src/lib/constants.ts +++ b/lightrag_webui/src/lib/constants.ts @@ -1,6 +1,6 @@ import { ButtonVariantType } from '@/components/ui/Button' -export const backendBaseUrl = '' +export const backendBaseUrl = 'http://localhost:9621' export const webuiPrefix = '/webui/' export const controlButtonVariant: ButtonVariantType = 'ghost' diff --git a/lightrag_webui/src/locales/en.json b/lightrag_webui/src/locales/en.json index d7c68c73..53505eb6 100644 --- a/lightrag_webui/src/locales/en.json +++ b/lightrag_webui/src/locales/en.json @@ -141,6 +141,7 @@ "maxQueryDepth": "Max Query Depth", "minDegree": "Minimum Degree", "maxLayoutIterations": "Max Layout Iterations", + "edgeSizeRange": "Edge Size Range", "depth": "Depth", "degree": "Degree", "apiKey": "API Key", diff --git a/lightrag_webui/src/locales/zh.json b/lightrag_webui/src/locales/zh.json index bd1a1841..7ff58d5d 100644 --- a/lightrag_webui/src/locales/zh.json +++ b/lightrag_webui/src/locales/zh.json @@ -141,6 +141,7 @@ "maxQueryDepth": "最大查询深度", "minDegree": "最小邻边数", "maxLayoutIterations": "最大布局迭代次数", + "edgeSizeRange": "边粗细范围", "depth": "深度", "degree": "邻边", "apiKey": "API密钥", diff --git a/lightrag_webui/src/stores/settings.ts b/lightrag_webui/src/stores/settings.ts index 311e5061..0acbbb86 100644 --- a/lightrag_webui/src/stores/settings.ts +++ b/lightrag_webui/src/stores/settings.ts @@ -24,6 +24,12 @@ interface SettingsState { enableHideUnselectedEdges: boolean enableEdgeEvents: boolean + minEdgeSize: number + setMinEdgeSize: (size: number) => void + + maxEdgeSize: number + setMaxEdgeSize: (size: number) => void + graphQueryMaxDepth: number setGraphQueryMaxDepth: (depth: number) => void @@ -76,6 +82,9 @@ const useSettingsStoreBase = create()( enableHideUnselectedEdges: true, enableEdgeEvents: false, + minEdgeSize: 1, + maxEdgeSize: 1, + graphQueryMaxDepth: 3, graphMinDegree: 0, graphLayoutMaxIterations: 15, @@ -132,6 +141,10 @@ const useSettingsStoreBase = create()( setGraphMinDegree: (degree: number) => set({ graphMinDegree: degree }), + setMinEdgeSize: (size: number) => set({ minEdgeSize: size }), + + setMaxEdgeSize: (size: number) => set({ maxEdgeSize: size }), + setEnableHealthCheck: (enable: boolean) => set({ enableHealthCheck: enable }), setApiKey: (apiKey: string | null) => set({ apiKey }), @@ -196,6 +209,10 @@ const useSettingsStoreBase = create()( if (version < 9) { state.showFileName = false } + if (version < 10) { + state.minEdgeSize = 1 + state.maxEdgeSize = 1 + } return state } }