关联图定位计算

278 阅读1分钟
  • 实现一个关联图,关联图节点的位置需要通过js计算获取,再用线连接。

实现过程

1.使用平均计算

  1. 先将数据进行分层
  traverse(data, level, levelArr) {
    if (!levelArr[level]) {
      levelArr[level] = [data];
    } else {
      levelArr[level].push(data);
    }
    if (data.children) {
      ++level;
      data.children.forEach((item) => {
        this.traverse(item, level, levelArr);
      });
    }
    return levelArr;
  }
  1. 再通过分层计算x,y的位置
  processData(data, width, height) {
    let tData = this.traverse(data, 0, []);
    let dataSet = [];
    const wGap = Math.round(width / tData.levelArr.length + 1);
    tData.levelArr.forEach((nodes, setIndex) => {
      let hGap = Math.round(height / nodes.length);
      nodes.forEach((node, index) => {
        node.position = {
          x: wGap * setIndex + 10,
          y: hGap * index +10,
        };
      });
    });
  }
  1. 得到的结果: Frame 1
  • 缺点:不够直观,当数据量多的时候容易混乱。

2.通过父节点分块计算

  • 通过记录父节点的hGap,将父子关系想象成一个盒子,层层嵌套。
  • Frame 1
  1. 与第一种方法相同,先将数据分层。
  2. 通过父节点的hGap,再计算y。
   processData(data, width, height) {
    let tData = this.traverse(data, 0, []);
    let dataSet = [];
    const wGap = Math.round(width / tData.levelArr.length + 1);
    tData.levelArr.forEach((nodes, setIndex) => {
      let hGap = 0;
      if (setIndex === 0) {
        hGap = Math.round(height / nodes.length);
      }
      dataSet.push(...nodes);
      nodes.forEach((node, index) => {
        let pNode = null;
        let cIndex = 0;
        if (node.parentId !== -1) {
          pNode = dataSet.find((item) => item.id === node.parentId);
          hGap = pNode.position.hGap / pNode.children.length;
          cIndex = pNode.children.findIndex((item) => item.id === node.id);
        }
        node.position = {
          x: wGap * setIndex + 10,
          y: pNode ? pNode.position.y + hGap * cIndex : hGap * index,
          hGap: hGap,
        };
      });
    });
  }
  1. 计算结果
  • Frame 1 (1)
  • 缺点:因为容器是确定的height,当子节点过多时会被覆盖。

3.子节点累计成为块

  • 思路与2一致,将父子关系想象成盒子。与2不同的是,方法3是通过累计子节点的高度形成盒子的高度,而2是固定高度进行计算。
  1. 与第一种方法相同,先将数据分层,计算出x坐标。
  2. 递归数据,通过父子关系与子节点累计,计算出y坐标。
  calY(data, value) {
    data.position = { y: value };
    if (!data.children) {
      return { data, value };
    }
    data.children.forEach((item, index) => {
      if (index > 0) {
        value += 50;
      }
      const obj = this.calY(item, value);
      value = obj.value;
    });
    return { data, value };
  },
  1. 计算结果
  • Frame 1 (2)