使用vue开发echarts柱状图和折线图基础组件 以及 自定义 tooltips

开发背景就不过多赘述了,直接先来几张效果图吧

    

  

1.首先在 package.json 中添加echarts:

{
  "dependencies": {
    "echarts": "^5.0.0",
  }
}

2.然后执行 npm install;

3.接下来就开始编写相关组件文件,代码量较大,建议直接复制下来按步骤运行: 

3.1.创建组件文件  barLineChartPY.vue 代码如下:

<template>
  <!-- 多折线图 圆滑转折点  面积渐变色 -->
  <div style="with: 100%; height: 100%;" :id="id"></div>
</template>

<script>
export default {
  props: {
    "id": {
      type: String,
      default: "myChart"
    }, 
    "title": {
      type: String,
      default: ""
    }, 
    "color": {
      type: String,
      default: ""
    }, 
    "chartData": {
      type: Object,
      default: undefined
    }, 
    "units": {
      type: String,
      default: ""
    },
    "yMax": {
      type: Number,
      default: undefined
    }
  },
  data() {
    return {
      myChart: {},
      colors: ['#3769C9', '#EB9C06', '#80FFA5', '#00DDFF', '#FF0087'],
      xData: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
      // 柱状图的 基础 series  本组件中的默认 series
      seriesBar: {
        name: '',
        type: 'bar',
        // barWidth: 10,
        // stack: 'total',
        // label: {show: false},
        // itemStyle: {
          //这里设置柱形图圆角 [左上角,右上角,右下角,左下角]
          // barBorderRadius: 30,
          // 柱状图 柱子  渐变色  或 单色
          // 前4个参数用于配置渐变色的起止位置, 这4个参数依次对应右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始
          // offset的范围是0 ~ 1, 用于表示位置
          // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: '#033BFF'}, {offset: 1, color: '#01B1FF'}])
        // },
        // emphasis: {
          // focus: 'series',
          // itemStyle: {
            // 柱状图 柱子  渐变色  或 单色
            // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: '#01B1FF'}, {offset: 1, color: '#033BFF'}])
          // }
        // },
        data: [123, 150, 100, 300, 500, 1000, 1300, 1100, 800, 600, 500, 350],
        data0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
      },

      // 折线图的 基础 series
      seriesLine: {
        name: '', //this.chartData.seriesName,
        type: "line",
        // smooth: true,  // 圆滑的拐点 默认false
        // showSymbol: true,
        data: [123, 150, 100, 300, 500, 1000, 1300, 1100, 800, 600, 500, 350], // this.chartData.dataArr,
        data0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        // lineStyle: {
          // color: "#00DDFF",
          // width: 1,
        // },
        // areaStyle: {  // color: "transparent",
          // 折线图 面积  渐变色  或 单色
          // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: "#00DDFFFF"}, {offset: 1, color: "#00DDFF00"}])
        // },
        // emphasis: {
          // focus: 'series'
        // }
      }
    }
  },
  methods: {
    initChart() {
      var echarts = require("echarts");
      // 基于准备好的dom,初始化echarts实例
      this.myChart = echarts.init(document.getElementById(this.id));
      // 绘制图表---横轴标识--xAxis.data=['1月','2月','3月']
      this.xData = this.chartData.xData && this.chartData.xData.length > 0 ? this.chartData.xData : this.xData;
      
      // debugger
      var flag = false;
      const units = this.units;
      const series = this.getSeries();
      for (var ii = 0, nn = series.length; ii < nn; ii++) {
        if (series[ii].type == 'bar') {
          flag = true;
          break;
        }
      }

      var left = 45;
      if (this.yMax && (this.yMax + '').length <= 3) {
        left = 30;
      } else if (this.yMax && (this.yMax + '').length <= 4) {
        left = 40;
      } else if (this.yMax && (this.yMax + '').length <= 6) {
        left = 55;
      } 
      
      var option = {
        grid: {top: "30", bottom: '25', right: '30', left: left},
        tooltip: {
          trigger: "axis",
          formatter: function(params) { // 自定义 tooltip 
            // console.log(params);
            var txt = params[0].name;
            for (var i = 0, n = params.length; i < n; i++) {
              var sn = params[i].seriesName, 
                  cl = params[i].color, 
                  val = params[i].value;
                  
              txt += '<div><span class="blue-dot middle" style="background: ' + cl + ';"></span><span>' + sn + '' + val + units + '</span></div>'; 
            }
            return txt;
          }
        },
        legend: {
          show: true,
          left: 'right',
          // icon: "circle", // 修改形状
          itemHeight: 8, // 修改icon图形大小
          itemWidth: 16, // 修改icon图形大小
          itemGap: 8, // 修改间距
          textStyle: {color: '#fff', fontSize: 12}// padding: [0, -5, 0, 0], // 修改文字和图标距离
        },
        xAxis: {
            type: "category",
            data: this.xData,
            axisTick: {show: true},
            axisLine: {show: true, lineStyle: {color: "#4e9bdf"}},
            axisLabel: {textStyle: {color: "#365787"}, margin: 10, rotate: 0}, // rotate x轴标识 旋转角度
            boundaryGap: flag, //false:x轴文字贴紧俩边
        },
        yAxis: {
            name: (this.units ? ("单位:" + this.units) : ""),
            type: "value",
            max: this.yMax,
            axisLabel: {textStyle: {color: "#ffffff"}}, //// margin: 10,
            axisLine: {show: true, lineStyle: {color: "#4e9bdf"}},
            splitLine: {lineStyle: {color: "#4e9bdf", type: 'dashed'}},  // dashed-虚线
            min: 0,
        },
        series: series
      };

      // console.log(`id -> ${this.id}\noption -> ${JSON.stringify(option)}`);

      this.myChart.setOption(option);

      //自适应屏幕
      this.updateRsize(this.myChart);
    },
    getSeries() {
      // 折线图折线数据  --- series[0].name-折线的名称
      // series[0].data - 折线的数据
      var optSeries = [];
      const seriesData = this.chartData.seriesData;
      // console.log(`seriesData.length -> ${seriesData.length}\nseriesData -> ${JSON.stringify(seriesData)}`);
      if (seriesData && seriesData.length > 0) {
        for (var i = 0, n = seriesData.length; i < n; i++) {
          // 判断传递过来的 seriesData[i] 中的要展示的echarts图类型  默认为 bar 类型 柱状图
          const type = seriesData[i].type || 'bar'; 
          var series = JSON.parse(JSON.stringify(this.seriesBar)); // 克隆对象 this.seriesBar 赋值给 series
          if ("bar" != type) series = JSON.parse(JSON.stringify(this.seriesLine)); // 克隆对象 this.seriesLine 赋值给 series
          
          // 判断并设置 series.name
          series.name = seriesData[i].name || series.name;

          // 判断并处理传递过来的 seriesData[i].data  并设置进 series 中
          const tmpSeries = seriesData[i];
          if (tmpSeries.data && tmpSeries.data.length > 0) {
            series.data = tmpSeries.data;
            // 当数据长度小于 x轴要展示的数据长度时  使用 0 进行补充
            if (tmpSeries.data.length < this.xData.length) {
              for (var j = tmpSeries.data.length, m = this.xData.length; j < m; j++) {
                series.data.push(0);
              }
            }
          }

          // 判断并设置 series.stack 独立模式 留空不设置   或 堆叠模式 stack:'total'
          if (seriesData[i].stack) series.stack = seriesData[i].stack;

          // bar 类型的
          if ('bar' == type) {
            // 判断并设置柱子宽度 series.barWidth 
            if (seriesData[i].barWidth) series.barWidth = seriesData[i].barWidth; 

            // 判断并设置 series.itemStyle.
            if (seriesData[i].itemStyle) {
              // 判断并设置 series.itemStyle.barBorderRadius
              if (seriesData[i].itemStyle.radius) {
                if (!series.itemStyle) series.itemStyle = {};
                
                series["itemStyle"]["barBorderRadius"] = seriesData[i].itemStyle.radius
              }

              // 判断并设置 series.itemStyle.color
              const res = this.getItemStyleColor(seriesData[i].itemStyle.color, seriesData[i].itemStyle.colors);
              if (res) {
                if (!series.itemStyle) series.itemStyle = {};
                
                series["itemStyle"]["color"] = res;
              }
            }
          } else {
            // line类型的
            // 判断并设置 series.smooth 圆润拐点
            series.smooth = seriesData[i].smooth || false;
            if (seriesData[i].color) series.color = seriesData[i].color

            // 判断并设置 series.lineStyle
            if (seriesData[i].lineStyle) {
              // 判断并设置 series.lineStyle.width
              if (seriesData[i].lineStyle.width) {
                if (!series.lineStyle) series.lineStyle = {};
                
                series["lineStyle"]["width"] = seriesData[i].lineStyle.width;
              }
              // 判断并设置 series.lineStyle.color
              const res = this.getItemStyleColor(seriesData[i].lineStyle.color, seriesData[i].lineStyle.colors);
              if (res) {
                if (!series.lineStyle) series.lineStyle = {};
                
                series["lineStyle"]["color"] = res;
              }
            }

            // 判断并设置 series.areaStyle
            if (seriesData[i].areaStyle) {
              // 判断并设置 series.areaStyle.color
              const res = this.getItemStyleColor(seriesData[i].areaStyle.color, seriesData[i].areaStyle.colors);
              if (res) {
                if (!series.areaStyle) series.areaStyle = {};
                
                series["areaStyle"]["color"] = res;
              }
            }
          }

          // 判断并设置 series.emphasis
          if (seriesData[i].emphasis) {
            if (seriesData[i].emphasis.focus) {
              if (!series.emphasis) series.emphasis = {};
                
              series["emphasis"]["focus"] = seriesData[i].emphasis.focus;
            }
            // 判断并设置 series.emphasis.color
            const res = this.getItemStyleColor(seriesData[i].emphasis.color, seriesData[i].emphasis.colors);
            if (res) {
              if (!series.emphasis) series.emphasis = {};
                
              series["emphasis"]["color"] = res;
            }
          }

          optSeries.push(series);
          // console.log(`i -> ${i}\nseries -> ${JSON.stringify(series)}\noptSeries -> ${JSON.stringify(optSeries)}`);
        }
      } else {
        // this.seriesBar.data = this.seriesBar.data0;
        optSeries[0] = this.seriesBar;
      }

      // console.log(`optSeries -> ${JSON.stringify(optSeries)}`);
      return optSeries;
    },
    getItemStyleColor(color, colors) {
      if (color) {
        return color;
      } else if (colors) {
        const cok = Object.keys(colors);
        const fx = colors.fx;
        var cos = [];
        for (var ii = 0, nn = cok.length; ii < nn; ii++) {
          if ('fx' != cok[ii] && 0 <= cok[ii] <= 1) 
            cos.push({offset: cok[ii], color: colors[cok[ii]]});
        }
      
        if (fx && fx.length == 4) {
          return new echarts.graphic.LinearGradient(fx[0], fx[1], fx[2], fx[3], cos);
        } else {
          return new echarts.graphic.LinearGradient(0, 0, 0, 1, cos);
        }
      }

      return undefined;
    }
    
  },
  mounted() {
    // this.initChart();
  },
  watch: {
    //动态监听数据是否变化
    chartData: {
      deep: true,  //true为进行深度监听,false为不进行深度监听
      handler() {
        this.initChart();
      }
    },
  },
};
</script>

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

3.2.创建文件 maintenancefundsChart.vue  并引入刚创建的组件, 代码如下:

<template>
  <div class="cloud_wrap">
    <border-tem-py :width="'100%'">
      <!-- 插槽模板 -->
      <div class="title" slot="title">柱状折线图统计</div>
      <div class="content-box" slot="content">
        <div class="layui-row layui-col-space10">
          <div class="layui-col-md12">
            <bar-line-chart-py :id="'mfChart'" :chartData="chartData" :units="'万元'" />
          </div>
        </div>
      </div>
    </border-tem-py>
  </div>
</template>
<script>
import barLineChartPy from '../../../../common/barLineChartPY.vue'; // 路径根据自己实际项目中的进行修改
export default {
  components: { barLineChartPy },
  data() {
    return {
      active: 'y',
      chartData: { 
          xData: [], 
          seriesData: [
            {
              name: '统计',  // 必填
              data: [123, 330, 236.5, 500, 360.6,188.8,669.0,115,188,55],   // 必填
              type: 'bar', // 非必填  默认  bar  柱状图
              // stack: 'total',  // 柱状图或折线图展示模式   独立模式 留空不设置  或 堆叠模式 stack:'total'  非必填
              barWidth: 15, // 柱子宽度    非必填
              itemStyle: { // 仅柱状图生效  非必填
              //   // radius: 30, // 柱状图圆角 数字 或 数字数组 [20, 20, 0, 0] [左上角,右上角,右下角,左下角]
              //   // 柱子颜色  color 单色   colors 渐变色 (color / colors 二选一)
              //   // fx 渐变方向 右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始
              //   // 0、1 渐变的位置 以及 相应位置的颜色  取值范围 0~1
              //   // color: '',
                colors: {'fx': [0, 0, 0, 1], /* 渐变的方向 */ 0: '#2D96F3', 1: '#0B40C3'}
              },
              // // 鼠标移动到柱条上时的样式
              // emphasis: {  // 柱状图 和 折线图均可   非必填
              //   focus: 'series',
              //   // color 与 colors 参看 itemStyle 中的说明
              //   // color: '',
              //   colors: {}
              // }
            },
            {
              name: '统计2',  // 必填
              data: [230, 136, 500, 360, 288, 569, 315, 288, 155],  // 必填
              type: 'line', // 非必填  默认  bar  柱状图
              // smooth: true, // 折线图 转折点是否圆润 默认false    非必填
              // lineStyle: { // 仅折线图生效    非必填
              //   // width: 1,
              //   // color 与 colors 参看 itemStyle 中的说明
              //   color: '#EB9C06',
              //   // colors: {}
              // },
              // areaStyle: {  // 进折线图生效   折线图扫过的面积的样式     非必填
              //   // color 与 colors 参看 itemStyle 中的说明
              //   // color: '',
              //   colors: {}
              // }
            }
          ]
        }
    };
  },
  methods:{
      btnClick(val) {
        this.active = val;
        this.loadData();
      },
      loadData() {
        let params = {
          type: this.active
        };
        this.content = JSON.stringify(params)
        // 随机数数组 赋值 生成echarts图
        this.chartData.seriesData[0].data = this.$options.filters['randomNums'](0, 300, 12);
        this.chartData.seriesData[1].data = this.$options.filters['randomNums'](0, 600, 12);
      }
  },
  mounted() {
    this.loadData();
    // 定时器  模拟动态加载数据  实时渲染echarts  实现 实时动态echarts
    const interval = setInterval(() => {
      this.loadData();
    }, 2000);

    // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
    this.$once('hook:beforeDestroy', () => {         
      clearInterval(interval);                                    
    });
  },
};
</script>

<style scoped>
* {
  font-family: MicrosoftYaHei;
}

.cloud_wrap{
  z-index: 1;
  position: relative;
  cursor: pointer;
}

.cloud_wrap .layui-col-md12 {
  min-width: 175px;
  height: 230px;
}
</style>

3.3.然后再相关页面中再引入 maintenancefundsChart.vue 并使用即可;

 

小贴士:

百度Echarts官网:https://echarts.apache.org/examples/zh/index.html

html中的调色与透明度:https://www.cnblogs.com/jindao3691/p/16093404.html

vue中随机数、随机数数组过滤器方法以及在methods中调用:https://www.cnblogs.com/jindao3691/p/16122622.html

vue组件-echarts圆环图以及legend多列展示 和 legend分页展示:https://www.cnblogs.com/jindao3691/p/16093592.html

 

每天进步一点点,点滴记录,积少成多。

以此做个记录,

如有不足之处还望多多留言指教!

posted @ 2022-04-02 18:29  金刀3691  阅读(1730)  评论(0编辑  收藏  举报