vue+echarts封装环图;

前端可视化数据环图封装

  1. html
<template>
  <div class="container">
    <div
      ref="loop"
      style=""
      :style="{ width: `${width}`, height: `${height}` }"
    ></div>
    <div
      v-if="legendSelect"
      :style="{ top: styleData.top, left: styleData.left }"
      class="loop_label"
    >
      <div class="text" v-text="selectedSeries.legend"></div>
      <div class="num" v-text="selectedSeries.measure"></div>
    </div>
    <div class="progress-box" v-if="progress">
      <div class="progress-top">
        <div class="progress-top-label">
          <span>工单总数</span>
          <span>单位: 个</span>
        </div>
        <div class="progress-top-total">
          {{ sum }}
        </div>
      </div>
      <div class="progress-bottom">
        <ul>
          <li v-for="(v, i) in loopData" :key="i">
            <div class="progress-name">
              <span>{{ v.name }}</span>
              <span :style="{ color: v.itemStyle.color }">{{ v.num }}</span>
            </div>
            <div
              class="progress-bar"
              :style="{ backgroundColor: v.itemStyle.color, width: v.num }"
            ></div>
            <div class="progress-bar-bgc"></div>
          </li>
        </ul>
      </div>
    </div>
    <ul class="bfb_list" v-if="!progress">
      <li
        v-for="(v, i) in loopData"
        :key="i"
        :style="{ color: v.itemStyle.color }"
        @click="tabClick(v, i)"
      >
        {{ v.num }}
      </li>
    </ul>
  </div>
</template>

2.js

<script>
export default {
  props: {
    width: {
      type: String,
      default: "360px",
    },
    height: {
      type: String,
      default: "160px",
    },
    title: {
      type: String,
      default: "景区资源",
    },
    nuit: {
      type: String,
      default: "个",
    },
    center: {
      type: Array,
      default: () => {
        return ["60%", "50%"];
      },
    },
    styleData: {
      type: Object,
      default: () => {
        return {
          textSize: "18px",
          textColor: "#BFEBFF",
          valueSize: "48px",
          valueColor: "#FFFFFF",
          top: "34%",
          left: "8%",
        };
      },
    },
    //图例
    legendSelect: { type: Boolean, default: true },
    //图例数据
    legends: {
      type: Array,
      default: () => {
        return [
          "#00FFFF",
          "#FCEF03",
          "#95FF2B",
          "#15BFFF",
          "#00DD8A",
          "#2872EC",
        ];
      },
    },
    displayModel: {
      type: Number,
      default: 0, //0 图例 1 进度条 2 图例+个数
    },
    rowData: {
      type: Array,
      default: () => {
        return [
          {
            measure: 3011,
            legend: "已处理",
          },
          {
            measure: 3211,
            legend: "未处理",
          },
          {
            measure: 2511,
            legend: "处理中",
          },
        ];
      },
    },
    progress: {
      type: Boolean,
      default: true,
    },
  },

  data() {
    return {
      loopData: [],
      num: 0,
      //当前选中的数据
      selectedSeries: {
        legend: "",
        measure: "",
      },
      sum: 0,
      myChart: {},
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.draw();
    });
  },
  methods: {
    draw() {
      // 基于准备好的dom,初始化echarts实例
      this.myChart = this.$echarts.init(this.$refs.loop);
      this.option = {
        tooltip: {
          trigger: "item",
          formatter: "{b}:{d}%",
        },
        series: [
          {
            type: "pie",
            radius: ["75%", "85%"],
            center: this.center,
            hoverAnimation: false,
            selectedMode: "single",
            label: {
              show: false,
              position: "center",
            },

            labelLine: {
              show: false,
            },
            data: [],
          },
        ],
      };
      if (this.legendSelect) {
        this.option.legend = {
          show: !this.progress,
          orient: "vertical",
          top: 10,
          right: 60,
          textStyle: {
            color: "#BFEBFF",
            fontSize: 14,
          },
          itemWidth: 8,
          itemHeight: 8,
          selectedMode: false,
        };
      }
      this.loopData = this.convertData(this.rowData, this.legends);
      this.option.series[0].data = this.loopData;
      this.carousel();
      this.myChart.setOption(this.option);
    },
    //数据转换
    convertData(rowData, legends) {
      this.sum = 0;
      let returnData = [];
      if (rowData.length > 0) {
        rowData.forEach((d, index) => {
          this.sum += d.measure;
          returnData.push({
            value: d.measure,
            name: d.legend,
            itemStyle: {
              color: legends[index % 10],
            },
          });
        });
        returnData.forEach((d) => {
          d.num =
            this.sum == 0 ? "0" : ((d.value / this.sum) * 100).toFixed(2) + "%";
          d.sum = this.sum == 0 ? "0" : this.sum;
        });

        if (returnData.length > 0 && returnData[0].value == this.sum) {
          returnData[0].num = "100%";
        }

        //进度条模式时 倒序排序
        if (this.displayModel == 1) {
          returnData.sort((a, b) => {
            return b.value - a.value;
          });
        }

        //增加千分位
        if (this.displayModel == 2) {
          let re = /(?=(?!(\b))(\d{3})+$)/g;
          returnData.forEach((r) => {
            r.value = String(r.value).replace(re, ",");
          });
        }
      } else {
        returnData.push({
          name: "暂无数据",
          value: "0",
          num: "0%",
          itemStyle: { color: "#373F55" },
        });
      }
      return returnData;
    },
    setTimeToDo() {
      let that = this;
      let data = that.option.series[0].data;

      that.selectedSeries.legend = data[that.num].name;
      that.selectedSeries.measure = data[that.num].num;
      // 必须重新设置option,因为echart没有监听data的变化
      if (data.length > 2) {
        data.forEach((e) => (e.selected = false));
        data[that.num].selected = true;
      that.option && that.myChart.setOption(that.option);
      }
    },
    setHighLight() {
      let that = this;
      clearInterval(that.timer);
      const data = that.option.series[0].data;
      that.timer = setInterval(() => {
        if (that.num < data.length - 1) {
          that.num++;
        } else {
          that.num = 0;
        }
        that.setTimeToDo();
      }, 1000);
    },
    //轮播
    carousel() {
      if (this.option.series[0].data.length > 0) {
        //开启定时器
        this.setTimeToDo();
        this.setHighLight();
      }
    },
    tabClick(v, i) {
      this.$emit("statusClick", v.name);
    },
  },
  watch: {
    rowData: {
      handler(neVal) {
        let that = this;
        that.option.series[0].data = [];
        that.loopData = that.convertData(neVal, that.legends);
        that.option.series[0].data = that.loopData;
        that.$nextTick(() => {
          that.num = 0;
          that.selectedSeries = {
            legend: "",
            measure: "",
          };
          // that.sum = 0;
          let chart = that.$echarts.init(that.$refs.loop);
          that.carousel();
          chart.setOption(that.option);
        });
      },
      deep: false,
    },
  },
  destroyed() {
    this.timer && clearInterval(this.timer);
  },
};
</script>

3.style基于scss

<style lang="scss" scoped>
.loop_label {
  width: 59%;
  position: absolute;
  top: 29%;
  left: 0;
  height: 49%;
  // text-shadow: 0 0 3px #000000;
  font-size: 0px;

  .text {
    // padding-left: 35px;
    font-size: 16px;
    font-weight: "400";
    // overflow: hidden;
    // text-overflow: ellipsis;
    // white-space: nowrap;
    width: 100%;
    text-align: center;
    font-family: "微软雅黑";
    color: #ECECEC;
    // margin: 4px 0;
    // background-image: -webkit-linear-gradient(#ffffff, #99ecfb);
    // background-clip: text;
    // -webkit-text-fill-color: transparent;
  }
  .num {
    font-size: 42px;
    font-family: "Voltage";
    text-align: center;
    font-weight: "400";
    color: #FFFFFF;
    // background-image: -webkit-linear-gradient(#ffffff, #8a9eb5);
    // background-clip: text;
    // -webkit-text-fill-color: transparent;
  }
}
.bfb_list {
  font-family: "DINCond-Medium";
  font-size: 20px;
  width: 160px;
  position: absolute;
  top: 16px;
  right: 6px;
  z-index: 99999999;
  color: #00ffff;
  li {
    list-style: none;
    cursor: pointer;
    text-align: right;
    margin-top: 2px;
  }
}
.progress-box {
  position: absolute;
  right: 10px;
  top: 11px;
  width: 180px;
  height: 136px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  .progress-top {
    width: 100%;
    height: 36px;
    display: flex;
    justify-content: space-between;
    .progress-top-label {
      width: 65px;
      height: 100%;
      //   background-color: #fff;
      span:nth-child(1) {
        font-weight: bold;
        font-size: 16px;
        color: #fff;
      }
      span:nth-child(2) {
        font-size: 14px;
        color: #14bfff;
      }
    }
    .progress-top-total {
      font-family: "DINCond-Medium";
      font-size: 36px;
      line-height: 36px;
      color: #26c9ff;
    }
  }
  .progress-bottom {
    width: 100%;
    height: 99px;
    li {
      list-style: none;
      position: relative;
      width: 100%;
      height: 32px;
      .progress-name {
        position: relative;
        width: 100%;
        height: 26px;
        line-height: 26px;
        span:nth-child(1) {
          color: #aae3ff;
          font-size: 14px;
        }
        span:nth-child(2) {
          font-family: "DINCond-Medium";
          position: absolute;
          right: 0;
          font-size: 20px;
        }
      }
      .progress-bar {
        position: absolute;
        bottom: 0;
        height: 6px;
        z-index: 99999;
      }
      .progress-bar-bgc {
        width: 180px;
        height: 6px;
        background-color: #373f55;
      }
    }
  }
}
.container {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  pointer-events: all;
  margin-top: -31px;
  .left {
    flex: 1;
  }
  .right {
    overflow: auto;
    flex: 1;
    width: 100%;
    height: 80%;
    justify-content: center;
    align-items: center;
    max-height: calc(100% - 20px);
  }
}
</style>

4.如图
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值