Search code examples
javascripthtmlsvg

SVG Circular Progress bar to complete progress by defined value


I am creating one SVG Circular Progress bar. It is working, But when i pass some value, Hence based on that value it is not completing the progress.

Below is the code, Which i tried so far

    window.addEventListener("load", function
(event){
  let progressbar = document.querySelectorAll('.progress-bar');
  progressbar.forEach(function(circle){
    let degree = 0;
    let percentage=0;
    var targetDegree = parseInt(circle.getAttribute('data-degree'));
      var element = circle.children;
       var childElem = element.item(1);
      let color = circle.getAttribute('data-color'); 
       let number = document.querySelector('.text');
       let childNumber = document.querySelector('.totalfilling'); 
       var interval = setInterval(function(){ 
         degree+=1;
         if(percentage >= 1){ 
         clearInterval(interval);
           return; 
         } 
         percentage = degree/targetDegree ;
         var progressCalc = 848 - (848 * targetDegree) / 100;
     
      //childElem.style = `stroke-dashoffset: calc(${progressCalc})`;
        childElem.style.background = `conic-gradient( 
         ${color} ${percentage*100}%, #222 0%)`;
         number.innerHTML = degree;
         number.style.color =  color;
        childNumber.innerHTML = '<h5>'+targetDegree+'</h5>'
      },50)
  });
});
body {
        width: 100%;
        height: 100vh;
        margin: 0;
        padding: 0;
      }
      .center {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgb(25, 25, 50);
      }
      .progress {
        width: 400px;
        height: 400px;
        background: rgb(255, 255, 255);
        border-radius: 5mm;
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
      }
      circle {
        fill: none;
      }
      svg {
        transform: rotate(90deg);
      }
      circle:nth-child(1) {
        stroke: rgb(240, 248, 255);
        stroke-width: 12px;
      }
      circle:nth-child(2) {
        stroke: rgb(78, 91, 205);
        stroke-dasharray: 848;
        stroke-linecap: round;
        stroke-width: 16px;
        animation: progress 1s ease;
      }
      @keyframes progress {
        from {
          stroke-dashoffset: 848;
        }
      }
      .text {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-family: poppins;
        font-size: 60px;
        color: rgb(78, 91, 205);
        font-weight: 500;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
      }
      .text span {
        font-size: 14px;
        color: rgb(78, 91, 205);
      }
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Circular Progress Bar</title>
  </head>
  <body>
    <div class="center">
      <div class="progress">
        <svg class="progress-bar" data-degree="75" data-color="#0b60e9" width="300" height="300">
          <circle class="progress-circle" cx="150" cy="150" r="135"></circle>
          <circle class="progress-circle" cx="150" cy="150" r="135"></circle>
           <div class="text">
          75
          <span>Completed</span>
        </div>
        <div class="totalfilling">
                    <h5>1000</h5>
                </div>
        </svg>
       
      </div>
    </div>
  </body>
</html>

In the above code i tried to use some max value, So the progress bar should complete based on the max value. But this logic is not working.

Need help.


Solution

  • So, basically if I good understanding your task, stroke doesn’t fill circle to value, right?

    If so, try change way how you calculate percentage.

    percentage = degree / 100;
    

    And then in relation to that adjust stroke-dashoffset

    Thing is that interval has to stop when the degree reaches the targetDegree

    if (degree >= targetDegree) {
      clearInterval(interval);
      return;
    }
    

        window.addEventListener("load", function (event) {
        let progressbar = document.querySelectorAll('.progress-bar');
        progressbar.forEach(function (circle) {
          let degree = 0;
          let percentage = 0;
          const targetDegree = parseInt(circle.getAttribute('data-degree'));
          const maxDegrees = 100;
          const circumference = 848;
          const element = circle.children;
          const childElem = element.item(1);
          const color = circle.getAttribute('data-color');
          const number = document.querySelector('.text');
          const childNumber = document.querySelector('.totalfilling');
    
          var interval = setInterval(function () {
            if (degree >= targetDegree) {
              clearInterval(interval);
              return;
            }
            degree += 1;
            percentage = degree / targetDegree;
            const progressCalc = circumference - (circumference * percentage);
            childElem.style.strokeDashoffset = progressCalc;
            childElem.style.stroke = color;
            number.innerHTML = degree;
            number.style.color = color;
            childNumber.innerHTML = '<h5>' + targetDegree + '</h5>';
          }, 50);
        });
      });
    body {
        width: 100%;
        height: 100vh;
        margin: 0;
        padding: 0;
      }
      .center {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgb(25, 25, 50);
      }
      .progress {
        width: 400px;
        height: 400px;
        background: rgb(255, 255, 255);
        border-radius: 5mm;
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
      }
      circle {
        fill: none;
      }
      svg {
        transform: rotate(-90deg);
      }
      circle:nth-child(1) {
        stroke: rgb(240, 248, 255);
        stroke-width: 12px;
      }
      circle:nth-child(2) {
        stroke: rgb(78, 91, 205);
        stroke-dasharray: 848;
        stroke-linecap: round;
        stroke-width: 16px;
      }
      .text {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-family: poppins;
        font-size: 60px;
        color: rgb(78, 91, 205);
        font-weight: 500;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
      }
      .text span {
        font-size: 14px;
        color: rgb(78, 91, 205);
      }
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Circular Progress Bar</title>
      </head>
      <body>
        <div class="center">
      <div class="progress">
        <svg class="progress-bar" data-degree="135" data-color="#0b60e9" width="300" height="300">
          <circle class="progress-circle" cx="150" cy="150" r="135"></circle>
          <circle class="progress-circle" cx="150" cy="150" r="135"></circle>
        </svg>
        <div class="text">
          75
          <span>Completed</span>
        </div>
        <div class="totalfilling">
          <h5>1000</h5>
        </div>
      </div>
    </div>
      </body>
    </html>