Прогресс-бар СВГ

у меня есть требование, где мне нужно динамически загружать 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" width="79.36px" height="93.844px" 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. Вот это код.

#progressMove {
  transition: .3s y;
}
#progressMove:hover {
  y: 60%;
}
<svg id="kenseoProgress" width="79.36px" height="93.844px" 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" width="79.36px" height="93.844px" mask="url(#bubbleKenseo)" height="100">
    <rect id="progressMove" x="0" y="0%" width="100%" height="100%" fill="blue" stroke="black" />
  </g>
</svg>

итак, проблемы, которые у меня есть:

  • невозможно сохранить границу SVG
  • независимо от цвета, который я добавляю, имеет какую-то непрозрачность, которую я не могу удалить.
  • редактировать: совместимость с браузером: IE11+, chrome, safari и firefox

PS: Я не хочу использовать SMIL анимации.

4 ответов


во-первых, вы хотите использовать clip-path, или выберите mask заливка на белый цвет для 100% непрозрачности:mask используется в качестве альфа-канала в оттенках серого, а красный цвет заливки вызывает изменение непрозрачности.

что касается штриха, вы хотите добавить его как отдельный элемент, на который не влияет отсечение. (вы, вероятно, можете повторно использовать путь с defs и use, Я просто скопировал его здесь)

#progressMove {
  transition: .3s y;
}
#progressMove:hover {
  y: 60%;
}
<svg id="kenseoProgress" width="79.36px" height="93.844px" 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-width="1" 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" width="79.36px" height="93.844px" clip-path="url(#bubbleKenseo)" height="100">
    <rect id="progressMove" x="0" y="0%" width="100%" height="100%" fill="blue" stroke="black" />
  </g>
</svg>

РЕШЕНИЕ CHROME / SAFARI

использование свойства CSS transform и counter-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" width="79.36px" height="93.844px" viewBox="0 0 79.36 93.844">
    <pattern id="progress" x="0" y="0" width="79.36" height="93.844" patternUnits="userSpaceOnUse">
      <rect id="progressMove" x="0" y="0" width="100%" height="100%" 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>

Примечание:

будет обновляться, если я могу дать лучшее решение для покрытия браузера поддержка.


EDIT:

на основе Persijn ответ, вам также придется изменить цвет фона на цвет его родителя.

весь компонент будет figure элемент, к сожалению, символ в spritesheet будет использоваться только для предоставления пути и фона.

Примечание: 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>

тесты:

  • Chrome 53
  • в IE10
  • Edge
  • FireFox 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>

SVG с шаблоном и переходом y:

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" width="79.36px" height="93.844px" viewBox="0 0 79.36 93.844">
    <pattern id="pattern1"
           x="0" y="0" width="79.36" height="93.844"
           patternUnits="userSpaceOnUse" >

      <rect id="fillshape" x="0" y="0" width="100%" height="200%" 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...

вот решение, которое использует div за формой svg. Недостатком этого решения является то, что форма 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" width="100" height="100" 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>

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" width="79.36px" height="93.844px" 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" width="79.36px" height="93.844px" mask="url(#bubbleKenseo)" height="100" stroke-width="0">
      <rect id="progressMove" x="0" y="0" width="100%" height="100%" fill="blue" stroke="black" style="transform: translateY(100%);" />
    </g>
    <g id="prObject" x="0" y="0" width="79.36px" height="93.844px" height="100" fill-opacity="0" stroke="black" stroke-width="0.5px">
      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#mypath"></use>
    </g>
  </svg>
</body>

</html>