<template>
  <div>
    <div ref="g6Dom" :style="{ height: height, width: width }"></div>
    <button @click="actions['Enable/Disable Node States'].Breathing()">
      Breathing()
    </button>
    <button @click="actions['Enable/Disable Node States'].Scaling()">
      Scaling()
    </button>

    <button @click="actions['Enable/Disable Edge States'].Growing()">
      Growing()
    </button>
    <button @click="actions['Enable/Disable Edge States'].Running()">
      Running()
    </button>
  </div>
</template>

<script lang="ts" setup>
import { nextTick, watch, onMounted, onBeforeUnmount, ref } from 'vue';
import { Graph, extend, Extensions } from '@antv/g6';

const props = defineProps({
  /**
   * 图表主题
   *
   * 'dark' | 'light'
   */
  theme: {
    type: String,
    default: 'light', // 'dark' | 'light'
  },
  /**宽度，默认100% */
  width: {
    type: String,
    default: '100%',
  },
  /**高度 */
  height: {
    type: String,
    default: '500px',
  },
});

const g6Dom = ref<HTMLElement | undefined>(undefined);

const ExtGraph = extend(Graph, {
  // layouts: {
  //   dagre: Extensions.DagreLayout,
  // },
  edges: {
    'polyline-edge': Extensions.PolylineEdge,
    'custom-edge': Extensions.CubicEdge,
  },
});

const data = {
  nodes: [
    {
      id: '0',
      data: {
        label: 'A0',
        x: 110,
        y: 110,
      },
    },
    // B
    {
      id: '1',
      data: {
        label: 'B1',
        parentId: 'B',
        x: 110,
        y: 350,
      },
    },
    {
      id: '2',
      data: {
        label: 'B2',
        parentId: 'B',
        x: 220,
        y: 350,
      },
    },
    {
      id: '3',
      data: {
        label: 'B3',
        parentId: 'A',
        x: 360,
        y: 350,
      },
    },
    // C
    {
      id: '4',
      data: {
        label: 'C1',
        parentId: 'C',
        x: 360,
        y: 150,
      },
    },
    {
      id: '5',
      data: {
        label: 'C2',
        parentId: 'C',
        x: 460,
        y: 150,
      },
    },
  ],
  edges: [
    {
      id: 'edge-102',
      source: '0',
      target: '1',
      data: {
        type: 'custom-edge',
        animates: {
          update: [
            {
              // 在 selected 和 active 状态变化导致的 haloShape opacity 变化时，使 opacity 带动画地更新
              fields: ['opacity'],
              shapeId: 'haloShape',
              states: ['selected', 'active'],
              duration: 500,
            },
          ],
        },
      },
    },
    {
      id: 'edge-161',
      source: '0',
      target: '2',
      data: {},
    },
    {
      id: 'edge-253',
      source: '0',
      target: 'A',
      data: {
        keyShape: {
          endArrow: true,
        },
        labelShape: {
          text: 'asdf-arrow',
        },
      },
    },
    {
      id: 'edge-237',
      source: '1',
      target: '4',
      data: {
        type: 'polyline-edge',
        keyShape: {
          endArrow: true,
          routeCfg: {
            /**
             * 目前支持正交路由 'orth' 和地铁路由 'er'
             */
            // name: 'er',
            /**
             * 是否开启自动避障，默认为 false
             * Whether to enable automatic obstacle avoidance, default is false
             */
            enableObstacleAvoidance: true,
          },
          /**
           * 拐弯处的圆角弧度，默认为直角，值为 0
           * The radius of the corner rounding, defaults to a right angle
           */
          // radius: 20,
          /**
           * 拐弯处距离节点最小距离, 默认为 2
           * Minimum distance from the node at the corner, default is 5.
           */
          // offset: 0,
          /**
           * 控制点数组，不指定时根据 A* 算法自动生成折线。若指定了，则按照 controlPoints 指定的位置进行弯折
           * An array of control points that, when not specified, automatically generates the bends according to the A* algorithm. If specified, bends are made at the position specified by controlPoints.
           */
          // controlPoints: [],
        },
      },
    },
    {
      id: 'edge-133',
      source: '2',
      target: '4',
      data: {
        type: 'polyline-edge',
        keyShape: {
          /**
           * 拐弯处的圆角弧度，默认为直角
           */
          radius: 20,
          /**
           * 拐弯处距离节点最小距离, 默认为 5
           */
          // offset: 0,
          /**
           * 控制点数组，不指定时根据 A* 算法自动生成折线。若指定了，则按照 controlPoints 指定的位置进行弯折
           */
          controlPoints: [
            { x: 220, y: 220 },
            { x: 300, y: 130 },
          ],
        },
      },
    },
    {
      id: 'edge-320',
      source: '2',
      target: '5',
      data: {
        keyShape: {
          endArrow: true,
        },
        labelShape: {
          text: 'edge-arrow',
        },
      },
    },
    {
      id: 'edge-355',
      source: '3',
      target: '4',
      data: {
        keyShape: {
          endArrow: true,
        },
        labelShape: {
          text: 'asdf-arrow',
        },
      },
    },
  ],
  combos: [
    {
      id: 'A',
      data: {
        text: 'combo A',
      },
    },
    {
      id: 'B',
      data: {
        label: 'combo B',
      },
    },
    {
      id: 'C',
      data: {
        label: 'combo C',
      },
    },
  ],
};
let graph: any = null;
/**初始化渲染图表 */
function initChart() {
  if (!g6Dom.value) return;
  graph = new ExtGraph({
    container: g6Dom.value,
    height: 500,
    plugins: [
      {
        // lod-controller will be automatically assigned to graph with `disableLod: false` to graph if it is not configured as following
        type: 'lod-controller',
        disableLod: true,
      },
    ],
    modes: {
      default: [
        {
          type: 'drag-node',
          enableTransient: false,
          updateComboStructure: false,
        },
        {
          type: 'click-select',
          itemTypes: ['node', 'edge', 'combo'],
        },
        {
          type: 'drag-combo',
          enableTransient: true,
          updateComboStructure: true,
        },
        // 'drag-combo',
        'drag-canvas',
        // 'click-select',
        'zoom-canvas',
      ],
    },

    theme: {
      type: 'spec',
      base: 'light',
      specification: {
        node: {
          dataTypeField: 'parentId',
        },
      },
    },
    node: model => {
      const { id, data } = model;
      return {
        id,
        data: {
          ...data,
          type: 'rect-node',
          keyShape: {
            width: 60,
            height: 30,
            radius: 8,
          },
          labelShape: {
            position: 'center',
            text: data.label,
          },
          animates: {
            update: [
              {
                fields: ['opacity'],
                shapeId: 'haloShape',
                states: ['breathing'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
              {
                fields: ['lineWidth'],
                shapeId: 'keyShape',
                states: ['breathing'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
              {
                fields: ['height'],
                shapeId: 'keyShape',
                states: ['scaling'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
            ],
          },
        },
      };
    },
    edge: {
      type: 'custom-edge',
      animates: {
        update: [
          {
            fields: ['lineDash'],
            shapeId: 'keyShape',
            states: ['growing', 'running'],
            iterations: Infinity,
            duration: 2000,
          },
          {
            fields: ['offsetDistance'],
            shapeId: 'buShape',
            states: ['circleRunning'],
            iterations: Infinity,
            duration: 2000,
          },
        ],
      },
    },
    combo: model => {
      const { id, data } = model;
      return {
        id,
        data: {
          ...data,
          type: 'rect-combo',
          keyShape: {
            opacity: 0.8,
            padding: [20, 20, 20, 20],
            radius: 8,
          },
          labelShape: {
            text: data.label,
            offsetY: 8,
          },
          labelBackgroundShape: {},
          animates: {
            update: [
              {
                fields: ['width', 'height', 'x', 'y'],
                shapeId: 'keyShape',
              },
            ],
          },
        },
      };
    },
    nodeState: {
      breathing: {
        haloShape: {
          opacity: 0.25,
          lineWidth: 20,
          visible: true,
        },
        keyShape: {
          stroke: '#000',
          lineWidth: 4,
        },
      },
      scaling: {
        keyShape: {
          r: 24,
          width: 48,
          height: 48,
        },
      },
    },
    edgeState: {
      growing: {
        keyShape: {
          lineWidth: 2,
          lineDash: ['100%', 0],
        },
      },
      running: {
        keyShape: {
          lineWidth: 2,
          lineDash: [2, 2],
          //  TODO: lineDashOffset
        },
      },
    },
    data,
  });
}

const actions = {
  'Enable/Disable Node States': {
    Breathing: () => {
      graph.getAllNodesData().forEach(node => {
        if (graph.getItemState(node.id, 'breathing')) {
          graph.setItemState(node.id, 'breathing', false);
        } else {
          graph.setItemState(node.id, 'scaling', false);
          graph.setItemState(node.id, 'breathing', true);
        }
      });
    },
    Scaling: () => {
      graph.getAllNodesData().forEach(node => {
        if (graph.getItemState(node.id, 'scaling')) {
          graph.setItemState(node.id, 'scaling', false);
        } else {
          graph.setItemState(node.id, 'breathing', false);
          graph.setItemState(node.id, 'scaling', true);
        }
      });
    },
  },
  'Enable/Disable Edge States': {
    Growing: () => {
      graph.getAllEdgesData().forEach(edge => {
        if (graph.getItemState(edge.id, 'growing')) {
          graph.setItemState(edge.id, 'growing', false);
        } else {
          graph.setItemState(edge.id, 'running', false);
          graph.setItemState(edge.id, 'growing', true);
        }
      });
    },
    Running: () => {
      graph.getAllEdgesData().forEach(edge => {
        if (graph.getItemState(edge.id, 'running')) {
          graph.setItemState(edge.id, 'running', false);
        } else {
          graph.setItemState(edge.id, 'growing', false);
          graph.setItemState(edge.id, 'running', true);
        }
      });
    },
  },
};

watch(
  () => props.option,
  val => {
    // if (val) {
    //   nextTick(() => {
    //     initChart();
    //   });
    // }
  }
);

onMounted(() => {
  nextTick(() => {
    initChart();
  });
});

onBeforeUnmount(() => {});
</script>

<style lang="less" scoped></style>
