Search code examples
svgsvg-path

SVG path inside circle bad overlap


I have a SVG timer. There is a path to show the current state. But the path overlaps badly as you can see in my attached screenshot:

screenshot

The code out of the inspector for this screenshot is:

<svg class="ion-timer-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" style="width: 100%; height: 100%;">
<circle fill="none" cx="60" cy="60" r="55" style="stroke: rgb(255, 255, 255); stroke-width: 10;"></circle>
<path fill="none" transform="scale(-1, 1) translate(-120 0)" d="M 114.89147163068816 63.4534536651529 A 55 55 0 0 0 60 5" style="stroke: rgb(0, 0, 0); stroke-width: 10; stroke-linecap: butt;"></path>
<g ng-transclude=""></g>
</svg>

This is how the SVG is generated:

// credit to http://stackoverflow.com/questions/5736398/how-to-calculate-the-svg-path-for-an-arc-of-a-circle
    // inspired by: https://github.com/crisbeto/angular-svg-round-progressbar
    var updateState = function(ring, val, total, options) {
      var polarToCartesian = function(centerX, centerY, radius, angleInDegrees) {
        var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
        return {
          x: centerX + (radius * Math.cos(angleInRadians)),
          y: centerY + (radius * Math.sin(angleInRadians))
        };
      };

      var R           = options.progressCircle.radius - (options.progressCircle.strokeWidth / 2);
      var size        = options.progressCircle.radius * 2;
      var value       = val >= total ? total - 0.00001 : val;
      var type        = 359.9999;
      var perc        = total === 0 ? 0 : (value / total) * type;
      var x           = size/2;
      var start       = polarToCartesian(x, x, R, perc); // in this case x and y are the same
      var end         = polarToCartesian(x, x, R, 0);
      var arcSweep    = (perc <= 180 ? '0' : '1');
      var d           = ['M', start.x, start.y, 'A', R, R, 0, arcSweep, 0, end.x, end.y].join(' ');

      return ring.attr('d', d);

This ugly white line outside the black path sucks. How to get rid of this? Is there any antializing?

Another option would be to do margin-top:-1px at the black path. But where to do this?

EDIT: This is the timer after the suggestions from ccprog:

http://imgur.com/a/m1hjw

<svg class="ion-timer-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" style="width: 100%; height: 100%;">
    <mask id="mask">
        <circle id="ring" fill="none" cx="60" cy="60" r="55" style="stroke: rgb(255, 255, 255); stroke-width: 10;"></circle>
    </mask>
    <g mask="url(#mask)">
        <circle fill="rgb(255, 255, 255)" cx="60" cy="60" r="61"></circle>
        <path fill="none" style="stroke-width: 12; stroke: rgb(0, 0, 0); stroke-linecap: butt;" transform="scale(-1, 1) translate(-120 0)" d="M 112.6047821265274 76.0541862895814 A 55 55 0 0 0 60 5"></path>
    </g>
    <g ng-transclude=""></g>
</svg>

Solution

  • Use the full circle as a mask:

    <svg class="ion-timer-svg"
         xmlns="http://www.w3.org/2000/svg"
         viewBox="0 0 120 120" style="width: 100%; height: 100%;">
      <mask id="mask">
        <circle id="ring" fill="none" cx="60" cy="60" r="55"
                style="stroke: rgb(255, 255, 255); stroke-width: 10;"></circle>
      </mask>
      <g mask="url(#mask)">
        <circle fill="rgb(255, 255, 255)" cx="60" cy="60" r="61" />
        <path fill="none" transform="scale(-1, 1) translate(-120 0)"
              d="M 114.89147163068816 63.4534536651529 A 55 55 0 0 0 60 5"
              style="stroke: rgb(0, 0, 0); stroke-width: 12; stroke-linecap: butt;"></path>
      </g>
     <g ng-transclude=""></g>
    </svg>
    

    Note that this works because the color of the circle stroke is white. Any other color would give you some transparency.