圆圈不重叠了
This commit is contained in:
		
							parent
							
								
									b00b1293e4
								
							
						
					
					
						commit
						1688d8b200
					
				| 
						 | 
				
			
			@ -8,6 +8,38 @@
 | 
			
		|||
import { ref, onMounted, onBeforeUnmount } from "vue";
 | 
			
		||||
import G6 from "@antv/g6";
 | 
			
		||||
 | 
			
		||||
// 注册自定义边
 | 
			
		||||
G6.registerEdge('combo-border-edge', {
 | 
			
		||||
  draw(cfg, group) {
 | 
			
		||||
    const { sourceCombo, targetCombo } = cfg;
 | 
			
		||||
    if (!sourceCombo || !targetCombo) return;
 | 
			
		||||
    // 获取圆心和半径
 | 
			
		||||
    const { x: x1, y: y1, r: r1 } = sourceCombo;
 | 
			
		||||
    const { x: x2, y: y2, r: r2 } = targetCombo;
 | 
			
		||||
    // 计算两个圆心连线的单位向量
 | 
			
		||||
    const dx = x2 - x1, dy = y2 - y1;
 | 
			
		||||
    const len = Math.sqrt(dx * dx + dy * dy);
 | 
			
		||||
    const ux = dx / len, uy = dy / len;
 | 
			
		||||
    // 计算切点
 | 
			
		||||
    const sx = x1 + ux * r1;
 | 
			
		||||
    const sy = y1 + uy * r1;
 | 
			
		||||
    const tx = x2 - ux * r2;
 | 
			
		||||
    const ty = y2 - uy * r2;
 | 
			
		||||
    // 绘制曲线或直线
 | 
			
		||||
    return group.addShape('path', {
 | 
			
		||||
      attrs: {
 | 
			
		||||
        stroke: '#fff',
 | 
			
		||||
        lineWidth: 2,
 | 
			
		||||
        path: [
 | 
			
		||||
          ['M', sx, sy],
 | 
			
		||||
          // 可加弯曲 ['Q', (sx+tx)/2+20, (sy+ty)/2-20, tx, ty]
 | 
			
		||||
          ['L', tx, ty]
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}, 'line');
 | 
			
		||||
 | 
			
		||||
let graph = null;
 | 
			
		||||
const containerRef = ref(null);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,28 +119,74 @@ onMounted(() => {
 | 
			
		|||
 | 
			
		||||
  // --- 2. G6 Graph Initialization ---
 | 
			
		||||
  const container = containerRef.value;
 | 
			
		||||
  // 1. 统计每个combo的节点数量
 | 
			
		||||
  const comboNodeCount = {};
 | 
			
		||||
  nodes.forEach(node => {
 | 
			
		||||
    comboNodeCount[node.comboId] = (comboNodeCount[node.comboId] || 0) + 1;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 先排序
 | 
			
		||||
  const sortedCombos = combos
 | 
			
		||||
    .map(combo => ({ ...combo, count: comboNodeCount[combo.id] || 0 }))
 | 
			
		||||
    .sort((a, b) => b.count - a.count);
 | 
			
		||||
 | 
			
		||||
  // 计算每排最大半径
 | 
			
		||||
  const topCombos = sortedCombos.slice(0, 3);
 | 
			
		||||
  const bottomCombos = sortedCombos.slice(3, 6);
 | 
			
		||||
  const topMaxR = Math.max(...topCombos.map(c => c.r));
 | 
			
		||||
  const bottomMaxR = Math.max(...bottomCombos.map(c => c.r));
 | 
			
		||||
 | 
			
		||||
  // 横向间距 = 前后两个combo半径之和 + 额外间隔
 | 
			
		||||
  function getX(i, combosArr, width) {
 | 
			
		||||
    let x = combosArr[0].r + 60; // 左边留空
 | 
			
		||||
    for (let j = 0; j < i; j++) {
 | 
			
		||||
      x += combosArr[j].r + combosArr[j + 1].r + 80; // 80为额外间隔
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const width = container.scrollWidth || 1200;
 | 
			
		||||
  const height = container.scrollHeight || 800;
 | 
			
		||||
  const topY = height * 0.25;
 | 
			
		||||
  const bottomY = height * 0.75;
 | 
			
		||||
 | 
			
		||||
  // 上排
 | 
			
		||||
  topCombos.forEach((combo, idx) => {
 | 
			
		||||
    combo.x = getX(idx, topCombos, width);
 | 
			
		||||
    combo.y = topY;
 | 
			
		||||
  });
 | 
			
		||||
  // 下排
 | 
			
		||||
  bottomCombos.forEach((combo, idx) => {
 | 
			
		||||
    combo.x = getX(idx, bottomCombos, width);
 | 
			
		||||
    combo.y = bottomY;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 更新 combos
 | 
			
		||||
  combos.forEach(c => {
 | 
			
		||||
    const found = [...topCombos, ...bottomCombos].find(sc => sc.id === c.id);
 | 
			
		||||
    c.x = found.x;
 | 
			
		||||
    c.y = found.y;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 5. 节点分布在各自combo圆内
 | 
			
		||||
  nodes.forEach(node => {
 | 
			
		||||
    const combo = combos.find(c => c.id === node.comboId);
 | 
			
		||||
    // 随机分布在combo圆内
 | 
			
		||||
    const angle = Math.random() * 2 * Math.PI;
 | 
			
		||||
    const radius = Math.random() * (combo.r - nodeSize / 2);
 | 
			
		||||
    node.x = combo.x + Math.cos(angle) * radius;
 | 
			
		||||
    node.y = combo.y + Math.sin(angle) * radius;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 6. 用 layout: null,G6 不再自动布局
 | 
			
		||||
  graph = new G6.Graph({
 | 
			
		||||
    container,
 | 
			
		||||
    width,
 | 
			
		||||
    height,
 | 
			
		||||
    layout: null, // 或你自定义的布局
 | 
			
		||||
    groupByTypes: false, // 允许 combo-to-combo 边
 | 
			
		||||
    // --- MODIFICATION: Set preventComboOverlap to true to avoid circle overlaps ---
 | 
			
		||||
    layout: {
 | 
			
		||||
      type: 'comboForce',
 | 
			
		||||
      preventComboOverlap: true, // 让combo不重叠
 | 
			
		||||
      preventNodeOverlap: true,  // 节点不重叠
 | 
			
		||||
      linkDistance: 250,         // 连接距离
 | 
			
		||||
      nodeSpacing: 50,           // 节点间距
 | 
			
		||||
      comboSpacing: 150,          // combo间距(可根据实际效果调整,数值越大圆圈越分开)
 | 
			
		||||
      gravity: 40,
 | 
			
		||||
      comboGravity: 30,
 | 
			
		||||
    },
 | 
			
		||||
    groupByTypes: false,
 | 
			
		||||
    layout: null,
 | 
			
		||||
    modes: {
 | 
			
		||||
      default: ['drag-canvas', 'zoom-canvas', 'drag-combo', 'drag-node'],
 | 
			
		||||
      default: ['drag-canvas', 'zoom-canvas', 'drag-combo', 'drag-node']
 | 
			
		||||
    },
 | 
			
		||||
    defaultNode: {
 | 
			
		||||
      size: nodeSize,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user