Home > Mobile >  Calculate dashed progress path in SVG circle
Calculate dashed progress path in SVG circle

Time:09-18

I'm building a progress circle that represents a users level up to three. It contains three dashes around the perimeter. A darker line that overlaps each dash will represent the user's progress. If a user is level one, the first dash should be overlapped by an amount equal to (their current experience / total experience to next level). If the user is level two, the first dash should be fully overlapped and the second dash should be the same as the above and so on. I've built my SVG circle with the following code:

<svg
   width="240"
   height="240"
   viewBox="0 0 240 240"
   strokeWidth="2px"
   strokeDasharray="220 10"
   strokeDashoffset="50"
>
    <circle cx="120" cy="120" r="110" fill="white" stroke="turquoise" />
</svg>

This image represents a user that is on level two and about halfway through to level three.

How could I calculate a <path> to overlap the circle and display the user's progress?

CodePudding user response:

This is how you'd do it with an arc path. Draw the arc from the bottom of the circle to 1 unit in the x axis. Set the pathLength="100" so you can calculate the required dash array appropriately. Then make sure your dash-array adds up to 100.

Note - you can't use a round line-cap for this method - there is a bug in Chrome that adds an incorrect line-cap at the end of the stroke-dash array.

<svg
   width="240px"
   height="240px"
   viewBox="0 0 240 240"
   stroke-width="4"
   stroke-dasharray="220 10"
   stroke-dashoffset="50"
   stroke-linecap ="none">
  
    <circle cx="120" cy="120" r="110" fill="white" stroke="turquoise" />
    <path pathLength="100" d="M120 230 a 110 110 0 1 1 1 0" stroke="red" fill="none" stroke-width="8" stroke-dasharray="0 1 32 1 15 50" stroke-dashoffset="0"/>
</svg>

CodePudding user response:

I question your design for readability:

This design is based on Google Analystics graphs:

<script src="https://progress-circle.github.io/element.js"></script>

    <progress-circle edge="grey">
      <style>
        svg {
          font: 16px arial;
          height: 180px;
        }
      </style>
      <progress value="75%" stroke="green">Level I</progress>
      <progress value="60%" stroke="orange">Level II</progress>
      <progress value="50%" stroke="orangered">Level III</progress>
    </progress-circle>

CodePudding user response:

Here you can control the length of each path by setting the stroke-dasharray. The first number is the length (between 0 and 94 (2*PI*45/3 = 94)) and the second number is the space between strokes (this should just be more than 284).

In this example the red path is 50% length. You need to experiment a bit with the numbers.

var dist = 6;
console.log('Length of 1/3 circle:', Math.round(2 * Math.PI * 45 / 3)-dist);
console.log('Rotate <g> slightly:',-Math.round(2 * Math.PI * 45 / 12)-(dist/2));
<div id="progress">
  <svg viewBox="0 0 100 100" width="300" height="300">
      <g transform="translate(50 50) rotate(-27)">
         <path transform="rotate(0)" d="M 45,0 A 45,45 0 0 1 0,45 45,45 0 0 1 -45,0 45,45 0 0 1 0,-45 45,45 0 0 1 45,0 Z" stroke-width="5" stroke-dasharray="44 400" stroke-dashoffset="0" stroke="red" fill="none" stroke-linecap="round"/>
         <path transform="rotate(120)" d="M 45,0 A 45,45 0 0 1 0,45 45,45 0 0 1 -45,0 45,45 0 0 1 0,-45 45,45 0 0 1 45,0 Z" stroke-width="5" stroke-dasharray="88 400" stroke-dashoffset="0" stroke="navy" fill="none" stroke-linecap="round"/>
         <path transform="rotate(240)" d="M 45,0 A 45,45 0 0 1 0,45 45,45 0 0 1 -45,0 45,45 0 0 1 0,-45 45,45 0 0 1 45,0 Z" stroke-width="5" stroke-dasharray="88 400" stroke-dashoffset="0" stroke="orange" fill="none" stroke-linecap="round"/>
      </g>
   </svg>
</div>

  • Related