Create SVG progress circle

前端 未结 7 1098
再見小時候
再見小時候 2020-12-30 15:34

Anyone know how to create a circle \"progressbar\" in svg? I need to specify the percentage of the circle, så that a color grows in the shape of a cake.

The growing

相关标签:
7条回答
  • 2020-12-30 15:56

    Following is the idea I used to use. With a bit of modification in css and animation tag we can achieve more effects for intuitive user experiences.

    ---SAMPLE CODE----

    .over{
      -webkit-animation: rotator 1.5s ease-in-out infinite;
      stroke-dasharray: 107,38;
    }
    .bag{
      position: absolute;
    }
    @-webkit-keyframes rotator {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    <div class="container">
      <svg class="bag" height="100" width="100">
        <circle  cx="50" cy="50" r="40" stroke="#F8BBD0" stroke-width="3" fill="none">
        </circle>
      </svg>
      <svg class="over" height="100" width="100">
        <circle  cx="50" cy="50" r="40" stroke="#E91E63" stroke-width="3" fill="none" >
          <animate attributeType="CSS" attributeName="stroke-dasharray" from="1,254" to="247,56" dur="5s" repeatCount="indefinite" />
        </circle>
      </svg>
    </div>

    Hope you were looking for something kind of this. :)

    0 讨论(0)
  • 2020-12-30 15:56

    Codepen-Link

    <div class="flex-wrapper">
      <div class="single-chart">
          <svg viewBox="0 0 36 36" class="circular-chart orange">
              <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" stroke-dasharray="30, 100" 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" />
              <text x="18" y="20.35" class="percentage">30%</text>
          </svg>
      </div>
    </div>
    

    CSS Required for this svg circle

    .flex-wrapper {
      display: flex;
      flex-flow: row nowrap;
    }
    
    .single-chart {
      width: 33%;
      justify-content: space-around ;
    }
    
    .circular-chart {
      display: block;
      margin: 10px auto;
      max-width: 80%;
      max-height: 250px;
    }
    
    .circle-bg {
      fill: none;
      stroke: #eee;
      stroke-width: 3.8;
    }
    
    .circle {
      fill: none;
      stroke-width: 2.8;
      stroke-linecap: round;
      animation: progress 1s ease-out forwards;
    }
    
    @keyframes progress {
      0% {
        stroke-dasharray: 0 100;
      }
    }
    
    .circular-chart.orange .circle {
      stroke: #ff9f00;
    }
    
    .percentage {
      fill: #666;
      font-family: sans-serif;
      font-size: 0.5em;
      text-anchor: middle;
    }
    
    
    a {
      font-size: 26px;
    }
    

    .flex-wrapper {
      display: flex;
      flex-flow: row nowrap;
    }
    
    .single-chart {
      width: 33%;
      justify-content: space-around ;
    }
    
    .circular-chart {
      display: block;
      margin: 10px auto;
      max-width: 80%;
      max-height: 250px;
    }
    
    .circle-bg {
      fill: none;
      stroke: #eee;
      stroke-width: 3.8;
    }
    
    .circle {
      fill: none;
      stroke-width: 2.8;
      stroke-linecap: round;
      animation: progress 1s ease-out forwards;
    }
    
    @keyframes progress {
      0% {
        stroke-dasharray: 0 100;
      }
    }
    
    .circular-chart.orange .circle {
      stroke: #ff9f00;
    }
    
    .percentage {
      fill: #666;
      font-family: sans-serif;
      font-size: 0.5em;
      text-anchor: middle;
    }
    
    
    a {
      font-size: 26px;
    }
    <div class="flex-wrapper">
      <div class="single-chart">
          <svg viewBox="0 0 36 36" class="circular-chart orange">
              <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" stroke-dasharray="30, 100" 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" />
              <text x="18" y="20.35" class="percentage">30%</text>
          </svg>
      </div>
    </div>
    
    
    <br>
    <br>
    <br>
    <br>
    <br>
    
    <a href="https://codepen.io/sergiopedercini/">Thanks to sergiopedercini</a>

    0 讨论(0)
  • 2020-12-30 15:58

    Thanks, boldewyn.

    To answer my own question, I found the following solution:

    One can use the following path in template:

    <path id="progress" fill="none" stroke="#ffffff" d="" stroke-width="10"/>
    

    And use this function from Raphael js-framework to update x and y. If total is 100, value is the percentage of progress:

    function updateState (value, total, R) {
        var center;
        var alpha = 360 / total * value,
            a = (90 - alpha) * Math.PI / 180,
            x = 300 + R * Math.cos(a),
            y = 300 - R * Math.sin(a),
            path;
        if (total == value) {
            path = "M"+ 300 +","+ (300 - R) +" A"+ R+","+ R+","+ 0+","+ 1+","+ 1+","+ 299.99+","+ 300 - R;
        } else {
            if(alpha > 180) {
                center = 1;
            } else {
                center = 0;
            }
            path = "M"+ 300+","+ (300 - R) +" A"+ R+","+ R+","+ 0+"," + center +","+ 1+","+ x+","+ y;
        }
        return path;
    }
    

    The returned path variable is the value for the d attribute on the path element.

    This works perfect, if your browser supports SVG Full with the Elliptical Arc command for the path-element. In my case I only have SVG tiny, so this wont work for me :(

    0 讨论(0)
  • 2020-12-30 16:04
    <svg xmlns="http://www.w3.org/2000/svg" width="225" height="225">
        <g>
            <circle cx="112" cy="112" r="95"></circle>
            <path id="path" d="M 112,17 A 95,95 0 0,0 112,17"></path>
        </g>
    </svg>
    <script type="text/javascript">
        function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
            var angleInRadians = angleInDegrees * Math.PI / 180.0;
            var x = centerX + radius * Math.cos(angleInRadians);
            var y = centerY + radius * Math.sin(angleInRadians);
            return [x, y];
        }
        function drawCircle(elm, centerX, centerY, radius, percentage) {
            var angle = (360 * (percentage / 100)) % 360;
            var start = polarToCartesian(centerX, centerY, radius, -90);
            var end = polarToCartesian(centerX, centerY, radius, -(angle + 90));
            var large = percentage < 50 ? 0 : 1;
            var length = (2 * Math.PI * radius) * (percentage / 100);
            console.log(start, end, angle);
            elm.setAttribute('d', 'M ' + start[0] + ',' + start[1] + ' A ' + radius + ',' + radius + ' ' + 0 + ' ' + large + ',' + 0 + ' ' + end[0] + ',' + end[1]);
            elm.setAttribute('stroke-dasharray', length);
            elm.setAttribute('stroke-dashoffset', length);
        }
        drawCircle(document.getElementById('path'), 112, 112, 95, 47);
    </script>
    
    0 讨论(0)
  • 2020-12-30 16:05

    Use this self implemented method in JavaScript for example here percentage=85

    HTML Code:

    <p style="position:absolute;margin-left:95px;margin-top:50px;" id="percentage">0 %</p>  
    <svg style="position:absolute" id="svg_test" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <circle style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);" cx="110" cy="60" r="50" fill="none" stroke="#e4e4e4" stroke-width="2"></circle>
    <path id="svgpath" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);" fill="none" stroke="#16a6b6" d="M60,60 A50,50 0 0,1 160,60" stroke-width="2"></path>
    </svg>
    
    <circle style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);" cx="110" cy="60" r="50" fill="none" stroke="#e4e4e4" stroke-width="2"></circle>
    <path id="svgpath" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);" fill="none" stroke="#16a6b6" d="M60,60 A50,50 0 0,1 160,60" stroke-width="2"></path>
    </svg>
    

    jQuery Code:

        percentage=85
        if(percentage>=50)
        {
            flag=1;
        }
        var per=0;
        $(svg).animate({ 'to': 1 }, {
        duration: 2000,
        step: function(pos, fx) {
    
            //var offset = (pos);
            if(pos<0.5)
            {
                if(percentage>=50)
                {
                    per=180;
                    $('#percentage').html(Math.round(pos*100)+" %");
                }
                else
                {
                    per=(percentage*180/50);
                    $('#percentage').html(Math.round(percentage*pos*2)+" %");
                }
    
                endx=110-50*Math.cos(0+(Math.PI/180)*per*(pos*2));
                endy=60-50*Math.sin(0+(Math.PI/180)*per*(pos*2));
                svg.setAttribute('d',current_dx+endx+","+endy);
            }   
            else if(pos>=0.5 && pos!=1 && flag==1)
            {
                per=((percentage-50)*180/50);
                $('#percentage').html(Math.round(50+(percentage-50)*(pos-0.5)*2)+" %");
                endx=110+50*Math.cos(0+(Math.PI/180)*per*(pos-0.5)*2);
                endy=60+50*Math.sin(0+(Math.PI/180)*per*(pos-0.5)*2);
                svg.setAttribute('d',current_d+endx+","+endy);
    
            }
    
    
        }
    });
    

    Demo : Click Here

    0 讨论(0)
  • 2020-12-30 16:07

    Shamelessly copy and pasting from the specification:

    <path d="M275,175 v-150 a150,150 0 0,0 -150,150 z"
        fill="yellow" stroke="blue" stroke-width="5" />
    

    The path uses the "elliptical arc" command to draw a partial circle. You can either draw several of them, each describing a different circular section, or you give one of them an ID and reference it with <use xlink:href="#ID" />. Then you can rotate the <use/>. Draw as many of them as you need for granularity (e.g., 100 sectors allow you steps of 0% to 100%).

    To colorize them, just set the fill="" attribute of each single sector to the fitting value.

    0 讨论(0)
提交回复
热议问题