<template>
  <div style="background:#f1f2f3" id="full">
    <img style="width: 25px; height: 25px;float: right" v-if="!fullscreen" @click="enterFullscreen" src="@/assets/icons/amplify.svg" title="全屏">
    <img style="width: 25px; height: 25px;float: right" @click="backFullscreen" v-if="fullscreen" src="@/assets/icons/reduce.svg" title="还原">
    <div id="container"></div>
  </div>
</template>

<script>
import G6 from '@antv/g6';
import axios from 'axios'
let graph;
const fittingString = (str, maxWidth, fontSize) => {
  const ellipsis = "...";
  const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
  let currentWidth = 0;
  let res = str;
  const pattern = new RegExp("[\u4E00-\u9FA5]+"); // distinguish the Chinese charactors and letters
  str.split("").forEach((letter, i) => {
    if (currentWidth > maxWidth - ellipsisLength) return;
    if (pattern.test(letter)) {
      // Chinese charactors
      currentWidth += fontSize;
    } else {
      // get the width of single letter according to the fontSize
      currentWidth += G6.Util.getLetterWidth(letter, fontSize);
    }
    if (currentWidth > maxWidth - ellipsisLength) {
      res = `${str.substr(0, i)}${ellipsis}`;
    }
  });
  return res;
};
const ERROR_COLOR = 'red';
const getNodeConfig = (node) => {
  if (node.nodeUrl) {
    return {
      basicColor: ERROR_COLOR,
      fontColor: '#FFF',
      borderColor: ERROR_COLOR,
      bgColor: '#ff5722',
    };
  }
  let config = {
    basicColor: '#fff',
    fontColor: '#333',
    borderColor: '#fff',
    bgColor: '#fff',
  };
  switch (node.type) {
    case 'root': {
      config = {
        basicColor: '#E3E6E8',
        fontColor: 'rgba(0,0,0,0.85)',
        borderColor: '#E3E6E8',
        bgColor: '#5b8ff9',
      };
      break;
    }
    default:
      break;
  }
  return config;
};

const COLLAPSE_ICON = function COLLAPSE_ICON(x, y, r) {
  return [
    ['M', x - r, y],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x - r + 4, y],
    ['L', x - r + 2 * r - 4, y],
  ];
};
const EXPAND_ICON = function EXPAND_ICON(x, y, r) {
  return [
    ['M', x - r, y],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x - r + 4, y],
    ['L', x - r + 2 * r - 4, y],
    ['M', x - r + r, y - r + 4],
    ['L', x, y + r - 4],
  ];
};
const nodeBasicMethod = {
  createNodeBox: (group, config, w, h, isRoot) => {
    /* 最外面的大矩形 */
    const container = group.addShape('rect', {
      attrs: {
        x: 0,
        y: 0,
        width: w,
        height: h,
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'big-rect-shape',
    });
    if (!isRoot) {
      /* 左边的小圆点 */
      group.addShape('circle', {
        attrs: {
          x: 3,
          y: h / 2,
          r: 0,
          fill: config.basicColor,
        },
        // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
        name: 'left-dot-shape',
      });
    }
    /* 矩形 */
    group.addShape('rect', {
      attrs: {
        x: 3,
        y: 0,
        width: w - 19,
        height: h,
        fill: config.bgColor,
        stroke: config.borderColor,
        radius: 2,
        cursor: 'pointer',
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'rect-shape',
    });

    /* 左边的粗线 */
    group.addShape('rect', {
      attrs: {
        x: 3,
        y: 0,
        width: 3,
        height: h,
        fill: config.basicColor,
        radius: 1.5,
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'left-border-shape',
    });
    return container;
  },
  /* 生成树上的 marker */
  createNodeMarker: (group, collapsed, x, y) => {
    group.addShape('circle', {
      attrs: {
        x,
        y,
        r: 13,
        fill: 'rgba(47, 84, 235, 0.05)',
        opacity: 0,
        zIndex: -2,
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'collapse-icon-bg',
    });
    group.addShape('marker', {
      attrs: {
        x,
        y,
        r: 7,
        symbol: collapsed ? EXPAND_ICON : COLLAPSE_ICON,
        stroke: 'rgba(0,0,0,0.25)',
        fill: 'rgba(0,0,0,0)',
        lineWidth: 1,
        cursor: 'pointer',
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'collapse-icon',
    });
  },
  afterDraw: (cfg, group) => {
    /* 操作 marker 的背景色显示隐藏 */
    const icon = group.find((element) => element.get('id') === 'collapse-icon');
    if (icon) {
      const bg = group.find((element) => element.get('id') === 'collapse-icon-bg');
      icon.on('mouseenter', () => {
        bg.attr('opacity', 1);
        graph.get('canvas').draw();
      });
      icon.on('mouseleave', () => {
        bg.attr('opacity', 0);
        graph.get('canvas').draw();
      });
    }
    /* ip 显示 */
    const ipBox = group.find((element) => element.get('id') === 'ip-box');
    if (ipBox) {
      /* ip 复制的几个元素 */
      const ipLine = group.find((element) => element.get('id') === 'ip-cp-line');
      const ipBG = group.find((element) => element.get('id') === 'ip-cp-bg');
      const ipIcon = group.find((element) => element.get('id') === 'ip-cp-icon');
      const ipCPBox = group.find((element) => element.get('id') === 'ip-cp-box');

      const onMouseEnter = () => {
        ipLine.attr('opacity', 1);
        ipBG.attr('opacity', 1);
        ipIcon.attr('opacity', 1);
        graph.get('canvas').draw();
      };
      const onMouseLeave = () => {
        ipLine.attr('opacity', 0);
        ipBG.attr('opacity', 0);
        ipIcon.attr('opacity', 0);
        graph.get('canvas').draw();
      };
      ipBox.on('mouseenter', () => {
        onMouseEnter();
      });
      ipBox.on('mouseleave', () => {
        onMouseLeave();
      });
      ipCPBox.on('mouseenter', () => {
        onMouseEnter();
      });
      ipCPBox.on('mouseleave', () => {
        onMouseLeave();
      });
      ipCPBox.on('click', () => { });
    }
  },
  setState: (name, value, item) => {
    const hasOpacityClass = [
      'ip-cp-line',
      'ip-cp-bg',
      'ip-cp-icon',
      'ip-cp-box',
      'ip-box',
      'collapse-icon-bg',
    ];
    const group = item.getContainer();
    const childrens = group.get('children');
    graph.setAutoPaint(false);
    if (name === 'emptiness') {
      if (value) {
        childrens.forEach((shape) => {
          if (hasOpacityClass.indexOf(shape.get('id')) > -1) {
            return;
          }
          shape.attr('opacity', 0.4);
        });
      } else {
        childrens.forEach((shape) => {
          if (hasOpacityClass.indexOf(shape.get('id')) > -1) {
            return;
          }
          shape.attr('opacity', 1);
        });
      }
    }
    graph.setAutoPaint(true);
  },
};

G6.registerNode('card-node', {
  options: {
    style: {
      stroke: '#ccc',
    },
  },
  draw: (cfg, group) => {

    const config = getNodeConfig(cfg);
    const isRoot = cfg.dataType === 'root';
    const nodeUrl = cfg.nodeUrl;
    /* the biggest rect */
    const container = nodeBasicMethod.createNodeBox(group, config, 243, 64 + Number(25*cfg.infoSize) , isRoot);

    if (cfg.dataType !== 'root') {
      /* the type text */
      group.addShape('text', {
        attrs: {
          text: cfg.dataType,
          x: 3,
          y: -10,
          fontSize: 12,
          textAlign: 'left',
          textBaseline: 'middle',
          fill: 'rgba(0,0,0,0.65)',
        },
        // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
        name: 'type-text-shape',
      });
    }

    /* name */
    group.addShape('text', {
      attrs: {
        text: cfg.id,
        x: 19,
        y: 19,
        fontSize: 14,
        fontWeight: 700,
        textAlign: 'left',
        textBaseline: 'middle',
        fill: config.fontColor,
        cursor: 'pointer',
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'name-text-shape',
    });

    /* the description text */
    group.addShape('text', {
      attrs: {
        text: fittingString(cfg.value, 243 - 50, 14),
        x: 19,
        y: 45,
        fontSize: 14,
        textAlign: 'left',
        textBaseline: 'middle',
        fill: config.fontColor,
        cursor: 'pointer',
      },
      // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
      name: 'bottom-text-shape',
    });
    if (cfg.infoSize > 0) {
      Object.keys(cfg.info).forEach((key,index) => {
        console.log(key, cfg.info[key],index);
        group.addShape('text', {
          attrs: {
            text: fittingString(String(cfg.info[key]), 243 - 50, 14),
            x: 19,
            y: 65 + (25*index) ,
            fontSize: 12,
            textAlign: 'left',
            textBaseline: 'middle',
            fill: config.fontColor,
            cursor: 'pointer',
          },
          // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
          name: 'bottom-text-shape',
        });
      });
    }
    if (nodeUrl) {
      group.addShape('text', {
        attrs: {
          x: 191,
          y: 62,
          text: '⇢',
          fill: '#fff',
          fontSize: 18,
        },
        // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
        name: 'error-text-shape',
      });
    }

    const hasChildren = cfg.children && cfg.children.length > 0;
    if (hasChildren) {
      nodeBasicMethod.createNodeMarker(group, cfg.collapsed, 236, 32);
    }
    return container;
  },
  afterDraw: nodeBasicMethod.afterDraw,
  setState: nodeBasicMethod.setState,
});
export default {
  props:['id'],
  data () {
    return {
      fullscreen:false
    }
  },
  mounted () {
    // this.getData()
    document.addEventListener('fullscreenchange', this.handleFullscreenChange);
    document.addEventListener('mozfullscreenchange', this.handleFullscreenChange);
    document.addEventListener('webkitfullscreenchange', this.handleFullscreenChange);
    document.addEventListener('MSFullscreenChange',this.handleFullscreenChange)
  },
  methods:{
    createMenu (array) {
      var that = this
      let arr = []
      const HASLINKS = ['有效线索数','有效项目数']
      function convertToElementTree(node) {
        // 新节点
        var elNode = {
          id: node['name'],
          nodeid:node['id'],
          info:node['info']?node['info']:{},
          infoSize:node['infoSize']?node['infoSize']:1,
          value:node['labor']?node['labor'] !== node['name']?node['labor']:'-':'-',
          children: [],
          nodeUrl:HASLINKS.includes(node['name'])?'123':null
        }

        if (node.children && node.children.length > 0) {
          // 如果存在子节点
          for (var index = 0; index < node.children.length; index++) {
          // 遍历子节点, 把每个子节点看做一颗独立的树, 传入递归构造子树, 并把结果放回到新node的children中
          elNode.children.push(convertToElementTree(node.children[index]));
          }
        }
        return elNode;
      }
      array.forEach((element) => {
        arr.push(convertToElementTree(element))
      });
      return arr
    },
    async getData () {
      const res = await this.$api.requested({
        "id": 20230625101004,
        "content": {
          "hrid": this.id
        }
      })
      const container = document.getElementById('container');
      const width = container.scrollWidth;
      const height = container.scrollHeight || 500;
      const graph = new G6.TreeGraph({
        container: 'container',
        width,
        height,
        linkCenter: true,
        fitCenter: true,
        modes: {
          default: ['drag-canvas','zoom-canvas','collapse-expand','drag-node', 'lasso-select'],
        },
        defaultNode: {
          /* node type, the priority is lower than the type in the node data */
          type: 'card-node',
        },
        defaultEdge: {
          type: 'cubic-horizontal',
        },
        layout: {
          type: 'dendrogram',
          direction: 'RL',
          nodeSep: 100,
          rankSep: 250,
          radial: true,
        },
      });

      graph.node(function (node) {
        return {
          label: node.id,
        };
      });

      graph.data(this.createMenu([res.data])[0]);
      graph.render();
      graph.fitView();
      graph.on('node:click', evt => {
        const item = evt.item;
        console.log(item)
      })
      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);
        };
    },
    enterFullscreen () {
      /* 获取(<html>)元素以全屏显示页面 */
      const full = document.getElementById('full')
      if (full.RequestFullScreen) {
        full.RequestFullScreen()
        //兼容Firefox
      } else if (full.mozRequestFullScreen) {
        full.mozRequestFullScreen()
        //兼容Chrome, Safari and Opera等
      } else if (full.webkitRequestFullScreen) {
        full.webkitRequestFullScreen()
        //兼容IE/Edge
      } else if (full.msRequestFullscreen) {
        full.msRequestFullscreen()
      }
    },
    handleFullscreenChange () {
      if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
        // 全屏模式激活

        console.log('全屏模式已激活');
        this.fullscreen = true
      } else {
        // 全屏模式退出
        this.fullscreen = false
        console.log('全屏模式已退出');
      }
    },
    /*全屏还原*/
    backFullscreen(){
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.webkitCancelFullScreen) {
        document.webkitCancelFullScreen();
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
      } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
      }
    },
  },
}

</script>
<style>
#container{
  height: 100vh;
  width: 100vw;
}
</style>
