PercentChart.vue 10.8 KB
<template>
  <div :class="className" :style="{ height: height, width: width }"></div>
</template>

<script>
import * as echarts from 'echarts';
require("echarts/theme/macarons"); // echarts theme
import resize from "./mixins/resize";
const animationDuration = 2600;
export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%",
    },
    autoResize: {
      type: Boolean,
      default: true
    },
    chartData: {
      // type: Object
      required: true
    },
    chartConfig: {
      type: Object,
      default: () => {
        return {};
      }
    },
    title: {
      type: String,
      default: "分布图"
    }
  },
  data() {
    return {
      chart: null,
      config: {
        title: {
          text: "",
          top: "3%",
          left: "1%",
          // padding: 20,
          textStyle: {
            color: "rgba(255, 255, 255, 0.8)",
            fontStyle: "normal",
            fontSize: 16
          }
          // subtext: "筛查人群总数\n" + "10,234",
          // subtextStyle: {
          //   color: "#80FFFF",
          //   fontStyle: "normal",
          //   fontSize: 14,
          //   align: "center",
          //   formatter: [
          //     "{a|这段文本采用样式a}",
          //     "{b|这段文本采用样式b}这段用默认样式{x|这段用样式x}"
          //   ].join("\n"),

          //   rich: {
          //     a: {
          //       color: "red",
          //       lineHeight: 10
          //     },
          //     b: {
          //       backgroundColor: {
          //         image: "xxx/xxx.jpg"
          //       },
          //       height: 40
          //     },
          //     x: {
          //       fontSize: 18,
          //       fontFamily: "Microsoft YaHei",
          //       borderColor: "#449933",
          //       borderRadius: 4
          //     }
          //   }
          // }
        },
        color: [
          "rgba(2, 167, 240, 1)",
          "rgba(245, 166, 0, 1)",
          "rgba(248, 60, 83, 1)"
        ],
        // 设置图表的位置
        grid: {
          // x: 60, // 左间距
          // y: 80, // 上间距
          // x2: 60, // 右间距
          // y2: 40, // 下间距
          left: 20,
          right: 20,
          bottom: 20,
          top: "23%", //grid 组件离容器上侧的距离
          containLabel: true // grid 区域是否包含坐标轴的刻度标签, 常用于『防止标签溢出』的场景
        },
        // 提示框组件
        tooltip: {
          trigger: "axis", // 触发类型, axis: 坐标轴触发
          borderWidth:0,
          axisPointer: {
            // 指示器类型  'line' 直线指示器 'shadow' 阴影指示器 'none' 无指示器
            // 'cross' 十字准星指示器 其实是种简写,表示启用两个正交的轴的 axisPointer
            type: "none"
          },
          textStyle: {
            color: "#cdd3ee" // 文字颜色
          },
          // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 折线(区域)图、柱状(条形)图、K线图
          // {a}(系列名称),{b}(类目值),{c}(数值), {d}(无)
          // formatter: "{b}<br />{a0}: {c0}%<br />{a1}: {c1}%<br />{a2}: {c2}%"
          // formatter: "{b}<br />{a}: {c}%<br />"
          formatter: function(params) {
            var relVal = params[0].name;
            for (var i = 0, l = params.length; i < l; i++) {
              relVal +=
                "<br/>" +
                params[i].marker +
                params[i].seriesName +
                " : " +
                params[i].value +
                "%";
            }
            return relVal;
          }
        },
        // 图例组件
        legend: {
          show: false,
          textStyle: {
            // 文本样式
            fontSize: 16,
            color: "#cdd3ee"
          },
          top: 13, // 定位
          data: ["已完成", "进行中", "未完成"] // 图例的数据数组
        },
        // X轴
        xAxis: {
          type: "value", // 坐标轴类型,   'value' 数值轴,适用于连续数据
          // 坐标轴刻度
          axisTick: {
            show: false // 是否显示坐标轴刻度 默认显示
          },
          // 坐标轴轴线
          axisLine: {
            // 是否显示坐标轴轴线 默认显示
            show: false // 是否显示坐标轴轴线 默认显示
          },
          // 坐标轴在图表区域中的分隔线
          splitLine: {
            show: false // 是否显示分隔线。默认数值轴显示
          },
          splitArea: false,
          // 坐标轴刻度标签
          axisLabel: {
            show: false // 是否显示刻度标签 默认显示
          },
          max: [100] //相当于百分比饼图
        },
        yAxis: [
          // 左侧Y轴
          {
            // 坐标轴类型,  'category' 类目轴,适用于离散的类目数据
            // 为该类型时必须通过 data 设置类目数据
            type: "category",
            // 坐标轴刻度
            axisTick: {
              show: false // 是否显示坐标轴刻度 默认显示
            },
            // 坐标轴轴线
            axisLine: {
              // 是否显示坐标轴轴线 默认显示
              show: false, // 是否显示坐标轴轴线 默认显示
              lineStyle: {
                // 坐标轴线线的颜色
                color: "#cdd3ee"
              }
            },
            // 坐标轴在图表区域中的分隔线
            splitLine: {
              show: false // 是否显示分隔线。默认数值轴显示
            },
            splitArea: false,
            // 坐标轴刻度标签
            axisLabel: {
              show: false, // 是否显示刻度标签 默认显示
              fontSize: 16, // 文字的字体大小
              color: "#cdd3ee", // 刻度标签文字的颜色
              // 使用字符串模板,模板变量为刻度默认标签 {value}
              formatter: "{value}"
            },
            // 类目数据,在类目轴(type: 'category')中有效
            data: ["比例"]
          }
        ],
        // 系列列表
        series: [
          {
            type: "bar", // 系列类型
            name: "", // 系列名称, 用于tooltip的显示, legend 的图例筛选

            stack: "total", // 数据堆叠,同个类目轴上系列配置相同的stack值后,后一个系列的值会在前一个系列的值上相加
            barMaxWidth: 20, // 柱条的最大宽度,不设时自适应
            // 图形上的文本标签
            label: {
              show: true,
              // 标签的位置 left right bottom top inside  // 绝对的像素值 position: [10, 10]
              // 相对的百分比 position: ['50%', '50%']
              position: "inside",
              color: "white",
              fontSize: 16,
              distance: 0,
              formatter: "{a0}\n\n\n\n{c0}%"
            },
            // 图形样式
            // itemStyle: {
            //   barBorderRadius: [10, 0, 0, 10] // 圆角半径, 单位px, 支持传入数组分别指定 4 个圆角半径
            // },
            data: [] // 系列中的数据内容数组
          }
          // {
          //   type: "bar",
          //   name: "",
          //   stack: "总量",
          //   barMaxWidth: 20,
          //   label: {
          //     show: true,
          //     position: "inside",
          //     color: "white",
          //     fontSize: 16,
          //     distance: 0,
          //     formatter: "{a0}\n\n\n\n{c0}%"
          //   },
          //   data: []
          // },
          // {
          //   type: "bar",
          //   name: "",
          //   stack: "总量",
          //   barMaxWidth: 20,
          //   label: {
          //     show: true,
          //     position: "inside",
          //     color: "white",
          //     fontSize: 16,
          //     distance: 0,
          //     formatter: "{a0}\n\n\n\n{c0}%"
          //   },
          //   data: []
          // }
        ]
      }
    };
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        this.setOptions(val);
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
    });
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    this.chart.dispose();
    this.chart = null;
  },
  methods: {
    initChart() {
      //   this.chart = echarts.init(document.getElementById('chart'));
      this.chart = echarts.init(this.$el, "macarons");
      // 监听屏幕变化自动缩放图表
      //   window.addEventListener('resize', function () { this.chart.resize() })

      this.setOptions(this.chartData);
    },
    setOptions(chartData) {
      // let option = {};
      // option = this.config;

      if (!chartData.data) return;
      const option = Object.assign(this.config, this.chartConfig);
      const series = chartData.data.map(v => {
        if (v.color) {
          return {
            name: v.name,
            value: Number(v.value),
            color: v.color
          };
        }
        return {
          name: v.name,
          value: Number(v.value)
        };
      });
      const seriesList = [];
      const colorList = [];
      const legendList = [];

      series.forEach((item, index) => {
        const seriesItem = {
          type: "bar",
          name: "",
          stack: "total",
          // barGap: '-100%', //重叠
          barMaxWidth: 20,
          label: {
            show: true,
            position: "inside",
            color: "white",
            fontSize: 16,
            distance: 0,
            formatter: "{a0}\n\n\n\n{c0}%"
          },
          data: []
        };
        // item.data = [series[index].value];
        // item.name = [series[index].name];
        if (item.color) {
          colorList.push(item.color);
        }
        if (item.name) {
          legendList.push(item.name);
          seriesItem.name = item.name;
        }
        if (item.value) {
          seriesItem.data = [item.value];
        }
        seriesList.push(seriesItem);
      });

      //   if (chartData.legend && chartData.legend.data) {
      //     option.legend.data = chartData.legend.data;
      //   }
      //   //   option.xAxis[0].data = series.map(_ => _.name);
      //   // option.series[0].data = series.map(_ => _.value);
      option.title.text = this.title;
      option.series = seriesList;
      option.color = series.map(_ => _.color);
      option.legend.data = series.map(_ => _.name);
      this.chart.setOption(option);
      this.$forceUpdate();
    }
  }
};
</script>