Browse Source

可视化 update

刘立冬 2 tuần trước cách đây
mục cha
commit
b583efc4d0
1 tập tin đã thay đổi với 114 bổ sung11 xóa
  1. 114 11
      visualization/knowledge_search_traverse/index.js

+ 114 - 11
visualization/knowledge_search_traverse/index.js

@@ -511,6 +511,17 @@ function NoteNode({ id, data, sourcePosition, targetPosition }) {
     }
   };
 
+  const handleCardClick = (e) => {
+    // 如果点击的是链接或按钮(或其子元素),不处理(避免双重触发)
+    if (e.target.closest('a') || e.target.closest('button')) {
+      return;
+    }
+    // 打开原帖链接
+    if (data.note_url) {
+      window.open(data.note_url, '_blank', 'noopener,noreferrer');
+    }
+  };
+
   return (
     <div>
       <Handle
@@ -519,6 +530,7 @@ function NoteNode({ id, data, sourcePosition, targetPosition }) {
         style={{ background: '#ec4899', width: 8, height: 8 }}
       />
       <div
+        onClick={handleCardClick}
         style={{
           padding: '14px',
           borderRadius: '20px',
@@ -715,7 +727,8 @@ function NoteNode({ id, data, sourcePosition, targetPosition }) {
               alt={\`Image \${currentImageIndex + 1}\`}
               style={{
                 width: '100%',
-                height: '160px',
+                aspectRatio: '2/3',
+                height: 'auto',
                 objectFit: 'cover',
                 display: 'block',
               }}
@@ -921,10 +934,22 @@ function AnalysisNode({ data }) {
     maxWidth: '900px',
     fontSize: '12px',
     boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
+    cursor: 'pointer',
+  };
+
+  const handleCardClick = (e) => {
+    // 如果点击的是链接或按钮(或其子元素),不处理(避免双重触发)
+    if (e.target.closest('a') || e.target.closest('button')) {
+      return;
+    }
+    // 打开原帖链接
+    if (data.note_url) {
+      window.open(data.note_url, '_blank', 'noopener,noreferrer');
+    }
   };
 
   return (
-    <div style={nodeStyle}>
+    <div style={nodeStyle} onClick={handleCardClick}>
       <Handle
         type="target"
         position={Position.Left}
@@ -1496,8 +1521,8 @@ function getLayoutedElements(nodes, edges, direction = 'LR') {
     const isHorizontal = direction === 'LR';
     dagreGraph.setGraph({
       rankdir: direction,
-      nodesep: 180,   // 垂直间距 - 增加以避免节点重叠
-      ranksep: 360,  // 水平间距 - 增加以容纳更宽的节点
+      nodesep: 250,   // 垂直间距 - 增加以适应更高的note节点
+      ranksep: 400,  // 水平间距 - 增加以容纳更宽的节点
     });
 
     // 添加节点 - 根据节点类型设置不同的尺寸
@@ -1508,7 +1533,7 @@ function getLayoutedElements(nodes, edges, direction = 'LR') {
       // note 节点有轮播图,需要更大的空间
       if (node.type === 'note') {
         nodeWidth = 360;
-        nodeHeight = 380;  // 增加高度以容纳轮播图
+        nodeHeight = 550;  // 更新以适应 2:3 比例的轮播图(约450px)+ 其他内容
       }
       // analysis 节点内容很多,需要更大的空间
       else if (node.type === 'analysis') {
@@ -1545,7 +1570,7 @@ function getLayoutedElements(nodes, edges, direction = 'LR') {
       let nodeHeight = 220;
       if (node.type === 'note') {
         nodeWidth = 360;
-        nodeHeight = 380;
+        nodeHeight = 550;
       }
 
       // 将 dagre 的中心点位置转换为 React Flow 的左上角位置
@@ -1555,6 +1580,54 @@ function getLayoutedElements(nodes, edges, direction = 'LR') {
       };
     });
 
+    // 为同层级的 note 节点添加交错偏移,避免视觉重叠
+    console.log('=== 开始交错偏移逻辑 ===');
+    console.log('总节点数:', nodes.length);
+
+    const noteNodes = nodes.filter(n => n.type === 'note');
+    console.log('过滤后的 note 节点数:', noteNodes.length);
+
+    if (noteNodes.length > 1) {
+      // 输出排序前的位置
+      console.log('排序前的 note 节点位置:');
+      noteNodes.forEach((n, i) => {
+        console.log('  [' + i + '] ' + n.id.substring(0, 40) + '... | type=' + n.type + ' | pos=(' + n.position.x.toFixed(0) + ', ' + n.position.y.toFixed(0) + ')');
+      });
+
+      // 按 Y 坐标排序
+      noteNodes.sort((a, b) => a.position.y - b.position.y);
+
+      console.log('排序后的 note 节点位置:');
+      noteNodes.forEach((n, i) => {
+        console.log('  [' + i + '] ' + n.id.substring(0, 40) + '... | pos=(' + n.position.x.toFixed(0) + ', ' + n.position.y.toFixed(0) + ')');
+      });
+
+      // 为相邻的 note 节点添加 X 方向的交错
+      let appliedCount = 0;
+      noteNodes.forEach((node, index) => {
+        if (index > 0) {
+          const prevNode = noteNodes[index - 1];
+          const yDistance = node.position.y - prevNode.position.y;
+
+          console.log('检查节点对 [' + (index-1) + '] vs [' + index + ']:');
+          console.log('  Y距离: ' + yDistance.toFixed(0) + 'px');
+
+          // 直接应用偏移,不再判断 Y 距离(因为实际内容高度可能超过预设)
+          // 奇数索引向右偏移,偶数索引向左偏移
+          const offset = (index % 2 === 0) ? -200 : 200;
+          const oldX = node.position.x;
+          node.position.x += offset;
+          appliedCount++;
+          console.log('  ✅ 应用偏移: X ' + oldX.toFixed(0) + ' → ' + node.position.x.toFixed(0) + ' (偏移' + offset + 'px)');
+        }
+      });
+
+      console.log('总共应用了 ' + appliedCount + ' 次偏移');
+    } else {
+      console.log('note 节点数量 <= 1,不需要交错');
+    }
+    console.log('=== 交错偏移逻辑结束 ===');
+
     console.log('✅ Layout completed, sample node:', nodes[0]);
     return { nodes, edges };
   } catch (error) {
@@ -1618,7 +1691,7 @@ function transformData(data) {
             description: node.body_text || node.desc || '',
             isSelected: node.is_selected !== undefined ? node.is_selected : true,
             imageList: node.image_list || [],
-            noteUrl: node.note_url || '',
+            note_url: node.note_url || '',
             evaluationReason: node.evaluationReason || node.evaluation_reason || '',
             interact_info: node.interact_info || {},
             nodeType: nodeType,
@@ -1972,8 +2045,8 @@ function FlowContent() {
 
         dagreGraph.setGraph({
           rankdir: 'LR',
-          nodesep: 180,   // 垂直间距 - 增加以避免节点重叠
-          ranksep: 360,  // 水平间距 - 增加以容纳更宽的节点
+          nodesep: 250,   // 增加垂直间距以适应更高的note节点
+          ranksep: 400,  // 增加水平间距
         });
 
         visibleNodes.forEach((node) => {
@@ -1983,7 +2056,7 @@ function FlowContent() {
           // note 节点有轮播图,需要更大的空间
           if (node.type === 'note') {
             nodeWidth = 360;
-            nodeHeight = 380;
+            nodeHeight = 550;  // 更新以适应 2:3 比例的轮播图(约450px)+ 其他内容
           }
 
           dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
@@ -2003,7 +2076,7 @@ function FlowContent() {
             let nodeHeight = 220;
             if (node.type === 'note') {
               nodeWidth = 360;
-              nodeHeight = 380;
+              nodeHeight = 550;  // 更新以适应 2:3 比例的轮播图
             }
 
             node.position = {
@@ -2015,6 +2088,36 @@ function FlowContent() {
           }
         });
 
+        // 为同层级的 note 节点添加交错偏移,避免视觉重叠
+        console.log('[DYNAMIC LAYOUT] 开始应用交错偏移');
+        const noteNodesToStagger = visibleNodes.filter(n => n.type === 'note');
+        console.log('[DYNAMIC LAYOUT] note 节点数:', noteNodesToStagger.length);
+
+        if (noteNodesToStagger.length > 1) {
+          // 按 Y 坐标排序
+          noteNodesToStagger.sort((a, b) => a.position.y - b.position.y);
+
+          console.log('[DYNAMIC LAYOUT] 排序后准备应用偏移:');
+          noteNodesToStagger.forEach((n, i) => {
+            console.log('  [' + i + '] ' + n.id.substring(0, 40) + '... | pos=(' + n.position.x.toFixed(0) + ', ' + n.position.y.toFixed(0) + ')');
+          });
+
+          // 为相邻的 note 节点添加 X 方向的交错
+          let appliedCount = 0;
+          noteNodesToStagger.forEach((node, index) => {
+            if (index > 0) {
+              // 奇数索引向右偏移,偶数索引向左偏移
+              const offset = (index % 2 === 0) ? -200 : 200;
+              const oldX = node.position.x;
+              node.position.x += offset;
+              appliedCount++;
+              console.log('[DYNAMIC LAYOUT] ✅ 应用偏移: X ' + oldX.toFixed(0) + ' → ' + node.position.x.toFixed(0) + ' (偏移' + offset + 'px)');
+            }
+          });
+
+          console.log('[DYNAMIC LAYOUT] 总共应用了 ' + appliedCount + ' 次偏移');
+        }
+
         console.log('✅ Dynamic layout recalculated for', visibleNodes.length, 'visible nodes');
       } catch (error) {
         console.error('❌ Error in dynamic layout:', error);