饼图(一)
前言
版本用的是5,跟4配置有差别
一、饼图
- 有间隔的环形图1,如图所示
有几个点要注意(从内到外,为环形1-3):
- 实现逻辑,由三个环形图实现
- 间隔实现,由于环形1和环形2是贴合的,所以没办法用设置border模拟间隔。这里采用添加数据,设置颜色transparent模拟间隔 缺点:
- 隐藏图例至保留一个时,会留有一个间隔,如上图
- 且占比需要手动计算,所以隐藏图例时不会重新生成占比,需要手动监听图例事件去重新计算占比。 主要代码:
const legendArr = [ { name: '图例1' }, { name: '图例2' }, { name: '图例3' }]
// 数据格式
const list = [ {"number":60,"areaName":"图例1"}, {"number":90,"areaName":"图例2"}, {"number":150,"areaName":"图例3"}]
// 转换后的数据
const data = []
if (list.length === 0) {
// 无数据
legendArr.forEach((item, i) => {
data.push({
name: item.name,
value: 0,
isRealData: true, // 标识,与装饰圆环做区分
isRealIndex: i
})
})
}
const total = list.reduce((a, b) => a + b.number, 0)
list.forEach((item, i) => {
data.push({
name: item.areaName,
value: item.number,
isRealData: true, // 标识,与装饰圆环做区分
isRealIndex: i
})
data.push({
// 透明扇形作分割
name: item.areaName,
value: total / 50,
labelLine: {
show: false,
lineStyle: {
color: 'transparent'
}
},
itemStyle: {
color: 'transparent'
}
})
})
const series = [{ // 外层装饰 type: 'pie', emphasis: { scale: false }, center: ['50%', '40%'],
radius: ['55%', '65%'],
label: {
show: false
},
itemStyle: {
color: new this.$echarts.graphic.RadialGradient(0.5, 0.5, 1, [
{
offset: 0,
color: 'rgba(17, 24, 43, 0)'
},
{
offset: 0.5,
color: 'rgba(0, 187, 255, 0.3)'
},
{
offset: 1,
color: 'rgba(17, 24, 43, 0)'
}
], false)
},
data: [1]
},
{
// 实际展示数据
type: 'pie',
emphasis: {
scale: false
},
center: ['50%', '40%'],
radius: ['40%', '48%'],
label: {
show: true,
fontSize: 20,
padding: [0, 40, 0, 0],
formatter: params => {
// 自定义的字段isRealData
if (params.data?.isRealData) {
return `
{color${params.data.isRealIndex}|${this.getPercent(params.data.value, total)}}
${params.value}次 ${params.name}
`
}
return ''
},
rich: {
color0: {
color: echartColors[0][0],
fontSize: 20,
lineHeight: 36
},
color1: {
color: echartColors[1][0],
fontSize: 20,
lineHeight: 36
},
color2: {
color: echartColors[1][0],
fontSize: 20,
lineHeight: 36
}
}
},
labelLine: {
show: false,
length: 0
},
data
},
{
// 内层半透明
type: 'pie',
emphasis: {
scale: false
},
center: ['50%', '40%'],
radius: ['28%', '40%'],
itemStyle: {
color: (params) => {
return params.dataIndex % 2 === 0 ? echartColors[params.dataIndex / 2][1] : 'transparent'
}
},
label: {
show: false
},
data
}
]
const options = {
color: echartColors.map(item => item[0]),
tooltip: {
trigger: 'item',
padding: 0,
borderColor: 'transparent',
formatter: params => {
if (params.data?.isRealData) {
return `
<div style="
margin: 0;
padding: 5px;
font-size: 20px;
">
<div style="margin: 5px 0;">${params.name}</div>
<div style="margin: 5px 0;">
次数:
<span style="color: ${echartColors[params.data.isRealIndex][0]};">${params.value}</span>
</div>
<div style="margin: 5px 0;">占比:${this.getPercent(params.value, total)}</div>
</div>
`
}
return ``
},
borderColor: 'rgba(255, 255, 255, 0.30196078431372547)',
borderWidth: 2,
backgroundColor: 'rgba(60, 61, 86, 1)',
textStyle: {
color: '#fff'
}
},
legend: {
bottom: '10%',
icon: 'rect',
itemGap: 40,
textStyle: {
color: '#fff',
fontSize: 20
}
},
grid: {
left: 0,
top: 60,
right: 50,
bottom: 45,
containLabel: true
},
xAxis: [
{
show: false
}
],
series
}
- 有间隔的环形图2,如图所示
注意:
- 两个环形间隔由border实现,只有背景色固定且不渐变不透明才能用这种方式,如果不是则用环形图1的形式实现
- 这里占比之类就不用向环形图1那样手动计算并监听图例事件
/**
* 数据格式
* { 单位名称:次数 }
*/
const dataObj = {companyone: 60, companytwo: 15, companyfour: 10, companythree: 50}
const data = []
Object.keys(dataObj).forEach((name, i) => {
data.push({
name,
value: dataObj[name],
isRealData: true, // 标识,与装饰圆环做区分
isRealIndex: i
})
})
const series = [{ name: '入廊单位统计', type: 'pie', center: ['40%', '50%'],
radius: ['60%', '68%'],
label: {
position: 'center',
fontSize: 20,
formatter: params => {
// 自定义的字段isRealData
if (params.data?.isRealData) {
// return `{d|${getPercent(params.value, total)}}\n{c|${params.value}次}\n{b|${params.name}}`
return `{d|${params.percent}%}\n{c|${params.value}次}\n{b|${params.name}}`
}
return ``
},
rich: {
b: {
fontSize: 18
},
c: {
fontSize: 18,
lineHeight: 28
},
d: {
fontSize: 18,
fontWeight: 'bold'
}
}
},
data: data.map((item, i) => {
return {
...item,
itemStyle: {
color: item.isRealData ? new this.$echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: echartColors[item.isRealIndex][0]
},
{
offset: 1,
color: echartColors[item.isRealIndex][1]
}
]) : 'transparent',
borderColor: 'rgba(20, 22, 44, 1)',
borderWidth: 4
}
}
})
},
{
// 内层半透明
type: 'pie',
emphasis: {
scale: false
},
center: ['40%', '50%'],
radius: ['45%', '55%'],
itemStyle: {
color: 'rgba(54, 60, 69, 1)',
borderColor: 'rgba(20, 22, 44, 1)',
borderWidth: 4
},
label: {
show: false
},
data: data
}
]
const options = {
color: echartColors.map(item => item[0]),
tooltip: {
trigger: 'item',
formatter: params => {
if (params.data?.isRealData) {
// ${getPercent(params.value, total)
return `
<div style="
margin: 0;
padding: 5px;
font-size: 20px;
">
<div style="margin: 5px 0;">${params.name}</div>
<div style="margin: 5px 0;">
次数:
<span style="color: ${echartColors[params.data.isRealIndex][0]};">${params.value}</span>
</div>
<div style="margin: 5px 0;">占比:${params.percent}%</div>
</div>
`
}
return ``
},
// '{a} <br/>{b}: {c}次 ({d}%)',
...this.$utils.defaultTooltipParams
},
legend: {
right: '0',
top: 'middle',
icon: 'rect',
orient: 'vertical',
itemGap: 40,
textStyle: {
color: '#fff'
},
formatter: name => {
const obj = data.find(item => item.name === name)
return `${name} ${obj?.value || 0}次`
}
},
series
}