Vue + echarts 环形图组件案例分享
2022-08-12 本文已影响0人
小小Bug你别跑
环形图
对比环形图
通用环形图
今天的下来需求要求封装两个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>
这两个组件属于大圈套小圈实现的样式效果,样式上它们存在很多的相同之处,其实他们也可以封装成一个组件,只不过可能会多一些参数的传递,这个大家就按照现实需求来决定吧!
为避免侵权各位亲借鉴的时候注意不要完全照搬谢谢...