1

This question is an extension of Define a circle / arc animation in SVG and How to calculate the SVG Path for an arc (of a circle).

I have modified the answer of @opsb as follows:

function calculateArcPath(x, y, radius, spread, startAngle, endAngle){
    var innerStart = polarToCartesian(x, y, radius, endAngle);
   var innerEnd = polarToCartesian(x, y, radius, startAngle);
    var outerStart = polarToCartesian(x, y, radius + spread, endAngle);
    var outerEnd = polarToCartesian(x, y, radius + spread, startAngle);
    var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
  
    var d = [
        "M", outerStart.x, outerStart.y,
        "A", radius + spread, radius + spread, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
        "L", innerEnd.x, innerEnd.y, 
        "A", radius, radius, 0, largeArcFlag, 1, innerStart.x, innerStart.y, 
        "L", outerStart.x, outerStart.y, "Z"
    ].join(" ");

    return d;
}

function polarToCartesian(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 startPath = calculateArcPath(250, 250, 50, 30, 0, 30)
var endPath = calculateArcPath(250, 250, 50, 30, 0, 150)

d3.select("path").attr("d", startPath)
d3.select("path").transition().duration(2000).attr("d", endPath)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="500" style="border:1px gray solid">  
  <path id="path" fill="blue" stroke="black"></path>
</svg>

However, the path isnt a smooth transition around the circle.

Community
  • 1
  • 1
SumNeuron
  • 4,850
  • 5
  • 39
  • 107

1 Answers1

8

Your animation looks weird because you're animating linearly between two curve shapes. One end point stays fixed while the other moves in a straight line (instead of along an arc).

I think you'll find it much easier to use the stroke-dashoffset trick to animate your curve. Here's a simple example:

function update_arc() {
  /* Fetch angle from input field */
  angle = document.getElementById("ang").value;
  if (angle < 0) angle = 0;
  if (angle > 360) angle = 360;
  /* Convert to path length using formula r * θ (radians) */
  var arclen = Math.PI * 50 * (360-angle) / 180.0;
  /* Set stroke-dashoffset attribute to new arc length */
  document.getElementById("c").style.strokeDashoffset = arclen;
}
#c {
  stroke-dashoffset: 157.08;
  stroke-dasharray: 314.16;
  -webkit-transition: stroke-dashoffset 0.5s;
  transition: stroke-dashoffset 0.5s;
}
<svg width="120" height="120" viewBox="0 0 120 120">
  <!-- Circle element of radius 50 units. -->
  <!-- (Rotated 90° CCW to put start point is at top.) -->
  <circle id="c" cx="60" cy="60"
          r="50" fill="none" stroke="blue"
          stroke-width="15"
          stroke-dashoffset="157.08"
          stroke-dasharray="314.16"
          transform="rotate(-90 60 60)" />
</svg>
<p>Enter new angle (0–360):<br />
<input type="text" id="ang" width="20" value="180" />
<button onclick="return update_arc()">Set</button></p>
r3mainer
  • 23,981
  • 3
  • 51
  • 88
  • Originally I was actually doing that.... However, if you use a thick stroke to make your arc, then either you have no fill or you can not create an outline (with the same SVG element although you could always make another one outlining it). The use of an arc segment which is not made via thick stroke-width is the crux of the question and what justifies it being in S.O. given that there are already several about the stroke-dashoffset trick – SumNeuron Apr 05 '17 at 04:44