<template>
  <div class="echart-render chart-box">
    <vue-charts
      :options="chartOption"
      :init-options="initOptions"
      autoresize
      v-if="chartOption"
      @click="chartClick"
      ref="vueChart"
    ></vue-charts>
    <p class="chart-none" v-else>暂无数据</p>
  </div>
</template>

<script>
import echarts from "echarts/lib/echarts";
import VueCharts from "@/plugins/VueCharts";

export default {
  name: "echart-render",
  components: { VueCharts },
  props: {
    chartType: {
      type: String,
      required: true,
      validator(value) {
        return (
          ["bar", "pieAnnulus", "line", "barGroup", "pie", "lineMark"].indexOf(
            value
          ) !== -1
        );
      },
    },
    rendererType: {
      type: String,
      default: "canvas",
      validator(val) {
        return ["canvas", "svg"].indexOf(val) !== -1;
      },
    },
    animationIsOpen: {
      type: Boolean,
      default: true,
    },
    chartData: {
      type: [Object, Array],
      required: true,
    },
    chartTitle: {
      type: String,
      default: "",
    },
    chartColor: {
      type: Array,
      default() {
        return [
          "#1886FE",
          "#1CD1A1",
          "#FECA57",
          "#5FC9FA",
          "#FE5863",
          "#dd7755",
        ];
      },
    },
    chartClick: {
      type: Function,
      default() {},
    },
  },
  data() {
    return {
      chartOption: null,
      initOptions: { renderer: "canvas" },
    };
  },
  watch: {
    chartData: {
      deep: true,
      handler() {
        this.getOptions();
      },
    },
  },
  mounted() {
    if (this.rendererType) this.initOptions.renderer = this.rendererType;
    this.getOptions();
  },
  methods: {
    getOptions() {
      const name = this.chartType[0].toUpperCase() + this.chartType.slice(1);
      this.chartOption = this[`get${name}Option`](this.chartData);
    },
    getDataURL(options) {
      return this.$refs.vueChart && this.$refs.vueChart.getDataURL(options);
    },
    getLineOption(datas) {
      if (!datas.dataList.length) return;
      const linearColor = new echarts.graphic.LinearGradient(0, 1, 0, 0, [
        {
          offset: 1,
          color: "rgba(58,147,251,1)",
        },
        {
          offset: 0,
          color: "rgba(58,147,251,0)",
        },
      ]);
      const tipShadowColor = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
        {
          offset: 1,
          color: "rgba(58,147,251,0.8)",
        },
        {
          offset: 0,
          color: "rgba(58,147,251,0)",
        },
      ]);

      const colors = {
        light: {
          lineColor: "#F0F4F9",
          labelColor: "#8C94AC",
        },
        dark: {
          lineColor: "#262A4D",
          labelColor: "#737AAE",
        },
      };
      const color = colors[datas.type];

      return {
        animation: this.animationIsOpen,
        grid: {
          top: "18%",
          bottom: "12%",
          left: "5%",
          right: "5%",
        },
        tooltip: {
          show: false,
        },
        xAxis: {
          type: "category",
          data: datas.dataList.map((item) => item.name),
          splitLine: {
            show: false,
          },
          axisLine: {
            lineStyle: {
              color: color.lineColor,
            },
          },
          axisLabel: {
            color: color.labelColor,
            fontSize: 14,
            margin: 14,
          },
          axisTick: {
            show: false,
          },
        },
        yAxis: {
          type: "value",
          splitLine: {
            show: true,
            lineStyle: {
              color: color.lineColor,
            },
          },
          axisLine: {
            show: false,
          },
          axisLabel: {
            fontSize: 14,
            color: color.labelColor,
            // formatter: function (value) {
            //   return value + "%";
            // },
          },
          axisTick: {
            show: false,
          },
        },
        series: [
          {
            name: "数量",
            type: "line",
            smooth: true,
            data: datas.dataList.map((item) => item.count),
            itemStyle: {
              color: "#3A93FB",
            },
            lineStyle: {
              color: "#3A93FB",
            },
            areaStyle: {
              color: linearColor,
            },
          },
          {
            name: "其他",
            type: "bar",
            data: datas.dataList.map((item) => item.count),
            barMaxWidth: 35,
            itemStyle: {
              color: "transparent",
            },
            emphasis: {
              itemStyle: {
                color: tipShadowColor,
              },
              label: {
                show: true,
                position: "top",
                backgroundColor: "#3A93FB",
                color: "#fff",
                fontSize: 14,
                offset: [0, -5],
                padding: [5, 4, 3, 3],
                borderRadius: 5,
              },
            },
          },
        ],
      };
    },
    getLineMarkOption(datas) {
      if (!datas.length) return;

      return {
        animation: this.animationIsOpen,
        grid: {
          top: "18%",
          bottom: "12%",
          left: "5%",
          right: "5%",
        },
        tooltip: {
          show: false,
        },
        xAxis: {
          type: "category",
          data: datas.map((item) => item.name),
          splitLine: {
            show: true,
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisLine: {
            lineStyle: {
              color: "#BDC8D9",
            },
          },
          axisLabel: {
            color: "#8C94AC",
            fontSize: 14,
            margin: 14,
          },
          axisTick: {
            show: false,
          },
        },
        yAxis: {
          type: "value",
          splitLine: {
            show: true,
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisLine: {
            show: false,
          },
          axisLabel: {
            fontSize: 14,
            color: "#8C94AC",
            // formatter: function (value) {
            //   return value + "%";
            // },
          },
          axisTick: {
            show: false,
          },
        },
        series: [
          {
            name: "数量",
            type: "line",
            symbolSize: 8,
            data: datas.map((item) => item.count),
            itemStyle: {
              color: "#3A93FB",
            },
            lineStyle: {
              color: "#3A93FB",
            },
            markLine: {
              symbol: "none",
              data: [
                {
                  type: "average",
                  lineStyle: {
                    color: "#626A82",
                  },
                  label: {
                    position: "insideEndTop",
                    formatter: "平均科次：{c}",
                  },
                  emphasis: {
                    lineStyle: {
                      type: "dotted",
                      color: "#1886FE",
                    },
                  },
                },
              ],
            },
          },
        ],
      };
    },
    getPieAnnulusOption(datas) {
      if (!datas.dataList.length) return;

      const colors = {
        light: {
          aColor: "#8C94AC",
          bColor: "#202B4B",
        },
        dark: {
          aColor: "#737AAE",
          bColor: "#ffffff",
        },
      };
      const color = colors[datas.type];

      const seriesData = datas.dataList.map((item) => {
        return {
          name: `${item.name}_${item.count}`,
          value: item.count,
        };
      });

      return {
        animation: this.animationIsOpen,
        color: this.chartColor,
        grid: {
          top: "20%",
          bottom: "10%",
        },
        tooltip: {
          trigger: "item",
          formatter: "{a} <br/>{b} : {c} ({d}%)",
        },
        legend: {
          show: true,
          orient: "vertical",
          left: "60%",
          top: "middle",
          itemGap: 20,
          itemWidth: 8,
          itemHeight: 8,
          textStyle: {
            rich: {
              a: {
                color: color.aColor,
                fontSize: 14,
                width: 100,
                padding: [0, 0, 0, 5],
              },
              b: {
                color: color.bColor,
                fontSize: 16,
                padding: [0, 0, 0, 10],
                fontWeight: "bold",
              },
            },
          },
          formatter: (label) => {
            const [name, count] = label.split("_");
            return `{a|${name}}{b|${count}%}`;
          },
        },
        series: [
          {
            name: "占比",
            type: "pie",
            radius: ["55%", "80%"],
            data: seriesData,
            label: {
              show: false,
            },
            center: ["25%", "50%"],
          },
        ],
      };
    },
    getPieOption(datas) {
      if (!datas.length) return;

      const seriesData = datas.map((item) => {
        return {
          name: item.name,
          value: item.count,
        };
      });

      return {
        animation: this.animationIsOpen,
        color: ["#1886FE", "#FECA57", "#5FC9FA", "#FE5863", "#dd7755"],
        grid: {
          top: "20%",
          bottom: "1%",
        },
        tooltip: {
          show: false,
        },
        legend: {
          show: true,
          bottom: "1%",
          itemGap: 20,
          itemWidth: 8,
          itemHeight: 8,
          icon: "circle",
          textStyle: {
            color: "#8C94AC",
            fontSize: 14,
            padding: [0, 0, 0, 5],
          },
        },
        series: [
          {
            name: "占比",
            type: "pie",
            radius: [0, "60%"],
            data: seriesData,
            itemStyle: {
              borderWidth: 2,
              borderColor: "#fff",
            },
            label: {
              fontSize: 14,
              color: "#626A82",
              formatter: "{b}：{d}%",
            },
          },
        ],
      };
    },
    getBarOption(datas) {
      if (!datas.dataList.length) return;
      const colors = {
        light: {
          lineColor: "#F0F4F9",
          labelColor: "#8C94AC",
          series: "#5FC9FA",
        },
        dark: {
          lineColor: "#262A4D",
          labelColor: "#737AAE",
          series: "#5FC9FA",
        },
      };
      const color = colors[datas.type];

      return {
        animation: this.animationIsOpen,
        color: this.chartColor,
        grid: {
          top: "20%",
          bottom: "10%",
          left: "5%",
          right: "5%",
        },
        tooltip: {
          show: true,
        },
        xAxis: {
          type: "category",
          data: datas.dataList.map((item) => item.name),
          axisLine: {
            lineStyle: {
              color: color.lineColor,
            },
          },
          axisLabel: {
            color: color.labelColor,
            fontSize: 14,
            padding: [3, 0, 0, 0],
          },
          axisTick: {
            show: false,
          },
        },
        yAxis: {
          type: "value",
          splitLine: {
            show: true,
            lineStyle: {
              color: color.lineColor,
            },
          },
          axisLine: {
            show: false,
          },
          axisLabel: {
            color: color.labelColor,
            fontSize: 14,
          },
          axisTick: {
            show: false,
          },
        },
        series: [
          {
            name: "数值",
            type: "bar",
            barMaxWidth: 80,
            barMinWidth: 10,
            data: datas.dataList.map((item) => item.count),
            itemStyle: {
              color: color.series,
            },
          },
        ],
      };
    },
    getBarGroupOption(dataList) {
      if (!dataList.length) return;
      const PLACE_STATES = {
        login: {
          name: "已登录",
          color: "#5FC9FA",
        },
        error: {
          name: "通讯故障",
          color: "#FE5863",
        },
        warning: {
          name: "预警数",
          color: "#FECA57",
        },
      };

      const legendData = Object.entries(PLACE_STATES).map((el) => el[1].name);

      let seriesList = [];
      let yAxisLabels = dataList.map((item) => item.name);

      Object.entries(PLACE_STATES).map(([key, { name, color }]) => {
        let seriesItemData = dataList.map((item) => item[key]);
        seriesList.push({
          name: name,
          type: "bar",
          data: seriesItemData,
          barWidth: 10,
          barGap: "0",
          itemStyle: {
            barBorderRadius: [5, 5, 0, 0],
            color: color,
          },
          label: {
            show: false,
          },
        });
      });

      let options = {
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "shadow",
          },
        },
        legend: {
          show: false,
          data: legendData,
          top: "2%",
          right: 0,
          itemGap: 20,
          itemWidth: 8,
          itemHeight: 8,
          textStyle: {
            color: "#626A82",
            fontSize: 14,
          },
        },
        grid: {
          left: "1%",
          right: "1%",
          bottom: "5%",
          top: "20%",
          containLabel: true,
        },
        yAxis: {
          type: "value",
          position: "top",
          axisLine: {
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisTick: { show: false },
          splitLine: {
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisLabel: {
            color: "#8C94AC",
            fontSize: 14,
            // formatter: function (value) {
            //   return Math.round(value * 100) + "%";
            // },
          },
        },
        xAxis: {
          type: "category",
          data: yAxisLabels,
          boundaryGap: ["5%", "5%"],
          axisLine: {
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisTick: { show: false },
          splitLine: {
            show: false,
            lineStyle: {
              color: "#F0F4F9",
            },
          },
          axisLabel: {
            color: "#8C94AC",
            fontSize: 14,
            margin: 20,
            align: "center",
            formatter: (value) => {
              return this.splitStrByStep(value, 4).join("\n");
            },
          },
        },
        series: seriesList,
      };

      if (dataList.length > 10) {
        const dataZoomRange = Math.floor((10 / dataList.length) * 100);
        options.dataZoom = [
          {
            type: "slider",
            xAxisIndex: [0],
            bottom: "0%",
            start: 0,
            end: dataZoomRange,
            minSpan: dataZoomRange,
            maxSpan: dataZoomRange,
            backgroundColor: "transparent",
            fillerColor: "#8C94AC",
            borderColor: "transparent",
            handleSize: "0%",
            showDetail: false,
            throttle: 200,
            height: 5,
          },
          {
            type: "inside",
            xAxisIndex: [0],
            start: 0,
            end: dataZoomRange,
          },
        ];
      }
      return options;
    },
    splitStrByStep(str, step = 2) {
      if (!step) return str;
      if (str.length < step) return [str];

      let strs = str.split("");
      let strArr = [];
      let part = [];
      strs.map((element) => {
        part.push(element);
        if (part.length >= step) {
          strArr.push(part.join(""));
          part = [];
        }
      });
      if (part.length) strArr.push(part.join(""));
      return strArr;
    },
  },
};
</script>

<style lang="scss" scoped>
.chart-box {
  height: 100%;
  position: relative;
}
.chart-box .chart-none {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  font-size: 20px;
  text-align: center;
  color: #8c94ac;
  margin: 0;
}
</style>
