美文网首页
Vue + echarts 环形图组件案例分享

Vue + echarts 环形图组件案例分享

作者: 小小Bug你别跑 | 来源:发表于2022-08-12 14:01 被阅读0次
    环形图

    今天的下来需求要求封装两个echarts环形图的组件儿,没有设计图自己搞样式和配色
    下面我们先看父级页面代码,这里边吧数据和颜色都作为参数穿到组件中,以保持组件的复用率。这里面我查找了三套配色冷暖色作为对比图使用,另外一套默认配色。

    <template>
      <div class="as_container">
        <div> 
          <PieAnnular id="ecahrtId" :colorList='coolColorSystem' :dataCon="data"/>
        </div>
        <div> 
          <PieAnnular id="ecahrtIds" :colorList='carmColorSystem' :dataCon="data"/>
        </div>
        <div>
          <Pie id="echartsId" :colorList='colorList' :dataList="data"/>
        </div>
      </div>
    </template>
    
    <script>
    import PieAnnular from './pieAnnular/pie.vue'
    import Pie from './pieAnnular/index.vue'
    export default {
      components:{
        PieAnnular,
        Pie
      },
      data(){
        return{
          coolColorSystem:['#61368f','#284797','#116bb1','#15a8aa','#1da563','#79bc52'],//冷色系
          carmColorSystem:['#efea37','#ea4f17','#ec892b','#e71519','#f0a929','#f36d83'],//暖色系
          // 通用色系10种
          colorList:['#46a6ff','#42cece','#59ce7c','#fbd643','#f36d83','#9d69e6','#5d5ed2','#4e5b8f','#ffad6a','#ffadcf'],
          data:[ //模拟数据
              {value:335, name:'直接访问'},
              {value:310, name:'邮件营销'},
              {value:234, name:'联盟广告'},
              {value:135, name:'视频广告'},
              {value:548, name:'搜索引擎'},
              {value:335, name:'直接访问2'}
          ]
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .as_container{
      display: flex;
      flex-wrap: wrap;
      width: 100%;
      height: 100%;
      &>div{
        width: 50%;
        height: 400px;
      }
    }
    </style>
    

    下面我们来看第一个组件


    对比环形图

    这个是这个组件两种配色效果,根据需求主要做对比使用,也是由于需求我们这里是用了title来做的中心园内的文字,不关联图、只作为固定数值展示。

    <template>
      <div :id="ids" style=" width: 100%;height: 100%;background-color: #19233A;" />
    </template>
    
    <script>
    export default {
      name: 'Annular',
      props: {
        id: {
          type: String,
          default: () => {
            return ''
          }
        },
        dataCon: {
          type: Array,
          default: () => {
            return []
          }
        },
        colorList: {
          type: Array,
          default: () => {
            return []
          }
        }
      },
      data() {
        return {
          ids: this.id,
          myChart: ''
        }
      },
      mounted() {
        this.$nextTick(() => {
          this.drawPie()
        })
      },
      methods: {
        imgBase() {
          this.myChart.getDataURL()
        },
        // 性别比例环形图
        drawPie() {
          const arrName = []
          const arrValue = []
          this.dataCon.forEach((v, i) => {
            arrName.push(v.name)
            arrValue.push(v.value)
          })
          // 基于准备好的dom,初始化echarts实例
          this.myChart = this.$echarts.init(document.getElementById(this.ids))
          // 绘制图表
    
          var rich = {
            name: {
              color: 'rgba(236, 238, 242, 1)',
              fontSize: 12,
              padding: [10, 10, 0, 10],
              fontWeight: '400'
            },
            hr: {
              borderColor: 'rgba(63, 127, 255, 0.2)',
              width: '100%',
              borderWidth: 1,
              height: 0
            },
            cir: {
              fontSize: 18,
              padding: [10, 10, 0, 10]
            }
          }
    
          var colorList = this.colorList ? this.colorList : ['#8618F8', '#07BFFE', '#15BAFF', '#23FFEA', '#13FF9F']
          this.myChart.setOption({
            backgroundColor: '#042a4e',
            title: {
            text: '99',  
            x: "34.5%",
            y: "center",
            textAlign:'center',  //x不为'center'时我们需要使用其保持文字相对图的居中
                textStyle: {
                    color: "rgb(255,255,255)",
                    fontSize: 24,
                    width:'30px',
                    align: "center"
                },
            },
            tooltip: {
                trigger: 'item',
            },
            legend: {
              orient: 'vertical',
              trigger: 'item',
              show: true,
              top:'center',
              right:'4%',
              icon: 'circle',
              itemWidth: 14,
              textStyle: {
                color: '#ECEEF2',
                fontSize: 14,
                lineHeight: this.dataCon.length > 2 ? 14 : 20,
                rich: {
                  percent: {
                    color: '#fff',
                    fontSize: 14,
                    padding: [0, 24, 0, 0]
                  }
                }
              },
              formatter: params => {
                return (
                  '{title|' + params + '} : {value|' + this.dataCon.find((item) => {
                    return item.name == params
                  }).value + '%' + '}'
                )
              }
            },
            // -----环形图---------------------------------------
            series: [
              {
                itemStyle: {
                  normal: {
                    color: function(params) {
                      return colorList[params.dataIndex]
                    }
                  }
                },
                type: 'pie',
                radius: ['40%', '60%'],
                hoverAnimation: false,
                center: ['35.5%', '50%'],
                label: {
                  normal: {
                    position: 'inner',
                    formatter: params => {
                      return ''
                    },
                    rich: rich
                  }
                },
                data: this.dataCon
              },
              {
                itemStyle: {
                  normal: {
                    opacity: 0.5,
                    color: function(params) {
                      return colorList[params.dataIndex]
                    }
                  }
                },
                type: 'pie',
                radius: ['30%', '40%'],
                hoverAnimation: false,
                center: ['35.5%', '50%'],
                label: {
                  normal: {
                    position: 'inner',
                    formatter: params => {
                      return ''
                    },
                    rich: rich
                  }
                },
                data: this.dataCon
              },
              // 外层白盘---------------------------------------------------
              {
                itemStyle: {
                  normal: {
                    color: 'rgba(63, 127, 255, 1)',
                    shadowBlur: 6,
                    shadowColor: 'rgba(63, 127, 255, 1)',
                    shadowOffsetX: 0,
                    shadowOffsetY: 0
                  }
                },
                type: 'pie',
                silent: true, // 取消高亮
                radius: ['68%', '69%'],
                center: ['35.5%', '50%'],
                hoverAnimation: false, // 取消动画效果
                data: this.dataCon,
                label: {
                  normal: {
                    show: false,
                    position: 'inner',
                    formatter: params => {
                      return (
                        '{percent|' + params.percent.toFixed(0) + '%}'
                      )
                    },
                    rich: rich
                  }
                },
                z: -1
              }
            ]
          })
          setTimeout(() => {
            window.onresize = () => {
              this.myChart.resize()
            }
            const resizeObserver = new ResizeObserver(entries => {
              this.myChart.resize()
            })
            resizeObserver.observe(document.getElementById(this.ids))
          }, 800)
        }
      }
    }
    </script>
    
    

    下面我们来看第二个组件


    通用环形图

    这个环形图是通用的环形图组件,不做对比的情况下大部分是使用这个,主要用于数据的展示、不存在太多交互甚至连图例和hover效果也隐藏掉了、然后这个里面我们加了一个暂无数据的判断。

    <template>
      <div style="width: 100%;height: 100%;background-color: #19233A;">
        <div v-show="dataList.length > 0" :id="ids" style="background-color: #19233A;height: 100%;" />
        <div v-show="dataList.length == 0" style="background-color: #19233A;position: relative;height: 100%;">
          <img src="@/XXX/XXX/noData.png" alt="" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:160px;">
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Annular',
      props: {
        id: {
          type: String,
          default: () => {
            return ''
          }
        },
        dataList: {
          type: Array,
          default: () => {
            return []
          }
        },
        colorList: {
          type: Array,
          default: () => {
            return []
          }
        }
      },
      data() {
        return {
          ids: this.id,
          myChart: ''
        }
      },
      watch: {
        dataList(newValue, oldValue) {
          this.$nextTick(() => {
            this.drawPie()
          })
        }
      },
      mounted() {
        this.$nextTick(() => {
          this.drawPie()
        })
      },
      methods: {
        drawPie() {
          if (this.dataList.length == 0) {
            return
          }
          // 指定图表的配置项和数据
          const chartDom = document.getElementById(this.id)
          // 有的话就获取已有echarts实例的DOM节点。
          this.myChart = this.$echarts.getInstanceByDom(chartDom)
          if (this.myChart == null) { // 如果不存在,就进行初始化
            this.myChart = this.$echarts.init(chartDom)
          }
          // 绘制图表
          var rich = {
            name: {
              color: 'rgba(236, 238, 242, 1)',
              fontSize: 12,
              padding: [10, 10, 0, 10],
              fontWeight: '400'
            },
            hr: {
              borderColor: 'rgba(63, 127, 255, 0.2)',
              width: '100%',
              borderWidth: 1,
              height: 1
            },
            cir: {
              fontSize: 18,
              padding: [0, 10, 0, 10]
            }
          }
    
          var colorList = this.colorList ? this.colorList : ['#8618F8', '#07BFFE', '#15BAFF', '#23FFEA', '#13FF9F', 'red']
          this.myChart.setOption({
            title: {
            text: '99', 
            x: "center",
            y: "center",
            //与上一个组件对比,当x为'center'时不使用textAlign。也可以保持
                textStyle: {
                    color: "rgb(50,197,233)",
                    fontSize: 24,
                    align: "center"
                }
            },
            backgroundColor: '#042a4e',
            // tooltip: {
            //     trigger: 'item',
            //     formatter: ''
            // },
            series: [{
              name: '',
              type: 'pie',
              center: ['50%', '50%'],
              animation: false,
              radius: this.id != 'annularCon' ? ['38%', '50%'] : ['24%', '36%'],
              clockwise: true,
              avoidLabelOverlap: true,
              silent: true,
              hoverOffset: 0,
              itemStyle: {
                color: function(params) {
                  return colorList[params.dataIndex]
                }
              },
              label: {
                show: true,
                position: 'outside',
                formatter: '{a|{b}:{d}%}\n{hr|}',
                rich: {
                  hr: {
                    borderRadius: 3,
                    borderColor: 'rgba(63, 127, 255, 0.5)',
                    borderWidth: 1,
                    width: 3,
                    height: 3,
                    padding: [2, 3, 0, -11]
                  },
                  a: {
                    padding: [-50, -70, -40, -80]
                  }
                }
              },
              labelLine: {
                smooth: true,
                length: 25,
                length2: 65,
                lineStyle: {
                  width: 1,
                  color: 'rgba(63, 127, 255, 0.5)'
                }
              },
              data: this.dataList
            }, {
              itemStyle: {
                opacity: 0.5,
                color: function(params) {
                  return colorList[params.dataIndex]
                }
              },
              animation: false,
              type: 'pie',
              radius: this.id != 'annularCon' ? ['32%', '44%'] : ['22%', '34%'],
              avoidLabelOverlap: true,
              center: ['50%', '50%'],
              label: {
                position: 'inner',
                formatter: params => {
                  return ''
                },
                rich: rich
              },
              data: this.dataList
            },
            // 外层白盘---------------------------------------------------
            {
              itemStyle: {
                color: 'rgba(63, 127, 255, 0.4)',
                shadowBlur: 6,
                shadowColor: 'rgba(63, 127, 255, 0.4)',
                shadowOffsetX: 0,
                shadowOffsetY: 0
              },
              type: 'pie',
              silent: true, // 取消高亮
              radius: this.id != 'annularCon' ? ['55%', '56.5%'] : ['40%', '41.5%'],
              center: ['50%', '50%'],
              data: this.dataList,
              animation: false,
              avoidLabelOverlap: true,
              label: {
                show: false,
                position: 'inner',
                formatter: params => {
                  return (
                    '{percent|' + params.percent.toFixed(0) + '%}'
                  )
                },
                rich: rich
              },
              z: -1
            },
            {
              name: '内圈',
              type: 'pie',
              radius: this.id != 'annularCon' ? ['32%', '28%'] : ['22%', '18%'],
              center: ['50%', '50%'],
              animation: false,
              itemStyle: {
                color: 'rgba(20, 56, 140, 0.3)'
              },
              emphasis: {
                itemStyle: {
                  color: 'rgba(20, 56, 140, 0.3)'
                }
              },
              labelLine: {
                show: false
              },
              data: [{
                value: 1
              }],
              zlevel: 1
            }]
          })
          this.$nextTick(() => {
            window.onresize = () => {
              this.myChart.resize()
            }
            const resizeObserver = new ResizeObserver(entries => {
              this.myChart.resize()
            })
            resizeObserver.observe(document.getElementById(this.ids))
          })
        }
      }
    }
    </script>
    

    这两个组件属于大圈套小圈实现的样式效果,样式上它们存在很多的相同之处,其实他们也可以封装成一个组件,只不过可能会多一些参数的传递,这个大家就按照现实需求来决定吧!

    为避免侵权各位亲借鉴的时候注意不要完全照搬谢谢...

    相关文章

      网友评论

          本文标题:Vue + echarts 环形图组件案例分享

          本文链接:https://www.haomeiwen.com/subject/kpbxgrtx.html