关于AntV-G6 + VUE实现股权穿图

404 阅读2分钟
const COLLAPSE_ICON = function COLLAPSE_ICON(x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r],
  ];
};
const EXPAND_ICON = function EXPAND_ICON(x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r],
    ['M', x, y - 2 * r + 2],
    ['L', x, y - 2],
  ];
};
const getIcon = function getIcon(cfg) {
  if (cfg.hasChildren && cfg.collapsed === undefined) {
    return EXPAND_ICON
  } else {
    return cfg.collapsed ? EXPAND_ICON : COLLAPSE_ICON
  }
};

drawGqTree(data) {
  G6.registerNode('icon-node', {
      options: {
        size: [60, 20],
        stroke: '#91d5ff',
        fill: '#fff',
      },
      draw(cfg, group) {
        const styles = this.getShapeStyle(cfg);
        const {labelCfg = {}} = cfg;

        const w = styles.width;
        const h = styles.height;

        const keyShape = group.addShape('rect', {
          attrs: {
            ...styles,
          },
        });
        if (cfg.hasChildren) {
          group.addShape('marker', {
            attrs: {
              x: 66,
              y: 6,
              r: 6,
              stroke: '#128BED',
              fill: '#fff',
              cursor: 'pointer',
              symbol: getIcon(cfg),
              click: function (params) {
                // console.log(params)
              }
            },
            name: 'collapse-icon'
          })
        }
        if (cfg.name) {
          /** 判断文字位置,折行等 **/
          let textY;
          let content = cfg.name;
          if (cfg.name.length < 8) {
            textY = 6
          } else {
            textY = 32 - h / 2
          }

          let UpXy = {
            y: 32,
          };
          let DownXy = {
            y: -24,
          };
          let Y;
          if (cfg.showDirection === "in") {
            Y = UpXy.y
          } else if (cfg.showDirection === "out") {
            Y = DownXy.y
          }
          if (cfg.name.length > 8 && cfg.name.length <= 16) {
            content = content.slice(0, 8) + '\n' + content.slice(8)
          } else if (cfg.name.length > 16) {
            content = content.slice(0, 8) + '\n' + content.slice(8, 16) + '...'
          }
          /**添加节点名称**/
          group.addShape('text', {
            attrs: {
              ...labelCfg.style,
              text: content,
              textAlign: 'center',
              x: 60 - w / 2,
              y: textY,
            },
          });
          /**持股比例信息**/
          group.addShape('text', {
            attrs: {
              fill: '#128BED',
              fontSize: 10,
              text: cfg.percent,
              textAlign: 'center',
              x: 32,
              y: Y,
            },
          });
          // /**持股比例信息文字**/
          // group.addShape('text', {
          //   attrs: {
          //     fill: '#128BED',
          //     fontSize: 10,
          //     text: cfg.leftText,
          //     textAlign: 'center',
          //     x: -28,
          //     y: Y,
          //   },
          // });
        }

        return keyShape;
      },
      update: undefined,
    },
    'rect',
  );
  G6.registerEdge('flow-line', {
    draw(cfg, group) {
      const startPoint = cfg.startPoint;
      const endPoint = cfg.endPoint;
      const {style} = cfg;
      let isEnt;
      if (cfg.targetNode._cfg.model.showDirection === "out") {
      //out代表对外投资
        isEnt = true;
        let shape = group.addShape('path', {
          attrs: {
            stroke: style.stroke,
            endArrow: style.endArrow ,
            path: [
              ['M', startPoint.x, startPoint.y],
              ['L', startPoint.x, (startPoint.y + endPoint.y) / 2],
              ['L', endPoint.x, (startPoint.y + endPoint.y) / 2],
              ['L', endPoint.x, endPoint.y - 2],
            ],
          },
        });
        return shape;
      } else {
        isEnt = false
        let shape = group.addShape('path', {
          attrs: {
            stroke: style.stroke,
            endArrow: style.reverseArrow,
            path: [
              ['M', startPoint.x, startPoint.y],
              ['L', startPoint.x, (startPoint.y + endPoint.y) / 2],
              ['L', endPoint.x, (startPoint.y + endPoint.y) / 2],
              ['L', endPoint.x, endPoint.y + 28],
            ],
          },
        });
        return shape;
      }

    },
  });
  const defaultStateStyles = {
    hover: {
      stroke: '#3d8be6',
      lineWidth: 1.6,
    },
  };

  const defaultNodeStyle = {
    fill: '#fff',
    stroke: '#3d8be6',
    radius: 2,
    lineWidth: 1,
  };

  const defaultEdgeStyle = {
    stroke: '#d6d6d6',
    endArrow: {
      path: "M 0,0 L 8, 3 L 8,0 L 8, -3 Z",
      fill: '#3d8be6',
      stroke: '#3d8be6',
      d:-20,
    },
    reverseArrow: {
      path: 'M 8,0 L 0, 3 L 0,0 L 0, -3 Z',
      fill: '#3d8be6',
      stroke: '#3d8be6',
      d: -20,
    }
  };

  const defaultLayout = {
    type: 'compactBox',
    direction: 'V', //V 垂直分布  H 水平分布
    getId: function getId(d) {
      return d.id;
    },
    getHeight: function getHeight() {
      return 16;
    },
    getWidth: function getWidth() {
      return 16;
    },
    getVGap: function getVGap() {
      return 50;
    },
    getHGap: function getHGap() {
      return 70;
    },
    getSide: (d) => {
      /**上下布局,此处判断在节点上还是下**/
      if (d.data.showDirection === "out") {
        return 'right'
      } else {
        return 'left'
      }
    }
  };

  const defaultLabelCfg = {
    style: {
      fill: '#000',
      fontSize: 11,
    },
  };

  const container = document.getElementById('container');
  const width = container.scrollWidth;
  const height =  document.body.clientHeight -240;
  const graph = new G6.TreeGraph({
    container: 'container',
    width,
    height,
    linkCenter: true,
    modes: {
      default: ['drag-canvas', 'zoom-canvas'],
    },
    defaultNode: {
      type: 'icon-node',
      size: [120, 40],
      style: defaultNodeStyle,
      labelCfg: defaultLabelCfg,
    },
    defaultEdge: {
      type: 'flow-line',
      style: defaultEdgeStyle,
    },
    nodeStateStyles: defaultStateStyles,
    edgeStateStyles: defaultStateStyles,
    layout: defaultLayout,
  });

  graph.data(data);
  graph.render();
  graph.fitCenter();

  graph.on('node:mouseenter', (evt) => {
    // console.log(evt);
  });
  //
  graph.on('node:mouseleave', (evt) => {
    // const {item} = evt;
    // graph.setItemState(item, 'hover', false);
  });

  graph.on('node:click', async (evt) => {
    let {item, target} = evt;
    let targetType = target.get('type');
    const name = target.get('name');
    const model = item.getModel();
     if(targetType === 'marker'){
       if (target.attr('symbol') === EXPAND_ICON) { //判断点击为'+'号
         if (name === 'collapse-icon') {
           if (!model.children) {
             model.children = [];
           }
           let params = {
             type: model.showDirection,
             name: model.name
           };
           let result = await PlantformService.getInvestRelationSearch(params);
           if (result.message.code === 0) {
             if (result.data && result.data.children) {
               result.data.children.forEach((item, index) => {
                 //beInvestFlag  type为in时判断 beInvestFlag 是否有子节点
                 if (model.showDirection === 'in') {
                   if (item.properties.beInvestFlag === "true") {
                     item.hasChildren = true
                   } else {
                     item.hasChildren = false
                   }
                 } else if (model.showDirection === 'out') {
                   if (item.properties.investFlag === "true") {
                     item.hasChildren = true
                   } else {
                     item.hasChildren = false
                   }
                 }
                 item.name = item.properties.name;
                 item.oldId = item.id; //保留原本id,以防查询使用
                 let date =  new Date().getTime();
                 const reserveId = `${date}${Math.random()}`
                 item.id = reserveId
                 item.percent = accMul(item.properties.stockPercent.substring(0, 4),100) + "%";
                 // item.percent = (item.properties.stockPercent.substring(0, 4)) * 100 + "%";
                 item.showDirection = params.type;
                //  item.leftText = '控股'
               });
               model.children = result.data.children;
             }
           }
           const icon = item.get('group').find(element => element.get('name') === 'collapse-icon');
           icon.attr('symbol', COLLAPSE_ICON);
           model.collapsed = false;
           graph.focusItem(model.id);
           graph.updateChild(model, model.id);
         }
       } else if (target.attr('symbol') === COLLAPSE_ICON) {
         model.children = [];
         const icon = item.get('group').find(element => element.get('name') === 'collapse-icon');
         icon.attr('symbol', EXPAND_ICON);
         model.collapsed = true;
         graph.focusItem(model.id);
         graph.updateChild(model, model.id);
       }
     }else if (targetType === 'text'){ // 点击节点
         alert(model.name)
     }

  });

  if (typeof window !== 'undefined')
    window.onresize = () => {
      if (!graph || graph.get('destroyed')) return;
      if (!container || !container.scrollWidth || !container.scrollHeight) return;
      graph.changeSize(container.scrollWidth, container.scrollHeight);
    };

}