<template>
  <div :id="id" :style="{ width, height }"></div>
</template>

<script>

import { getDataType } from '@/common/utils/tool.js';

const unwarp = (obj) => obj && (obj.__v_raw || obj.valueOf() || obj);

export default {
  name: "MetaLineBarChart",
  data() {
    return {
      zoomLength: 6,  // 默认显示几个柱子
      chart: null,
      echarts: window.echarts
    };
  },
  props: {
    id: {
      type: String,
      default: () => {
        return "lineBar_" + Date.now() + Math.random().toString(36).substr(2);
      },
    },
    width: {
      type: String,
      default: "100%",
    },
    height: {
      type: String,
      default: "100%",
    },
    // 图表数据
    series: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 图表方向 竖直：vertical 水平：horizontal
    orient: {
      type: String,
      default: "vertical",
    },
    // x轴的自定义配置
    xConfig: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // x轴label显示的内容
    xLabel: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // y轴的自定义配置
    yConfig: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // y轴label显示的内容
    yLabel: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 类目轴的数据
    axisData: {
      type: Array,
      default: () => {
        return null;
      },
    },
    // 是否显示图例
    showLegend: {
      type: Boolean,
      default: true,
    },
    // 图例位置
    positionLegend: {
      type: String,
      default: "top",
    },
    // 图例数据
    dataLegend: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 网格padding
    grid: {
      type: Object,
      default: () => {
        return {};
      },
    },
    // 是否支持缩放
    canZoom: {
      type: Boolean,
      default: true,
    },
    // 图表缩放配置项 二维数组,数组值代表控制的Axis 例如：[[0,1]]，默认缩放配置为 []，即没有缩放功能
    zoomIndex: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 缩放类型 默认 inside
    zoomType: {
      type: String,
      default: "inside",
    },
    // 缩放范围 默认显示0%-30%区域的数据
    zoomRange: {
      type: Object,
      default: () => {
        return {
          start: 0,
          end: 30
        }
      }
    },
    // 提示框
    tooltip: {
      type: Object,
      default: () => {
        return {};
      },
    },
    // 是否显示分割线 x: x轴显示  y: y轴显示 默认y
    splitLine: {
      type: String,
      default: "y",
    },
  },
  watch: {
    series: {
      deep: true,
      handler() {
        if (this.chart) {
          unwarp(this.chart).setOption({}, true);
          this.renderChart();
        } else {
          this.initChart();
        }
      },
    },
  },
  mounted() {
    this.addResizeEvent();
    this.initChart();
  },
  beforeUnmount() {
    this.removeResizeEvent();
    this.chart.getZr().off("click");
    this.desposeChart();
  },
  computed: {
    getZoomRange() {
      return {
        start: 0,
        end: this.axisData?.length >= this.zoomLength ? (this.zoomLength / this.axisData.length * 100) : 100
      }
    },
    getAxisData() {
      return this.axisData;
    },
    // 图表两边留白处理
    getBroundGap() {
      let num = 0;
      this.series.forEach((i) => {
        if (i.type === "line") num++;
      });

      // 全都是折线图，两边不留白
      if (num === this.series.length) {
        return { boundaryGap: false };
      }
      return { boundaryGap: [0, 0.1] };
    },
    getX() {
      // 不同的方向，渲染不同的type
      let type = "value";  // 默认竖直方向，x轴是数值轴
      let data = {};
      if (this.orient === "vertical") { // 水平方向，x轴是类目轴
        type = "category";
        data = { data: this.getAxisData };
      }

      const base = {
        type,
        axisLine: {
          show: true,
        },
        splitLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        ...this.getBroundGap,
        ...data,
      };

      let xAxis = [], iConfig = {};

      this.xConfig.length
        ? this.xConfig.forEach((i, index) => {
          // 判断 i 的类型，字符串类型，则只传了轴name;对象类型，则传了自定义配置，需要扩展进配置项
          iConfig = getDataType(i).split(" ")[1].slice(0, -1) === 'String' ? { name: i } : i

            xAxis.push({
              ...base,
              axisLabel: {
                formatter: `{value}${this.xLabel[index] || ""}`,
                rotate: -60,
              },
              ...iConfig
            });
          })
        : (xAxis = [
            {
              ...base,
              axisLabel: {
                formatter: `{value}${this.xLabel[0] || ""}`,
                rotate: -60,
              },
              ...iConfig
            },
          ]);

      xAxis[0].splitLine = {
        show: this.splitLine === "x" ? true : false,
      };

      return { xAxis };
    },
    getY() {
      // 不同的方向，渲染不同的type
      let type = "value"; // 默认竖直方向，y轴是数值轴
      let data = {};
      if (this.orient === "horizontal") { // 水平方向，y轴是类目轴
        type = "category";
        data = { data: this.getAxisData };
      }

      const base = {
        type,
        axisLine: {
          show: true,
        },
        splitLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        alignTicks: true,
        ...this.getBroundGap,
        ...data,
      };

      let yAxis = [], iConfig = {};

      this.yConfig.length
        ? this.yConfig.forEach((i, index) => {
          // 判断 i 的类型，字符串类型，则只传了轴name;对象类型，则传了自定义配置，需要扩展进配置项
          iConfig = getDataType(i).split(" ")[1].slice(0, -1) === 'String' ? { name: i } : i
          
            yAxis.push({
              ...base,
              axisLabel: {
                formatter: `{value}${this.yLabel[index] || ""}`,
              },
              alignTicks: true,
              ...iConfig,
            });
          })
        : (yAxis = [
            {
              ...base,
              axisLabel: {
                formatter: `{value}${this.yLabel[0] || ""}`,
              },
              ...iConfig,
            },
          ]);

      yAxis[0].splitLine = {
        show: this.splitLine === "y" ? true : false,
      };

      return { yAxis };
    },
    // 网格配置
    getGrid() {
      return {
        grid: {
          top: "25%",
          left: "15%",
          right: "15%",
          ...this.grid,
        },
      };
    },
    // 图例
    getLegend() {
      return {
        legend: {
          show: this.showLegend,
          [this.positionLegend]: 0,
          data: this.dataLegend,
        },
      };
    },
    // 缩放配置
    getDataZoom() {
      return this.canZoom
        ? {
            dataZoom: this.getDataZoomConfig,
          }
        : {};
    },
    // 获取缩放配置
    getDataZoomConfig() {
      let zoomConfig = [];

      const axisIndex =
        this.orient === "horizontal"
          ? { yAxisIndex: this.zoomIndex }
          : { xAxisIndex: this.zoomIndex };
      const zoomRangeVal = (this.zoomRange.start == 0 && this.zoomRange.end == 30) ? this.getZoomRange : this.zoomRange;
      const base = {
        type: this.zoomType,
        throttle: 50,
        filterMode: "filter",
        orient: this.orient,
        ...zoomRangeVal,
        ...axisIndex,
      };

      // orient 为 horizontal 以 x 轴为基准缩放 ; orient 为 vertical 以 y 轴为基准缩放
      this.zoomIndex.forEach((item) => {
        // item:[0, 1]  表示这个 dataZoom 组件控制 第一个 和 第二个 xAxis
        zoomConfig.push({
          ...base,
          ...() => {
            return this.orient === "horizontal"
              ? { yAxisIndex: item }
              : { xAxisIndex: item };
          },
        });
      });

      return zoomConfig;
    },
    // 提示框自定义配置
    getTooltip() {
      return {
          confine: true,
          // alwaysShowContent: false,
          // position: ["25%", 10],
          className: 'echarts-tooltip',
          ...this.tooltip
        };
    },
  },
  methods: {
    desposeChart() {
      if (this.chart) this.chart.dispose();
    },
    //   初始化图表实例
    initChart() {
      const dom = document.getElementById(this.id);
      this.chart = this.echarts.init(dom);
      this.renderChart();
      this.clickChart();
    },
    renderChart() {
      unwarp(this.chart).setOption(this.getOptions(), true);
    },
    getOptions() {
      return {
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "shadow",
            crossStyle: {
              color: "#999",
            },
          },
          confine: true,
          ...this.getTooltip,
        },
        ...this.getX,
        ...this.getY,
        ...this.getGrid,
        ...this.getLegend,
        ...this.getDataZoom,
        series: this.series.map(i => {
          return {
            emphasis: {
              itemStyle: {
                shadowColor: 'rgba(0, 0, 0, .3)',
                shadowBlur: 10
              }
            },

            ...i
          }
        }),
      };
    },
    // 添加窗口大小监听方法
    addResizeEvent() {
      const _this = this;
      window.addEventListener("resize", _this.handleResizeChart);
    },

    // 适应图表大小
    handleResizeChart() {
      this.chart && this.chart.resize();
    },

    // 移除窗口大小监听方法
    removeResizeEvent() {
      const _this = this;
      window.removeEventListener("resize", _this.handleResizeChart);
    },
    // 绑定鼠标点击事件
    clickChart() {
      this.chart.on('legendselectchanged', () => {
        this.hideTooltip()
      })
      this.chart.getZr().on("click", (e) => {
        const position = [e.offsetX, e.offsetY];
        if (this.chart.containPixel("grid", position)) {
          let index = this.chart.convertFromPixel(
            { seriesIndex: 0 },
            position
          )[0];
          if (isNaN(index)) return
          this.$emit("handleZrClick", index);
        }
      });
    },
    // 隐藏tooltip
    hideTooltip() {
      this.chart.dispatchAction({
          type: 'hideTip'
      })
    },
    // 显示tooltip
    /**
     * seriesIndex  系列的 index，在 tooltip 的 trigger 为 axis 的时候可选。
     * dataIndex 数据项的 index，如果不指定也可以通过 name 属性根据名称指定数据项
     * position  本次显示 tooltip 的位置。只在本次 action 中生效 缺省则使用 option 中定义的 tooltip 位置
     */
    showTooltip(seriesIndex=0, dataIndex=0, position) {
      this.hideTooltip();

      setTimeout(() => {
        this.chart.dispatchAction({
          type: 'showTip',
          seriesIndex,
          dataIndex,
          position
        })
      }, 10)
    },
    // 设置高亮系列：
    handleHighlight(seriesIndex = 0, dataIndex=0) {
      this.downHighlight()
      this.chart.dispatchAction({
        type: 'highlight',
        seriesIndex,
        dataIndex,
      });
    },
    downHighlight() {
      this.chart.dispatchAction({
        type: 'downplay'
      })
    },
  },
};
</script>

<style lang="scss" scoped>
:deep(.echarts-tooltip) {
  z-index: 1 !important;
}
</style>