Vue + ECharts 实现多层极坐标环形图
一、ECharts 配置详解
1.1标题配置(中间文本)
title: {text: `老人总数\n${total}`,left: 'center',top: '42%',textStyle: {color: '#fff',fontSize: 16,fontWeight: 'normal',lineHeight: 24,}
}
1.2 极坐标系核心配置
polar: {radius: [40, 100], // 内环到外环半径范围center: ['50%', '50%']
}
radius
控制环的内外大小(40~100 像素)
center
控制图表居中
angleAxis: {max: 100,clockwise: false,show: false
}
max: 100
:表示角度按百分比计算(满圈)
clockwise: false
:环形从逆时针方向开始
show: false
:不显示角度坐标轴
radiusAxis: {type: 'category',show: false
}
极坐标的径向轴(环的分布方向)设为类别型,也隐藏。
1.3 系列数据渲染(关键)
series: list.map((item, index) => ({type: 'bar',data: [item.percent],coordinateSystem: 'polar',roundCap: true,barWidth: 10,z: index,itemStyle: {color: item.color},startAngle: index === 0 ? 0 : list[index - 1].percent,endAngle: item.percent
}))
type: 'bar'
+coordinateSystem: 'polar'
=> 每一层为一个环形柱条
data: [item.percent]
:控制每一层占据的弧度(百分比)
roundCap: true
:每个环条两端为圆头
barWidth: 10
:每层环的宽度(10px)
z: index
:设置层级顺序,后渲染的在上层
color
:颜色来自数据项自定义
二、注意事项以及解释
什么是“极坐标系”?
我们平时看到的柱状图、折线图,都是用的“直角坐标系” —— 横轴是 X,竖轴是 Y。
而 极坐标系 是用“圆形”来表示数据的 —— 数据不是向上长,而是沿着圆圈展开。
你可以想象一块披萨:每一块就是一个“角度”,表示一个数据的占比
极坐标的两个坐标轴:
angleAxis
—— 控制“角度”,也就是每个环条占多少角度angleAxis: {max: 100,clockwise: false,show: false, } max: 100:表示整个圆为100%,用百分比来画。clockwise: false:从左边开始画环,并逆时针转。show: false:这个角度轴不显示出来(不然就一堆数字很丑)。
radiusAxis
—— 控制“半径”,决定这一条环是在哪一圈radiusAxis: {type: 'category',show: false, } type: 'category':代表我这里每一层圆都是“分类”用的,不是数值。show: false:同样不显示。
想象多层披萨:
第一层是小圈圈(内层)
第二层是稍微大一点的圈(外层)
第三层更大...
这就是“多层圆”,而
radiusAxis
决定它是在第几层。怎么形成“多层圆”?
series: list.map((item, index) => ({type: 'bar',data: [item.percent],coordinateSystem: 'polar',roundCap: true,barWidth: 10,z: index,itemStyle: { color: item.color }, })) list.map(...):我们有 4 种老人类型,就会画 4 个“圆圈圈”。data: [item.percent]:这个值决定这个甜甜圈占圆圈的多少角度(比如 30%)。barWidth: 10:每个圈的“厚度”是 10 像素。 为什么每一圈自动往外排? 因为 echarts 极坐标下,每画一个柱子,它会自动从里往外排列,每个 series 代表一层: series 0 → 最里面那圈 series 1 → 第二圈 series 2 → 第三圈 series 3 → 最外圈
3、全部代码
<template><div class="elderly-chart"><div ref="chartRef" class="chart"></div><div class="info"><div v-for="(item, index) in reversedList" :key="index" class="info-item"><div class="info-color" :style="{ backgroundColor: item.color }"></div><div class="info-text">{{ item.name }}</div><div class="info-number">{{ item.number }}人</div><div class="info-percent">{{ item.percent }}%</div></div></div></div></template><script setup>import { ref, onMounted } from 'vue'import * as echarts from 'echarts'const chartRef = ref(null)const list = [{ name: '介助', number: 344, percent: 27, color: '#F2E93D' },{ name: '介护', number: 304, percent: 37, color: '#4CE1D6' },{ name: '失能', number: 98, percent: 7, color: '#C3A6FD' },{ name: '自理', number: 485, percent: 93, color: '#2F7CF6' },]const reversedList = ref([...list].reverse())onMounted(() => {const chart = echarts.init(chartRef.value)const total = 1231const option = {backgroundColor: 'transparent',title: {text: `老人总数\n${total}`,left: 'center',top: '42%',textStyle: {color: '#fff',fontSize: 16,fontWeight: 'normal',lineHeight: 24,},},polar: {radius: [40, 100], // 保持内外半径范围不变center: ['50%', '50%'],},angleAxis: {max: 100, // 设置最大值为100,角度为百分比clockwise: false,show: false,},radiusAxis: {type: 'category',show: false,},series: list.map((item, index) => ({type: 'bar',data: [item.percent],coordinateSystem: 'polar',roundCap: true,barWidth: 10,z: index, // 控制层级itemStyle: {color: item.color,},// 动态设置每个环的占据角度startAngle: index === 0 ? 0 : list[index - 1].percent, // 每个环的起始角度endAngle: item.percent, // 每个环的结束角度})),}chart.setOption(option)window.addEventListener('resize', () => {chart.resize()})})</script><style scoped>.elderly-chart {display: flex;align-items: center;justify-content: center;background: #0B1E38;padding: 20px;}.chart {width: 300px;height: 300px;position: relative;}.info {margin-left: 30px;display: flex;flex-direction: column;justify-content: center;}.info-item {display: flex;align-items: center;margin-bottom: 12px;}.info-color {width: 10px;height: 10px;border-radius: 50%;margin-right: 8px;}.info-text {color: #fff;width: 50px;}.info-number {color: #fff;margin-left: 10px;width: 60px;}.info-percent {color: #fff;margin-left: 10px;}</style>