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>
相关推荐
_阿南_1 小时前
项目中新增给AI制定的代码规范
前端·程序员
名字还没想好☜2 小时前
React 实现暗黑模式切换:localStorage 持久化、SSR 首屏闪烁与跟随系统主题
前端·javascript·react.js·ecmascript·react·next.js
console.log('npc')3 小时前
Git 冲突与 AI 协助指南
前端·人工智能·git·大模型
爱学堂IT分享4 小时前
Cesium可视化系统实战课程-Cesium教程学习
前端
糖墨夕4 小时前
理解大语言模型:Agent 的“大脑”
前端·agent
Rain的Java大神之路5 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
cpolar技术支持5 小时前
浏览器也能跑本地 AI:用 Transformers.js + WebGPU 做一个最小推理 Demo,cpolar 给同事远程体验
前端·ai·cpolar·webgpu·transformers.js
计算机魔术师6 小时前
OpenAI 发布 GPT-6 Astra:多项基准刷新纪录, cybersecurity 能力达 Critical 阈值
前端
xy34536 小时前
Axure9.0中继器遮罩实现方法
前端·ui·html·axure·原型·产品设计
风骏时光牛马7 小时前
智能任务自动化协同AI工作流
前端