圆形进度条显示超过100%

5
我制作了一个类似于这篇文章的环形图表:https://medium.com/@pppped/how-to-code-a-responsive-circular-percentage-chart-with-svg-and-css-3632f8cd7705。但是,我也尝试在其中显示超过100%的值(该图表显示本月消费与上月消费的比较,有时需要显示值大于100%的情况)。我尝试添加另一个圆并对第一个圆使用不透明度,但效果不佳。我希望它看起来像这样:enter image description here
<svg viewBox="0 0 36 36" class="circular-chart cons">
  <path class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />
  <path class="circle-round" stroke-dasharray="100 100" 
        style="opacity: 0.9;" d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" />
  <path class="circle-round" stroke-dasharray="19 100" d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" />

  <text x="18" y="20.35" class="percentage cons-fill">119%</text>
</svg>

.circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3.8;
}
.circle-round{
  fill: none;
  stroke-width: 2.8;
  stroke-linecap: round;
  animation: progress 1s ease-out forwards;
}
.circular-chart.cons .circle-round {
  stroke: $cons;
}
@keyframes progress {
  0% {
    stroke-dasharray: 0 100;
  }
}
.cons-fill {
  fill: $cons;
}

1
嗨Jakub,欢迎来到stackoverflow :) 包含与您问题相关的代码是必要的,这样我们才知道如何帮助您。您可以在此处查看有关问题所需的内容[here] (https://stackoverflow.com/help/how-to-ask)。此外,请将范围限制为每个帖子1个问题。还有,请问“超过100%”是什么意思? - soulshined
嗨,soulshined,抱歉。我已经添加了代码并删除了第二个问题。 - Jakubbb1337
好的,看起来很不错。我不确定你是在谈论文本还是想要像重复加载器之类的东西(它只是无限循环)。我试着找了一下,没有看到重复的问题,所以如果到周六还没有人回答,我会尝试回答。所以,为了澄清,你想要一个无限循环样式的加载器像这个,这实际上是一样的吗?你想要一个分层进度条?没有JavaScript? - soulshined
没有无限循环的加载器。只是静态比较两个值以显示百分比。如果需要JS,我愿意听取建议。我现在考虑添加一条带阴影的小线,如果值超过100%,但到目前为止我还没有成功。感谢您对该主题的关注。 - Jakubbb1337
坦率地说,在这里不适合使用 循环 进度条。它们并不适用于超过100%的值。条形图将是更好的选择。 - Paulie_D
@Jakubbb1337 我将编辑您的问题标题,以更好地反映内容。这将有助于 SEO 关键词的优化。如果答案对您有帮助,请通过单击其中一个旁边的复选标记接受其中之一。 - soulshined
2个回答

4
考虑一种解决方案-在不同的圆上使用两个动画。 两个动画的开始都是在单击svg画布之后启动的begin="svg1.click"。 首先,第一个动画id="an_red"工作,将一个圆圈涂成红色,花费1秒钟dur="1s"。 在第一个动画id="an_red"完成一次完整的旋转后,打开第二个动画id="an_green",该动画为红色圆形填充动画的10个周期涂上整个绿色圆形。 请阅读下面的代码注释。

.circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3.8;
}
.circle-red{
  fill: none;
  stroke-width: 2.8;
  stroke-linecap: round; 
  stroke:red;
  stroke-dasharray:0 100;
}
.circle-green{
  fill:none;
  stroke: yellowgreen;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray:0 100;   
}

#txt1 {
text-anchor:middle;
dominant-baseline:central;
font-size:6px;
fill:dodgerblue;
}
<svg id="svg1" width="80vw" height="80vh" viewBox="0 0 36 36" opacity="1" class="circular-chart cons">
<g id="gr1">  
  <!-- Gray circle  -->
   <path  class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />
  
   
   <path class="circle-red"    
        style="opacity: 0.5;" d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" >
    <!-- Red circle rotation animation    -->
   <animate
   id="an_red"
   attributeName="stroke-dasharray"
   dur="1s"
   values="0 100;100 0"
   begin="svg1.click"
   end="an_green.end-1s"
   repeatCount="indefinite"
   
   restart="whenNotActive" />
  </path>      
 <circle class="circle-green"   
        cx="17.8155" cy="17.8155" r="14" >
  <!-- Green circle rotation animation -->
      <animate
     id="an_green"
  attributeName="stroke-dasharray"
  begin="svg1.click+1s"
  dur="10s"
  values="0 100; 100 0"
  repeatCount="1"
  
  restart="whenNotActive"/>
    </circle> 
   <text id="txt1" x="50%" y="50%"  >Click me
      <!-- Text fade animation -->
 <animate attributeName="opacity" begin="svg1.click" dur="1s" to="0" fill="freeze" restart="whenNotActive" />
   </text>  
 </g>   
     <animate xlink:href="#svg1" attributeName="opacity" values="1;0" begin="an_green.end" dur="1s" fill="freeze" />
</svg>

更新

考虑选项,当圆圈相互叠放时

底部圆圈负责显示填充量达到100%的动画效果
一个颜色更亮的上部圆圈负责填充其余19%。

当第一个、下部圆圈的动画效果结束时,该圆圈的动画效果开始。

  <!-- Animation filling a dark red circle by 19% -->
    <animate 
     id="an_dark_red"
     attributeName="stroke-dasharray"
     begin="an_red.end"
     dur="1s"
     values="0 100;19 81"
     fill="freeze"
     restart="whenNotActive"  />

.circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3;
}
.circle-round{
  fill: none;
  stroke-width: 3;
  
  stroke-linecap: round;
  stroke-dasharray:0 100; 
  }
 #txt1 {
text-anchor:middle;
dominant-baseline:central;
font-size:8px;
fill:red;
opacity:0;
}
<svg id="svg1" height="80vh" viewBox="0 0 36 36" class="circular-chart cons" >
   <!-- gray circle background -->
  <path class="circle-bg"  class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />

 <path id="red" class="circle-round" stroke="#FFB5B5"
      
         d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" > 
 
 <!-- Animation filling the red circle 100% -->
 <animate
   id="an_red"
   attributeName="stroke-dasharray"
   begin="svg1.click"
   dur="4s"
   values="0 100;100 0"
   fill="freeze"
   repeatCount="1"
   restart="whenNotActive"/>
   </path>  
   
  <path id="dark_red"  class="circle-round"  stroke="red" 
        stroke-dasharray="0 100" 
        d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" >
   
   <!-- Animation filling a dark red circle by 19% -->
 <animate 
  id="an_dark_red"
  attributeName="stroke-dasharray"
  begin="an_red.end"
  dur="1s"
  values="0 100;19 81"
  fill="freeze"
  restart="whenNotActive"  />
  </path> 
   
    <text id="txt1" x="50%" y="50%"  >119%
      <!-- The appearance of the text -->
 <animate attributeName="opacity" begin="an_dark_red.end" dur="1s" to="1" fill="freeze" restart="whenNotActive" />
   </text>  
 
</svg>

使用CSS动画来实现进度达到119%的选项

#svg1 {
 opacity:1;
 height:90vh;
 animation: hide 1s ease-out 7s forwards;
 } 
 
 @keyframes hide {
  100% {
    opacity: 0;
  }
} 
 .circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3;
}
.circle-round{
  fill: none;
  stroke-width: 3;
    stroke-linecap: round;
  stroke-dasharray:0 100; 
  } 
  
  #red {
  animation: progress 4s ease-out forwards;
  }
  
  @keyframes progress {
  100% {
    stroke-dasharray: 100 0;
  }
} 

#dark_red {
animation: progress2 1s ease-out 3.9s forwards;
}  

@keyframes progress2 {
  100% {
    stroke-dasharray: 19 81;
  }
} 
  
 #txt1 {
text-anchor:middle;
dominant-baseline:central;
font-size:8px;
fill:red;
opacity:0; 
animation: text_an 2s ease-out 5.1s forwards;
}   

@keyframes text_an {
  100% {
    opacity: 1;
  }
}
<svg id="svg1" height="30vh" viewBox="0 0 36 36" class="circular-chart cons" >
   <!-- gray circle background -->
  <path class="circle-bg"  class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />

 <path id="red" class="circle-round" stroke="#FFB5B5"
      
         d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" > 
  
   </path>  
   
  <path id="dark_red"  class="circle-round"  stroke="red" 
        stroke-dasharray="0 100" 
        d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" >
    
  </path> 
   
    <text id="txt1" x="50%" y="50%"  >119%  </text>   
      
 
</svg>

CSS动画选项,进度条等于175%

#svg1 {
 opacity:1;
 animation: hide 3s ease-out 10s forwards;
 } 
 
 @keyframes hide {
  100% {
    opacity: 0;
  }
} 
 .circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3;
}
.circle-round{
  fill: none;
  stroke-width: 3;
    stroke-linecap: round;
  stroke-dasharray:0 100; 
  } 
  
  #red {
  animation: progress 4s ease-out forwards;
  }
  
  @keyframes progress {
  100% {
    stroke-dasharray: 100 0;
  }
} 

#dark_red {
animation: progress2 3s ease-out 3.9s forwards;
}  

@keyframes progress2 {
  100% {
    stroke-dasharray: 75 25;
  }
} 
  
 #txt1 {
text-anchor:middle;
dominant-baseline:central;
font-size:8px;
fill:#CB5CCB;
opacity:0; 
animation: text_an 2s ease-out 7s forwards;
}   

@keyframes text_an {
  100% {
    opacity: 1;
  }
}
<svg id="svg1" height="80vh" viewBox="0 0 36 36" class="circular-chart cons" >
   <!-- gray circle background -->
  <path class="circle-bg"  class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />

 <path id="red" class="circle-round" stroke="#CBAACB"
      
         d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" > 
  
   </path>  
   
  <path id="dark_red"  class="circle-round"  stroke="#CB5CCB" 
        stroke-dasharray="0 100" 
        d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0" >
    
  </path> 
   
    <text id="txt1" x="50%" y="50%"  >175%  </text>   
      
 
</svg>

注意:

CSS动画选项适用于包括Edge在内的所有现代浏览器。


非常感谢您的反馈。非常好。查看smil工作在除了EdgeIE之外的所有地方都可以。 - Alexandr_TT
1
我应该补充说明它适用于新的Edge浏览器(基于Chromium),但仍处于测试阶段。就用户界面而言,我非常喜欢它。 - soulshined
1
@soulshined 添加了 CSS 动画的示例。适用于所有现代浏览器,包括 Edge。 - Alexandr_TT

3
问题在于,除非您扩展路径,否则无法超过完整圆圈。我同意这不是显示这些值的最佳工具,但您可以像这样做:

:root{
  --cons: #00ff00;
  --atime: 1s;
}
.shade{
  fill: none;
  stroke: #002200;
  stroke-width: 2.8;
  /*stroke-linecap: round;*/
  animation: sprogress var(--atime) ease-out forwards;
}
.circle-bg {
  fill: none;
  stroke: #ddd;
  stroke-width: 3.8;
}
.circle-round{
  fill: none;
  stroke-width: 2.8;
  stroke-linecap: round;
  animation: progress var(--atime) ease-out forwards;
}
.circular-chart.cons .circle-round {
  stroke: var(--cons);
}
@keyframes sprogress {
  0% {
    stroke-dasharray: 0 0 4 146;
  }
}
@keyframes progress {
  0% {
    stroke-dasharray: 0 150;
  }
}
.cons-fill {
  fill: var(--cons);
  font-size: 30%;
}
<svg viewBox="0 0 36 36" class="circular-chart cons" height="100vh">
  <path class="circle-bg" d="M18 2.0845
        a 15.9155 15.9155 0 0 1 0 31.831
        a 15.9155 15.9155 0 0 1 0 -31.831" />
  <path class="circle-round" stroke-dasharray="119 31" d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0
        a 15.9155 15.9155 0 0 1 -31.831 0 " />
  <path class="shade" stroke-dasharray="0 115 4 31" 
        style="opacity: 0.9;" d="M33.9155 18
        a 15.9155 15.9155 0 0 1 -31.831 0
        a 15.9155 15.9155 0 0 1 31.831 0
        a 15.9155 15.9155 0 0 1 -31.831 0                         " />

  <text x="18" y="20.35" class="percentage cons-fill">119%</text>
</svg>

这个想法是路径现在有150个单位。为了标记路径的位置,您需要一个带有类shade的路径。如果您需要超过150个单位,请添加更多的a元素,然后计算需要哪些值的stroke-dasharray
顺便说一下,如果您取消注释shade类中的stroke-linecap,您将获得一个有趣的效果,因为两端都将被显示,而不管stroke-dasharray的设置如何。 编辑评论后:
首先,需要注意的是原始代码中的技巧是周长为100。因此,每个弧有50个单位。关于stroke-dasharray属性,您可以给它一对破折号和间隔值。如果这些值的总和等于弧的周长,您就可以轻松控制破折号的位置和长度。在shade路径的情况下,您可以从0 0 4 146(无破折号,无间隔,4个单位的破折号,146个单位的间隔)动画到0 115 4 31(无破折号,115个单位的间隔,4个单位的破折号,31个单位的间隔)。这样,破折号始终有4个单位,结束位置在115 + 4 = 119个单位处。这并不完美,因为起始值(破折号的末尾)不是0,而是4。效果几乎不可察觉,但可以通过两种方法进行修复:
  • 使用破折号的起点标记百分比(从0 0 4 1460 119 4 27)。
  • 在开头扩展shade路径,然后更改stroke-dasharray值。例如,如果在开头添加另一个弧线,则周长将为200,值将从0 46 4 150变为0 165 4 31

1
(+) 可能需要更详细地解释几对属性值的工作原理。-“stroke-dasharray: 0 0 4 146” - Alexandr_TT
1
我在答案中添加了该策略的解释。希望有所帮助。 - vqf
谢谢。我明白可见部分仍保持常数长度 4,在动画过程中改变其前后间隙,我们旋转该部分。 - Alexandr_TT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接