component-svg圆环进度百分比图(顶部文本,中间图形,底部文本)

svg图形展示

vue3 + ts

图表顶部自定义编辑文本,圆环可自定义背景与颜色,底部为图表文本。

在ant 或echarts中也有类似的圆环进度

父组件调用

顶部自定义为文本描述信息

对应进度可计算为百分比,圆环宽度,进度以及背景颜色,百分比字体颜色,百分比底部文本,以及进度圆环开始渲染位置。

javascript 复制代码
<template>
  <div class="content-all">
    <div class="content-top-text">echarts文本描述</div>
    <!-- echarts整体-(图表+底部文本)  -->
    <div class="echarts-all">
       <!-- echarts整体-图表 -->
      <div class="echarts-chart">
        <HDemoSon
          :progress="75"
          :strokeWidth="12"
          :progressColor="'#4CAF50'"
          :backgroundColor="'#FFF'"
          :percentageTextColor="'#4CAF50'"
          :title="'完成率'"
          direction="top"
        />
      </div>
      <!-- echarts整体-底部文本 -->
      <div class="echarts-bottom-text">累计</div>  
    </div>
  </div>
</template>

<script setup>
import HDemoSon from './HDemoSon.vue'
</script>

<style scoped lang="scss">

@function vh($px) {
  @return calc($px / 1080) * 100vh;
}
// 整体样式
.content-all {
  padding: 2px;
  height: 100%;
  width: 100%;
  background-color: #0C6299;
}

// 顶部数据统计
.content-top-text{
  width: 100%;
  height: 20px;
  background-color: blueviolet;
}

// echarts整体-(图表+底部文本)
.echarts-all {
  width: 70px; 
  height: 90px;
  background-color: red;
}

// echarts整体-图表
.echarts-chart {
  width: 70px;
  height: 70px;
}


// echarts整体-底部文本
.echarts-bottom-text {
  background-color: aqua;
  height: 20px;
  width: 100%;
  line-height: 20px;
  text-align: center;
  font-weight: 500;
  font-size: 10px;
}
</style>

子组件-进度svg图形

图表正常接收数据进行渲染,底部自定义文本信息或样式

javascript 复制代码
<!-- 进度圆环组件 -->
<template>
  <div class="progress-ring">
    <!-- SVG -->
    <svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
      <!-- 背景圆环 -->
      <circle
        :stroke="backgroundColor"
        :stroke-width="strokeWidth"
        fill="transparent"
        :r="radius"
        cx="50"
        cy="50"
      />
      <!-- 进度圆环 -->
      <circle
        :stroke="progressColor"
        :stroke-width="strokeWidth"
        fill="transparent"
        :r="radius"
        cx="50"
        cy="50"
        :stroke-dasharray="circumference"
        :stroke-dashoffset="strokeDashoffset"
        :transform="rotationTransform"
      />
    </svg>
    <!-- 文本内容 -->
    <div class="progress-ring-text-container">
      <div class="progress-ring-percentage" :style="percentageStyle">
        {{ percentageText }}
      </div>
       <div v-if="title" class="progress-ring-title">
        {{ title }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  progress: {
    type: Number,
    default: 0,
    validator: (v) => v >= 0 && v <= 100
  },
  // 圆环宽度   
  strokeWidth: {
    type: Number,
  },
  // 进度圆环背景颜色  
  progressColor: {
    type: String,
  },
  // 进度圆环背景颜色   
  backgroundColor: {
    type: String,
  },
  // 字体   
  title: {
    type: String,
    default: ''
  },
  // 百分比字体颜色
  percentageTextColor: {
    type: String,
  },
  // 进度圆环开始绘制方向  
  direction: {
    type: String,
    default: 'top',
    validator: (v) => ['top', 'right', 'bottom', 'left'].includes(v)
  }
})

// 半径基于 viewBox 100x100
const radius = computed(() => 50 - props.strokeWidth / 2)
const circumference = computed(() => 2 * Math.PI * radius.value)

const strokeDashoffset = computed(() => {
  const p = Math.max(0, Math.min(100, props.progress))
  return circumference.value - (p / 100) * circumference.value
})

const rotationTransform = computed(() => {
  const map = { top: -90, right: 0, bottom: 90, left: 180 }
  return `rotate(${map[props.direction]} 50 50)`
})

// 百分比颜色
const percentageStyle = computed(() => ({
  color: props.percentageTextColor,
}))

// 百分比计算
const percentageText = computed(() => `${Math.round(props.progress)}%`)
</script>

<style scoped lang="scss">

@function vh($px) {
  @return calc($px / 1080) * 100vh;
}
/* 整体样式 */
.progress-ring {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.progress-ring svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

/* 中心文本内容 */
.progress-ring-text-container {
  position: relative;
  text-align: center;
  font-family: Arial, sans-serif;
  line-height: 1.2;
  z-index: 1;
}

/* 百分比 */
.progress-ring-percentage{
    font-size: 16px;
}

/* 文本 */
.progress-ring-title{
    font-size: 12px;
    color: #666;
}
</style>
相关推荐
燕山石头19 小时前
jeecg统一异常处理根据不同模块返回指定响应信息
前端
PyHaVolask19 小时前
CSRF跨站请求伪造
android·前端·csrf
程序员海军19 小时前
我的2025:做项目、跑副业、见人、奔波、搬家、维权、再回上海
前端·程序员·年终总结
我来整一篇20 小时前
[Razor] ASP.NET Core MVC 前端组件快速使用总结
前端·asp.net·mvc
P7Dreamer20 小时前
微信小程序处理Range分片视频播放问题:前端调试全记录
前端·微信小程序
RedHeartWWW20 小时前
初识next-auth,和在实际应用中的几个基本场景(本文以v5为例,v4和v5的差别主要是在个别显式配置和api,有兴趣的同学可以看官网教程学习)
前端·next.js
C_心欲无痕20 小时前
前端页面中,如何让用户回到上次阅读的位置
前端
C_心欲无痕20 小时前
前端本地开发构建和更新的过程
前端
Mintopia20 小时前
🌱 一个小而美的核心团队能创造出哪些奇迹?
前端·人工智能·团队管理
蚊道人20 小时前
Nuxt 4 学习文档
前端·vue.js