registerLayout.ts 3.62 KB
import { Base } from '@antv/layout/lib/layout/base';

import { DagreLayoutOptions, Node } from '@antv/layout/lib/layout/types';
import { itemHeight, maxLevel, nodeWidth } from './registerShape';
import G6 from '@antv/g6';
/**
 * 默认从左到右(maxLayer--->minLayer)
 * 默认居中对齐
 */
class CustomDagreLayout extends Base {
  /** 布局的起始(左上角)位置 */
  public begin: number[] = [0, 0];

  /** 节点水平间距(px) */
  public nodesep: number = 0;

  /** 每一层节点之间间距 */
  public ranksep: number = 40;

  constructor(options?: DagreLayoutOptions) {
    super();
    this.updateCfg(options);
  }

  public getDefaultCfg() {
    return {
      rankdir: "LR",
      nodesep: 0, // 节点水平间距(px)
      ranksep: 40, // 每一层节点之间间距
      begin: [0, 0], // 布局的起点位置
    };
  }

  /**
   * 执行布局
   */
  public execute() {
   
    const self = this;
    const { nodes, edges, ranksep, nodesep, begin } = self;
    if (!nodes) return;
    const layerMap: Map<number, Node[]> = new Map();
    nodes.forEach((item: any, index, arr) => {
    
      if (!layerMap.has(item.level)) {
        layerMap.set(
          item.level,
          arr.filter((node: any) => node.level === item.level)
        );
      }
    });

    // TODO 重新调整层级
    const startX = begin[0];
    const startY = begin[1];
    const size = layerMap.size;
    const maxWidth = size * nodeWidth + (size - 1) * ranksep;
    const keyHr: any = {};
    layerMap.forEach((list, key) => {
      const sum = list.reduce((pre: any, curr: any) => {
        return pre + curr.size[1];
      }, 0);
      let v = sum + (list.length - 1) * nodesep;
      keyHr[key] = v;
    });
    const offsetX = startX + maxWidth;
    // y轴始终以正中间为中心。
    const centerLine = startY;

    const comboSpace = 200;

   let arr = Array.from(layerMap.keys()).sort((a, b) => {
    return a-b;
   });
   let min: any = null;
   if (arr[0] < 1) {
     min = Math.abs(arr[0]);
   }

    arr.forEach((key, i) => {
      let keyLevel = arr.at(-(i+1)) ?? -1;
      if (min !== null) {
        keyLevel = keyLevel + min;
      }
      let value = layerMap.get(key) || [];
      let d = keyLevel === maxLevel ? size - 1 : keyLevel;
      const x = offsetX - d * ((size > 3 ? nodeWidth/1.5 : nodeWidth) + ranksep);
      const sortNodes = value.sort((x: any, y: any) => y.order - x.order);
      /** 此处需要判断是否在同一个combo中。 */
      const comboMap: Map<string, Node[]> = new Map();
      sortNodes.forEach((e: any) => {
        let comboId = e.comboId;
       let v = comboMap.get(comboId);
       if (!v) {
        comboMap.set(comboId, [e]);
       } else {
        v.push(e);
        comboMap.set(comboId, v);
       }
      })
      const y = centerLine + keyHr[key] / 2 + Array.from(comboMap.keys()).length / 2 * comboSpace;
      let preY = y;
      comboMap.forEach((value, key) => {
        value.forEach((e: any, index) => {
          const { size } = e;
          const margin = index === 0 ? 0 : nodesep;
          preY = preY - size[1] - margin;
          if ((value.length - 1) * size[1] == preY) { //解决整个页面刚好都是节点的异常
            preY = preY - 80;
          } else {
            preY = (value.length == 1 && preY === 0) ? 60 : preY;//解决==0时combo显示不正确问题,http://test.csylcloud.com:8380/browse/WZL-970
          }
          e.x = x;
          e.y = preY;
        });
        preY = preY - comboSpace;
      })
    });
    if (self.onLayoutEnd) self.onLayoutEnd();
  }

  public getType() {
    return 'lineageLayout';
  }
}

G6.registerLayout('lineageLayout', CustomDagreLayout);