Search code examples
ionic-frameworksvgionic3progress-bar

Is there a way to make a circular progress bar like the one in the image in ionic 3?


I am trying to make a circular progress bar like the one in the image attached. I have looked at the following ones:

They are ones that provide a semi-circle but what I am looking at is not a semi-circle but more than that.

I would like to know if there is anything around in the way I need it and if not, how can I modify the current ones available to what I am looking for.

enter image description here


Solution

  • Like this?

    Set the dial colours by changing the dialColours array. You can also set the dial size (dialRadius) and thickness (dialThickness).

    Set the progress by passing a percentage to setProgress().

    const dialColours = [
      { colour: 'rebeccapurple', range: 6.5 },  // range is percentage of dial range
      { colour: 'pink',          range: 6 },    // values should add to 100 (%)
      { colour: 'chocolate',     range: 10 },
      { colour: 'dodgerblue',    range: 15 },
      { colour: 'limegreen',     range: 18 },
      { colour: 'gold',          range: 16 },
      { colour: 'tomato',        range: 28.5 }
    ];
    
    function initialiseDial()
    {
      const dialAngleRange = 270;  // deg
      const dialRadius = 60;
      const dialThickness = 20;
      const dial = document.getElementById("dial");
    
      // Add the colour sections to the dial
      var colourStartAngle = 90 + dialAngleRange / 2;
      const r = dialRadius + dialThickness;
      var start = polar2cartesian(colourStartAngle, r);
      dialColours.forEach(col => {
        // Find third point point of colour sector triangle
        let endAngle = colourStartAngle - (col.range * dialAngleRange / 100);
        let end = polar2cartesian(endAngle, r);
        // Create the sector using an SVG polygon
        const path = document.createElementNS(dial.namespaceURI, "path");
        path.setAttribute("d", ['M', 0, 0,
                                'L', start.x, start.y, 
                                'A', r, r, 0, 1, 1, end.x, end.y,
                                'Z'].join(' '));
        path.setAttribute("fill", col.colour);
        dial.appendChild(path);
        // Step to next colour angle
        colourStartAngle = endAngle;
        start = end;
      });
    
      // Initialise the progress bar
      const progressBar = document.getElementById("progress-bar");
      start = polar2cartesian(90 + dialAngleRange / 2, dialRadius);
      const end = polar2cartesian(90 - dialAngleRange / 2, dialRadius);
      progressBar.setAttribute("d", ['M', start.x, start.y, 
                                     'A', dialRadius, dialRadius, 0, 1, 1, end.x, end.y].join(' '));
      progressBar.setAttribute("stroke-width", dialThickness);
      
    }
    
    
    function deg2rad(deg) {
      return deg * Math.PI / 180;
    }
    
    function polar2cartesian(angle, radius) {
      return {
        x: radius * Math.cos(deg2rad(angle)),
        y: radius * -Math.sin(deg2rad(angle))
      }
    }
    
    
    // Set the profress about
    function setProgress(percentage) {
      const progressBar = document.getElementById("progress-bar");
      progressBar.setAttribute("stroke-dasharray", [percentage, 100].join(' '));
    }
    
    
    initialiseDial();
    
    setProgress(100);
    svg {
      width: 200px;
    }
    <svg viewBox="0 0 160 160">
      <defs>
        <mask id="dial-mask">
          <path id="progress-bar" d="" fill="none" stroke="white" pathLength="100"/>
        </mask>
      </defs>
      <!--image href="https://i.sstatic.net/9aLrI.png" width="175" height="152"/-->
      <g id="dial" transform="translate(80, 80)" mask="url(#dial-mask)">
      </g>
    </svg>