使用SVG制作带动画的环形图(Doughnut Graph)遇阻求助
优化的带动画SVG环形图实现方案
你当前用多个<circle>叠加的实现容易出现分段重叠、位置偏移的问题,更高效的方式是通过精准控制stroke-dashoffset和stroke-dasharray的累加关系来实现分段环形,同时修正SVG元素的基础位置错误。以下是两种目标环形图的完整实现:
核心优化要点
- 统一所有环形元素的圆心坐标(修正你代码中
donut-hole的cx/cy错误) - 用
stroke-dashoffset的累加值控制分段起始位置,避免重叠 - 动画从
stroke-dasharray: 0 100过渡到目标分段长度,保证平滑展开 - 两种环形图分别通过调整分段颜色、动画节奏和环形样式实现
第一种环形图(对应目标样式1)
.svg-item { width: 50%; animation: donutfade 1s forwards; opacity: 0; } .donut-ring { stroke: #F4E2E2; } .donut-segment-1 { stroke: #EA0001; animation: donut1 3s forwards; } .donut-segment-2 { stroke: #0066FF; animation: donut2 3s forwards; } .donut-segment-3 { stroke: #FF66B2; animation: donut3 3s forwards; } /* 整体淡入动画 */ @keyframes donutfade { to { opacity: 1; } } /* 分段动画:从0展开到目标长度 */ @keyframes donut1 { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 17 83; } } @keyframes donut2 { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 33 67; } } @keyframes donut3 { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 50 50; } }
<div class="svg-item"> <svg width="100%" viewBox="0 0 44 44" class="donut"> <!-- 修正圆心位置,与其他环形保持一致 --> <circle class="donut-hole" cx="22" cy="22" r="15.915" fill="transparent"></circle> <!-- 基础环形背景 --> <circle class="donut-ring" cx="22" cy="22" r="15.915" fill="none" stroke-width="12"></circle> <!-- 分段1:起始偏移0,占比17% --> <circle class="donut-segment donut-segment-1" cx="22" cy="22" r="15.915" fill="none" stroke-width="12" stroke-dasharray="17 83" stroke-dashoffset="0"></circle> <!-- 分段2:起始偏移17(等于分段1的长度),占比33% --> <circle class="donut-segment donut-segment-2" cx="22" cy="22" r="15.915" fill="none" stroke-width="12" stroke-dasharray="33 67" stroke-dashoffset="17"></circle> <!-- 分段3:起始偏移17+33=50,占比50% --> <circle class="donut-segment donut-segment-3" cx="22" cy="22" r="15.915" fill="none" stroke-width="12" stroke-dasharray="50 50" stroke-dashoffset="50"></circle> </svg> </div>
第二种环形图(对应目标样式2,带中间文本+错峰动画)
.svg-item-2 { width: 50%; animation: donutfade 1s forwards; opacity: 0; } .donut-ring-2 { stroke: #E8F4F8; } .donut-segment-a { stroke: #00C896; animation: donutA 2.5s forwards 0.2s; stroke-dasharray: 25 75; stroke-dashoffset: 0; } .donut-segment-b { stroke: #FF9F43; animation: donutB 2.5s forwards 0.4s; stroke-dasharray: 40 60; stroke-dashoffset: 25; } .donut-segment-c { stroke: #FF6B6B; animation: donutC 2.5s forwards 0.6s; stroke-dasharray: 35 65; stroke-dashoffset: 65; } .donut-text { font-size: 8px; font-family: sans-serif; text-anchor: middle; dominant-baseline: middle; fill: #333; } @keyframes donutA { 0% { stroke-dasharray: 0 100; } } @keyframes donutB { 0% { stroke-dasharray: 0 100; } } @keyframes donutC { 0% { stroke-dasharray: 0 100; } }
<div class="svg-item-2"> <svg width="100%" viewBox="0 0 44 44" class="donut"> <circle cx="22" cy="22" r="15.915" fill="transparent"></circle> <circle class="donut-ring-2" cx="22" cy="22" r="15.915" fill="none" stroke-width="10"></circle> <circle class="donut-segment-a" cx="22" cy="22" r="15.915" fill="none" stroke-width="10"></circle> <circle class="donut-segment-b" cx="22" cy="22" r="15.915" fill="none" stroke-width="10"></circle> <circle class="donut-segment-c" cx="22" cy="22" r="15.915" fill="none" stroke-width="10"></circle> <!-- 中间文本 --> <text class="donut-text" x="22" y="22">100%</text> </svg> </div>
关键说明
- 所有环形元素的
cx/cy必须统一为SVG画布中心(22,22),避免位置偏移 stroke-dashoffset的数值等于前面所有分段的长度之和,确保分段依次排列不重叠- 动画中
stroke-dasharray从0 100过渡到目标值,实现从无到有的展开效果 - 第二种环形图通过添加延迟动画、调整stroke-width和中间文本,匹配不同视觉需求
内容的提问来源于stack exchange,提问作者Kenken
相关产品推荐
相关产品推荐

