Vue3 + ECharts 实现多层极坐标环形图

发布于:2025-05-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

一、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 = 1231
    const 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>
  


网站公告

今日签到

点亮在社区的每一天
去签到