You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为自定义Circular Progress Bar添加跟随进度的圆点

嘿,这个需求很好实现!我们可以借助SVG的<circle>元素做那个跟随进度的圆点,再用一点点JS计算位置就行。下面是具体的修改方案:

第一步:修改HTML,添加圆点元素

在你的SVG里新增一个小圆形,用来做进度末端的圆点:

<div class="storage_counter_holder">
<svg>
<circle cx="50%" cy="50%" r="48.5%"></circle>
<circle cx="50%" cy="50%" r="48.5%"></circle>
<!-- 新增的进度圆点 -->
<circle class="progress-dot" cx="0" cy="0" r="6" fill="#15385f"></circle>
<text x="50%" y="40%" dominant-baseline="middle">5,2/10 TB</text>
<text x="50%" y="55%" dominant-baseline="middle">available storage</text>
</svg>
</div>

第二步:调整CSS,给圆点加基础样式

给圆点补一些样式,重点设置transform-origin为中心,方便后续旋转定位:

.storage_counter_holder svg { 
  fill: none; 
  stroke-width: 4; 
  stroke-dasharray: 534; 
  stroke-linecap: round; 
  width: 100%; 
  height: 100%; 
}
.storage_counter_holder svg circle { 
  transform: rotate(154deg); 
  transform-origin: center; 
}
.storage_counter_holder svg circle:nth-child(1) { 
  stroke-dashoffset: 200; 
  stroke: lightgray; 
}
.storage_counter_holder svg circle:nth-child(2) { 
  stroke-dashoffset: 340; /*calc(440 - (440 * 87) / 100);*/ 
  stroke: #15385f; 
}
.storage_counter_holder svg text { 
  fill: #3D3D3D; 
  text-anchor: middle; 
}
.storage_counter_holder svg text:nth-child(3) { 
  font-size: 24px; 
  font-family: "Regular Fira Sans"; 
}
.storage_counter_holder svg text:nth-child(4) { 
  font-size: 16px; 
  font-family: "Light Fira Sans"; 
}
/* 进度圆点专属样式 */
.storage_counter_holder .progress-dot {
  fill: #15385f; /* 和进度条颜色保持一致 */
  transform-origin: center; /* 以SVG中心为旋转原点 */
}

第三步:用JS计算圆点的动态位置

核心思路是根据进度条的stroke-dashoffset计算已绘制的长度,再转换成角度,最后通过旋转圆点让它精准落在进度末端:

function updateProgressDot() {
  // 获取元素
  const holder = document.querySelector('.storage_counter_holder');
  const progressCircle = holder.querySelector('circle:nth-child(2)');
  const dot = holder.querySelector('.progress-dot');
  
  // 读取环形进度的关键参数(也可以改成CSS变量更灵活)
  const totalLength = 534; // 对应stroke-dasharray的值
  const startAngle = 154; // 对应circle的初始rotate角度
  const circleRadius = '48.5%'; // 环形的半径
  
  // 计算已绘制的进度长度
  const offset = parseFloat(getComputedStyle(progressCircle).strokeDashoffset);
  const drawnLength = totalLength - offset;
  
  // 把长度转换成角度,再加上起始角度得到圆点的旋转角度
  const drawnAngle = (drawnLength / totalLength) * 360;
  const totalRotation = startAngle + drawnAngle;
  
  // 设置圆点的位置和旋转
  dot.setAttribute('cx', `calc(50% + ${circleRadius})`);
  dot.setAttribute('cy', '50%');
  dot.style.transform = `rotate(${totalRotation}deg)`;
}

// 页面加载时初始化圆点位置
updateProgressDot();

动态更新的小提示

如果后续你需要修改进度(比如通过JS改变stroke-dashoffset),只要每次修改完后调用updateProgressDot(),圆点就会自动跟着进度移动啦!

要是想让参数更易维护,还可以把totalLength、startAngle这些值改成CSS变量,比如在.storage_counter_holder里加--total-length: 534;,然后在JS里用getComputedStyle(holder).getPropertyValue('--total-length')读取就行~

内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 12:32:42