SVG 进度条

Posted

技术标签:

【中文标题】SVG 进度条【英文标题】:SVG progress bar 【发布时间】:2016-11-21 02:19:25 【问题描述】:

我有一个需求,我需要动态加载 js 文件并通过 SVG 图标显示加载文件的进度。 SVG 图标将充当进度条,从下到上线性填充颜色。

这里是codepen

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"   viewBox="0 0 79.36 93.844">

  <path fill="transparent" stroke="black" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
</svg>

我打算让这个图标独立,这样我只会动态传递百分比值。

我以某种方式能够完成动画,但无法保留 svg 的边框或轮廓。这是code。

#progressMove 
  transition: .3s y;

#progressMove:hover 
  y: 60%;
<svg id="kenseoProgress"   viewBox="0 0 79.36 93.844">
  <defs>
    <mask id="bubbleKenseo">
      <path fill="red" stroke="black" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
    </mask>
  </defs>
  <g x="0" y="0"   mask="url(#bubbleKenseo)" >
    <rect id="progressMove" x="0" y="0%"   fill="blue" stroke="black" />
  </g>
</svg>

所以,我遇到的问题是:

无法维护 SVG 的边框 无论我添加什么颜色,都有某种我无法去除的不透明度。 编辑:浏览器兼容性:IE11+、chrome、safari 和 firefox

PS:我不想使用 SMIL 动画。

【问题讨论】:

【参考方案1】:

带有图案和 y 过渡的 SVG:

svg:hover pattern #fillshape 
  y: 0%;

pattern #fillshape 
  transition: y 1s;
  y: 100%;
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"   viewBox="0 0 79.36 93.844">
    <pattern id="pattern1"
           x="0" y="0"  
           patternUnits="userSpaceOnUse" >

      <rect id="fillshape" x="0" y="0"   stroke="none" fill="purple" />

  </pattern>
  <path fill="url(#pattern1)" stroke="black" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
</svg>

现在这在 Firefox 或 Edge 中不起作用。它不会将 x 和 y 识别为 CSS 属性...

这是一个在 svg 形状后面使用 div 的解决方案。 这个解决方案的缺点是 svg 形状有背景,例如。如果您只想要形状,则必须将形状的背景颜色与页面背景的颜色相匹配。

svg 
  position: relative;
 
.spesial 
  width: 90px;
  height: 0px;
  display: inline-block;
  background-color: purple;
  margin-left: -100px;
  transition: height 1s;

svg:hover + .spesial 
  height: 100px;
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"   viewBox="0 0 75 90">
  <path stroke="black" fill="gray" d="M-10,-10 100,-10 100,100 -10,100 -10,-10  50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
</svg>
<div class="spesial">
</div>

【讨论】:

谢谢,我可以使用以下解决方案,因为它支持跨浏览器。但我希望也许我可以将 div 保留在 svg 本身中。因为我使用use标签将此svg用作spritesheet。【参考方案2】:

铬/Safari 解决方案

使用 CSS 属性 transformcounter-increment 可以实现填充和数量递增。

jsFiddle

代码片段

for (var i = 0; i < 100; i++) 
  setTimeout(function() 
    $(".progress-container p").append("<span>");
  , i * 20);
pattern #progressMove 
  transform: translateY(100%);
  color: purple;
  animation: progressBar 2s steps(100, end) forwards;

@keyframes progressBar 
  to 
    transform: translateY(0);
  

.progress-container 
  margin: 0;
  display: inline-block;
  position: relative;
  counter-reset: progress;

.progress-container figcaption 
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-40%, -50%);

.progress-container p 
  margin: 0;
  font-weight: bold;

.progress-container span 
  counter-increment: progress;

.progress-container p::after 
  content: counter(progress)"%";
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<figure class="progress-container">
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"   viewBox="0 0 79.36 93.844">
    <pattern id="progress" x="0" y="0"   patternUnits="userSpaceOnUse">
      <rect id="progressMove" x="0" y="0"   stroke="none" fill="currentColor" />
    </pattern>
    <path fill="url(#progress)" stroke="#000" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
  </svg>
  <figcaption>
    <p>

    </p>
  </figcaption>
</figure>

注意:

如果我能提供更好的解决方案来涵盖浏览器支持,我会更新。


编辑:

根据Persijn 的回答,您还必须将背景颜色更改为其父级的颜色。

整个组件将是figure 元素,遗憾的是精灵表中的符号将仅用于提供路径和背景。

注意:此版本中删除了 jQuery。

jsFiddle

for (var i = 0; i < 100; i++) 
  setTimeout(function() 
    var progressCounter = document.querySelector(".progress__counter"),
      number = document.createElement("span");
    progressCounter.appendChild(number);
  , i * 20);
#spritesheet 
  display: none;

.icon 
  display: inline-block;
  width: 1em;
  height: 1em;

.icon-bubble 
  font-size: 7em;
  color: white;

.progress-container 
  margin: 0;
  display: inline-block;
  position: relative;
  counter-reset: progress;
  overflow: hidden;
  line-height: 0;

.progress__inner 
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;

.progress__fill 
  background-color: purple;
  height: 100%;
  transform: translateY(100%);
  animation: progressFill 2s steps(100, end) forwards;

@keyframes progressFill 
  to 
    transform: translateY(0);
  

.progress__counter 
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-40%, -50%);
  margin: 0;
  font-weight: bold;

.progress__counter span 
  counter-increment: progress;

.progress__counter::after 
  content: counter(progress)"%";
<figure class="progress-container">
  <svg class="icon icon-bubble">
    <use xlink:href="#icon-bubble"></use>
  </svg>
  <figcaption class="progress__inner">
    <div class="progress__fill"></div>
    <p class="progress__counter"></p>
  </figcaption>
</figure>

<svg id="spritesheet">
  <symbol id="icon-bubble" viewBox="0 0 79.36 93.844">
    <title>Loading Bubble</title>
    <path id="bubble-cover" fill="currentColor" stroke="#000" d="M-10,-10 100,-10 100,100 -10,100 -10,-10  50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
  </symbol>
</svg>

测试:

铬 53 IE10 边缘 火狐 47 ios 10 Safari

游乐场

jsFiddle

for (var i = 0; i < 100; i++) 
  setTimeout(function() 
    var progressCounter = document.querySelector(".progress__counter"),
      number = document.createElement("span");
    progressCounter.appendChild(number);
  , i * 20);
#spritesheet 
  display: none;

.icon 
  display: inline-block;
  width: 1em;
  height: 1em;

.icon-bubble 
  font-size: 7em;
  color: white;

.progress-container 
  margin: 0;
  display: inline-block;
  position: relative;
  counter-reset: progress;
  overflow: hidden;
  line-height: 0;

.progress__inner 
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;

.progress__fill 
  background-color: purple;
  height: 100%;
  transform: translateY(100%);
  animation: progressFill 2s steps(100, end) forwards, progressFillColor 100ms linear 2s forwards;
  position: relative;

@keyframes progressFill 
  to 
    transform: translateY(0);
  

@keyframes progressFillColor 
  to 
    background-color: green;
  

.progress__counter 
  position: absolute;
  top: 40%;
  transform: translateY(-40%);
  text-align: center;
  width: 100%;
  margin: 0;
  font-weight: bold;
  animation: progressCounter 100ms linear 1s forwards;

.progress__counter span 
  counter-increment: progress;

.progress__counter::after 
  content: counter(progress)"%";
  animation: progressCounterCompleted 1s linear 2s forwards;

@keyframes progressCounter 
  to 
    color: white;
  

/* Chrome Only*/

@keyframes progressCounterCompleted 
  33% 
    content: "File(s)";
  
  66% 
    content: "Uploaded";
  
  100% 
    content: "Successfully!";
  
<figure class="progress-container">
  <svg class="icon icon-bubble">
    <use xlink:href="#icon-bubble"></use>
  </svg>
  <figcaption class="progress__inner">
    <div class="progress__fill"></div>
    <p class="progress__counter"></p>
  </figcaption>
</figure>

<svg id="spritesheet">
  <symbol id="icon-bubble" viewBox="0 0 79.36 93.844">
    <title>Loading Bubble</title>
    <path id="bubble-cover" fill="currentColor" stroke="#000" d="M-10,-10 100,-10 100,100 -10,100 -10,-10  50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
  </symbol>
</svg>

【讨论】:

是的,考虑到 IE11+、chrome、safari 和 firefox,我需要浏览器支持。将在我的帖子中更新。【参考方案3】:

var prObject = document.getElementById("prObject"),
  prDom = document.getElementById("progressMove"),
  prValue = 0;

prObject.onmouseenter = function() 
  prDom.setAttribute('class', 'prHover')
;
prObject.onmouseleave = function() 
  prDom.removeAttribute('class')
;

/*prDom.setAttributeNS(null, 'y', '0');*/

var cTimer = setInterval(function() 
  prValue += 20.6;
  prDom.style.transform = "translateY(" + [100 - Math.min(prValue, 100)] + "%)";

  if (prValue >= 100) 
    clearInterval(cTimer);
  
, 450);
#progressMove 
  transition: transform 0.20s linear;

#progressMove.prHover 
  transform: translateY(40%) !important;
<!DOCTYPE html>
<html>

<head>
  <title></title>
</head>

<body>
  <svg id="kenseoProgress"   viewBox="0 0 79.36 93.844">
    <defs>
      <path id="mypath" fill="white" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
      <mask id="bubbleKenseo">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#mypath"></use>
      </mask>
    </defs>
    <g x="0" y="0"   mask="url(#bubbleKenseo)"  stroke->
      <rect id="progressMove" x="0" y="0"   fill="blue" stroke="black" style="transform: translateY(100%);" />
    </g>
    <g id="prObject" x="0" y="0"    fill-opacity="0" stroke="black" stroke->
      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#mypath"></use>
    </g>
  </svg>
</body>

</html>

【讨论】:

【参考方案4】:

首先,您想使用clip-path,或将mask 填充设置为白色以获得100% 的不透明度:mask 用作灰度 Alpha 通道,红色填充颜色会导致不透明度发生变化。

至于笔画,您想将其添加为不受剪裁影响的单独元素。 (您可能可以重复使用 defsuse 的路径,我只是在这里复制粘贴)

#progressMove 
  transition: .3s y;

#progressMove:hover 
  y: 60%;
<svg id="kenseoProgress"   viewBox="0 0 79.36 93.844">
  <defs>
    <clipPath id="bubbleKenseo">
      <path d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
    </clipPath>
  </defs>
  <path stroke="black" stroke- fill="transparent" d="M50,2C30-4,8,7,2,28c-6,20,5,42,26,48h0l-4,15l33-18c0-0,0-0,1-0l0-0l-0-0c8-4,15-12,17-22C83,30,71,8,50,2z" />
  <g x="0" y="0"   clip-path="url(#bubbleKenseo)" >
    <rect id="progressMove" x="0" y="0%"   fill="blue" stroke="black" />
  </g>
</svg>

【讨论】:

这很好用!我对现有代码做了最少的更改。谢谢。您能否解释一下为什么我看到我在问题中提到的应用颜色不透明? 我看不出这个解决方案与我的答案中的第一个解决方案有何不同,这只适用于 chrome @Mr_Green 蒙版用作灰度 Alpha 通道,其中黑色 = 0% 不透明度,白色 = 100%。您使用的红色被转换为中深灰色,因此它产生 50-60% 的不透明度。

以上是关于SVG 进度条的主要内容,如果未能解决你的问题,请参考以下文章

svg实现圆环进度条

角圆形 svg 进度条渐变笔画

用svg实现一个环形进度条

html SVG环形进度条 - 7

html SVG环形进度条 - 4

html SVG环形进度条 - 2