Browse Source

pref: 桑基图支持任意层级

zhengjie 5 months ago
parent
commit
4e4df28039

+ 62 - 79
src/app/components/ChartGraph/SankeyChart/SankeyChart.tsx

@@ -184,56 +184,47 @@ const SankeyChartComponent = React.memo((props: any) => {
 
       const hierarchyMap = new Map<string, SankeyNode>();
 
-      dataset.rows.forEach(row => {
-        const firstDimValue = String(row[dimensionIndices[0]]) || 'Unknown';
-        const secondDimValue = String(row[dimensionIndices[1]]) || 'Unknown';
-        const thirdDimValue = dimensionIndices[2] ? String(row[dimensionIndices[2]]) || 'Unknown' : null;
+      const buildHierarchy = (currentMap: Map<string, SankeyNode>, indices: number[], row: any[], depth: number) => {
+        const dimValue = String(row[indices[depth]]) || 'Unknown';
         const value = Number(row[valueIndex] || 0);
-
-        if (!hierarchyMap.has(firstDimValue)) {
-          hierarchyMap.set(firstDimValue, {
-            name: firstDimValue,
+        
+        if (!currentMap.has(dimValue)) {
+          currentMap.set(dimValue, {
+            name: dimValue,
             value: 0,
-            children: new Map()
+            children: depth < indices.length - 1 ? new Map() : undefined
           });
         }
 
-        const firstNode = hierarchyMap.get(firstDimValue)!;
-        firstNode.value += value;
+        const node = currentMap.get(dimValue)!;
+        node.value += value;
 
-        if (!firstNode.children!.has(secondDimValue)) {
-          firstNode.children!.set(secondDimValue, {
-            name: secondDimValue,
-            value: 0,
-            children: thirdDimValue ? new Map() : undefined
-          });
+        if (depth < indices.length - 1 && node.children) {
+          buildHierarchy(node.children, indices, row, depth + 1);
         }
+      };
 
-        const secondNode = firstNode.children!.get(secondDimValue)!;
-        secondNode.value += value;
-
-        if (thirdDimValue && secondNode.children) {
-          if (!secondNode.children.has(thirdDimValue)) {
-            secondNode.children.set(thirdDimValue, {
-              name: thirdDimValue,
-              value: 0
-            });
-          }
+      dataset.rows.forEach(row => {
+        buildHierarchy(hierarchyMap, dimensionIndices, row, 0);
+      });
 
-          const thirdNode = secondNode.children.get(thirdDimValue)!;
-          thirdNode.value += value;
+      // Recursive function to transform hierarchy map to nodes
+      const transformNodes = (nodes: Map<string, SankeyNode> | SankeyNode[]): any[] => {
+        if (nodes instanceof Map) {
+          return Array.from(nodes.values()).map(node => ({
+            name: node.name,
+            value: node.value,
+            children: node.children ? transformNodes(node.children) : undefined
+          }));
         }
-      });
+        return nodes.map(node => ({
+          name: node.name,
+          value: node.value,
+          children: node.children ? transformNodes(node.children) : undefined
+        }));
+      };
 
-      const nodes = Array.from(hierarchyMap.values()).map(node => ({
-        name: node.name,
-        value: node.value,
-        children: Array.from(node.children!.values()).map(child => ({
-          name: child.name,
-          value: child.value,
-          children: child.children ? Array.from(child.children.values()) : undefined
-        }))
-      }));
+      const nodes = transformNodes(hierarchyMap);
 
       return {
         ...defaultSpec,
@@ -386,56 +377,48 @@ class SankeyChartClass extends ReactChart {
 
       const hierarchyMap = new Map<string, SankeyNode>();
 
-      dataset.rows.forEach(row => {
-        const firstDimValue = String(row[dimensionIndices[0]]) || 'Unknown';
-        const secondDimValue = String(row[dimensionIndices[1]]) || 'Unknown';
-        const thirdDimValue = dimensionIndices[2] ? String(row[dimensionIndices[2]]) || 'Unknown' : null;
+      const buildHierarchy = (currentMap: Map<string, SankeyNode>, indices: number[], row: any[], depth: number) => {
+        const dimValue = String(row[indices[depth]]) || 'Unknown';
         const value = Number(row[valueIndex] || 0);
-
-        if (!hierarchyMap.has(firstDimValue)) {
-          hierarchyMap.set(firstDimValue, {
-            name: firstDimValue,
+        
+        if (!currentMap.has(dimValue)) {
+          currentMap.set(dimValue, {
+            name: dimValue,
             value: 0,
-            children: new Map()
+            children: depth < indices.length -1 ? new Map() : undefined
           });
         }
 
-        const firstNode = hierarchyMap.get(firstDimValue)!;
-        firstNode.value += value;
+        const node = currentMap.get(dimValue)!;
+        node.value += value;
 
-        if (!firstNode.children!.has(secondDimValue)) {
-          firstNode.children!.set(secondDimValue, {
-            name: secondDimValue,
-            value: 0,
-            children: thirdDimValue ? new Map() : undefined
-          });
+        if (depth < indices.length - 1 && node.children) {
+          buildHierarchy(node.children, indices, row, depth + 1);
         }
+      };
 
-        const secondNode = firstNode.children!.get(secondDimValue)!;
-        secondNode.value += value;
-
-        if (thirdDimValue && secondNode.children) {
-          if (!secondNode.children.has(thirdDimValue)) {
-            secondNode.children.set(thirdDimValue, {
-              name: thirdDimValue,
-              value: 0
-            });
-          }
+      dataset.rows.forEach(row => {
+        buildHierarchy(hierarchyMap, dimensionIndices, row, 0);
+      });
 
-          const thirdNode = secondNode.children.get(thirdDimValue)!;
-          thirdNode.value += value;
+      // Recursive function to transform hierarchy map to nodes
+      const transformNodes = (nodes: Map<string, SankeyNode> | SankeyNode[]): any[] => {
+        if (nodes instanceof Map) {
+          return Array.from(nodes.values()).map(node => ({
+            name: node.name,
+            value: node.value,
+            children: node.children ? transformNodes(node.children) : undefined
+          }));
         }
-      });
+        return nodes.map(node => ({
+          name: node.name,
+          value: node.value,
+          children: node.children ? transformNodes(node.children) : undefined
+        }));
+      };
 
-      const nodes = Array.from(hierarchyMap.values()).map(node => ({
-        name: node.name,
-        value: node.value,
-        children: Array.from(node.children!.values()).map(child => ({
-          name: child.name,
-          value: child.value,
-          children: child.children ? Array.from(child.children.values()) : undefined
-        }))
-      }));
+      const nodes = transformNodes(hierarchyMap);
+      console.log('nodes', nodes);
 
       return [{ nodes }];
     } catch (error) {
@@ -520,4 +503,4 @@ class SankeyChartClass extends ReactChart {
   }
 }
 
-export default SankeyChartClass;
+export default SankeyChartClass;

+ 1 - 1
src/app/components/ChartGraph/SankeyChart/config.ts

@@ -12,7 +12,7 @@ const config: ChartConfig = {
         key: 'dimension',
         required: true,
         type: 'group',
-        limit: 3,
+        limit: [3,5],
         actions: {
             STRING: ['alias', 'colorize', 'sortable'],
         },