2

enter image description here

Here is my JSfiddle I am trying to make an SVG Arc progress bar with a constant object at the end of the progress bar. When i animate this using JavaScript the constant object is going to the other side when it reach 100%. Otherwise it is working perfectly. Also i found 1 Pixel difference in stroke-dasharray for constant object when using Safari.

My Questions and concerns

1) I really like the quality of the SVG object but it is good for cross browser rendering like Canvas? (Canvas vs SVG Performance and Browser support)

2) How to prevent constant object is going to the other side when it reach 100 %?

3) How to make it responsive?

HTML

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 100 100">
      <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
           <stop offset="0%" stop-color="#56c4fb" />
           <stop offset="100%" stop-color="#0baeff" />
         </linearGradient>


        <path class="grey" d="M30,90 A40,40 0 1,1 80,90" style="fill:none;"/>
        <path id="purple" class="purple" d="M30,90 A40,40 0 1,1 80,90" style="fill:none; transition: .3s;"/>
        <path id="white" class="white" d="M30,90 A40,40 0 1,1 80,90" style="fill:none; transition: .3s;"/>
 </svg>  

CSS

        svg {
    height: 90vh;
    margin: auto;
    display: block;
    }

    path {
    stroke-linecap: round;
    stroke-width: 6;
    }

    path.grey {
    stroke: #e7e7e8;

    }

    path.purple {
    stroke: url(#gradient);
    stroke-dasharray: 198;
    stroke-dashoffset: 198;
    animation: dash 5s linear forwards;
   }
    path.white {
      stroke: #ffffff;
      stroke-dasharray: 0px, 198px;
      stroke-dashoffset: 198;
      stroke-width: 3.5px;
      animation: dash 5s linear forwards;

    }
    @keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
}
Vishnu
  • 741
  • 1
  • 7
  • 24

2 Answers2

5

Changing the keyframes stroke-dashoffset property to 1 instead of 0 seems to solve the issue. I've also cleaned up your SVG syntax of unneeded code and now it's also responsive (meaning it adjusts the height of the SVG according to the parent object.

Regarding your first question, SVG is the way to go, and it is extremely popular for widgets such as this one, much more popular than CANVAS, simply because it is easier to work with. Performance-wise SVG is totally fine.

svg {
  height: 90vh;
  margin: auto;
  display: block;
}

path {
  stroke-linecap: round;
  stroke-width: 6;
}

path.grey {
  stroke: #e7e7e8;
}

path.purple {
  stroke: url(#gradient);
  stroke-dasharray: 198;
  stroke-dashoffset: 198;
  animation: dash 3s .5s cubic-bezier(.7,0,.3,1) forwards;
}

path.white {
  stroke: #ffffff;
  stroke-dasharray: 0px, 198px;
  stroke-dashoffset: 198;
  stroke-width: 3.5px;
  animation: dash 3s .5s cubic-bezier(.7,0,.3,1) forwards;
}

@keyframes dash {
  to {
    stroke-dashoffset: 1; /* <---- changed to "1" from "0"  */
  }
}
<svg viewbox="0 0 100 100">
      <linearGradient id="gradient" x1="0" y1="0" x2="0" y2="100%">
           <stop offset="0%" stop-color="#56c4fb" />
           <stop offset="100%" stop-color="#0baeff" />
       </linearGradient>
       <path class="grey" d="M30,90 A40,40 0 1,1 80,90" fill='none' />
       <path id="purple" fill='none' class="purple" d="M30,90 A40,40 0 1,1 80,90" />
       <path id="white" fill='none' class="white" d="M30,90 A40,40 0 1,1 80,90" />
 </svg>
vsync
  • 118,978
  • 58
  • 307
  • 400
  • I play with almost all possible numbers. 1 is not a good solution because as you can see from this image https://ibb.co/hKYPVy it is not reaching 100%. Also for some reason safari need 2px for the same effect on chrome. i am confused. – Vishnu Jun 02 '18 at 03:31
  • when we give one on Safari the white object is invisible! it is visible when we give 2. On chrome it is even worst that the image i posted above, it's like reaching 98%. No Progress (Both blue and white object should be invisible) 1% Progress (Both blue and white object on the left corner) 50% Progress (Both blue and white object on top center) 100% Progress (Both blue and white object on bottom right corner) Challenge for me i am not able to achieve above screenplay to action perfectly & Browser rendering issues may come along with it, Thanks – Vishnu Jun 02 '18 at 04:10
  • Thank you!! i was looking for this too. Btw is there a way for me to use the cursor to drag the blue indicator instead using animation? – Kingsley Yong Aug 29 '22 at 07:04
  • @KingsleyYong - drag from where to where? left to right? that would be a very short distance and will make it sensitive to movements – vsync Aug 29 '22 at 07:08
  • @vsync drag the white dot from the beginning of the arc to the end instead of using the animation to bring the white dot to the end of the arc. – Kingsley Yong Aug 29 '22 at 07:15
  • @KingsleyYong - You cannot use the terms `beginning` to `end`. You need to explicitly say how will the mouse move affect the outcome, given a 2-dimentional surface (`x`/`y`) – vsync Aug 29 '22 at 08:10
  • https://im.ezgif.com/tmp/ezgif-1-06056c951c.gif sorry I not sure how to explain using the x/y coordinate. Basically is like this drag from 0% to 100%. – Kingsley Yong Aug 29 '22 at 08:55
  • It's still not clear.. when the user is grabbing the handle, can the use simply move the mouse from left to right, in a linear way? (without following the curve's path) – vsync Aug 29 '22 at 09:24
  • Its needs to be follow the curve's path, it's like dragging the handler (white dot) from the start point(left) to the end point(right) @vsync – Kingsley Yong Aug 30 '22 at 06:47
1

1) if a browser is able to do canvas, it is also very likely that it can do svg as well. BUT SVG, specific features need to be checked as well, so its hard to give a general »true|false« here, since some things may work, while others don't.

3) SVG's lives in their own »display scope«, if you do not depend on user input, it behaves pretty much as a simple <img >. Otherwise you will need to transform coordinates.

2) that one might need some js, if you want to display some »real« progress (a XHR for instance), you will need JS anyway… Just make the animation stop|non-repetitive

philipp
  • 15,947
  • 15
  • 61
  • 106