[svg] Circle drawing with SVG's arc path

Short question: using SVG path, we can draw 99.99% of a circle and it shows up, but when it is 99.99999999% of a circle, then the circle won't show up. How can it be fixed?

The following SVG path can draw 99.99% of a circle: (try it on http://jsfiddle.net/DFhUF/1381/ and see if you see 4 arcs or only 2 arcs, but note that if it is IE, it is rendered in VML, not SVG, but have the similar issue)

M 100 100 a 50 50 0 1 0 0.00001 0

But when it is 99.99999999% of a circle, then nothing will show at all?

M 100 100 a 50 50 0 1 0 0.00000001 0    

And that's the same with 100% of a circle (it is still an arc, isn't it, just a very complete arc)

M 100 100 a 50 50 0 1 0 0 0 

How can that be fixed? The reason is I use a function to draw a percentage of an arc, and if I need to "special case" a 99.9999% or 100% arc to use the circle function, that'd be kind of silly.

Again, a test case on jsfiddle using RaphaelJS is at http://jsfiddle.net/DFhUF/1381/
(and if it is VML on IE 8, even the second circle won't show... you have to change it to 0.01)


Update:

This is because I am rendering an arc for a score in our system, so 3.3 points get 1/3 of a circle. 0.5 gets half a circle, and 9.9 points get 99% of a circle. But what if there are scores that are 9.99 in our system? Do I have to check whether it is close to 99.999% of a circle, and use an arc function or a circle function accordingly? Then what about a score of 9.9987? Which one to use? It is ridiculous to need to know what kind of scores will map to a "too complete circle" and switch to a circle function, and when it is "a certain 99.9%" of a circle or a 9.9987 score, then use the arc function.

This question is related to svg geometry drawing vml geometric-arc

The answer is


I know it's a bit late in the game, but I remembered this question from when it was new and I had a similar dillemma, and I accidently found the "right" solution, if anyone is still looking for one:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,0 (r * 2),0
    a r,r 0 1,0 -(r * 2),0
    "
/>

In other words, this:

<circle cx="100" cy="100" r="75" />

can be achieved as a path with this:

  <path 
        d="
        M 100, 100
        m -75, 0
        a 75,75 0 1,0 150,0
        a 75,75 0 1,0 -150,0
        "
  />

The trick is to have two arcs, the second one picking up where the first left off and using the negative diameter to get back to the original arc start point.

The reason it can't be done as a full circle in one arc (and I'm just speculating) is because you would be telling it to draw an arc from itself (let's say 150,150) to itself (150,150), which it renders as "oh, I'm already there, no arc necessary!".

The benefits of the solution I'm offering are:

  1. it's easy to translate from a circle directly to a path, and
  2. there is no overlap in the two arc lines (which may cause issues if you are using markers or patterns, etc). It's a clean continuous line, albeit drawn in two pieces.

None of this would matter if they would just allow textpaths to accept shapes. But I think they are avoiding that solution since shape elements like circle don't technically have a "start" point.

jsfiddle demo: http://jsfiddle.net/crazytonyi/mNt2g/

Update:

If you are using the path for a textPath reference and you are wanting the text to render on the outer edge of the arc, you would use the exact same method but change the sweep-flag from 0 to 1 so that it treats the outside of the path as the surface instead of the inside (think of 1,0 as someone sitting at the center and drawing a circle around themselves, while 1,1 as someone walking around the center at radius distance and dragging their chalk beside them, if that's any help). Here is the code as above but with the change:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,1 (r * 2),0
    a r,r 0 1,1 -(r * 2),0
    "
/>

i made a jsfiddle to do it in here:

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))
};
}

function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
    "M", start.x, start.y, 
    "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;       
}
console.log(describeArc(255,255,220,134,136))

link

all you need to do is to change the input of console.log and get the result in console


A totally different approach:

Instead of fiddling with paths to specify an arc in svg, you can also take a circle element and specify a stroke-dasharray, in pseudo code:

with $score between 0..1, and pi = 3.141592653589793238

$length = $score * 2 * pi * $r
$max = 7 * $r  (i.e. well above 2*pi*r)

<circle r="$r" stroke-dasharray="$length $max" />

Its simplicity is the main advantage over the multiple-arc-path method (e.g. when scripting you only plug in one value and you're done for any arc length)

The arc starts at the rightmost point, and can be shifted around using a rotate transform.

Note: Firefox has an odd bug where rotations over 90 degrees or more are ignored. So to start the arc from the top, use:

<circle r="$r" transform="rotate(-89.9)" stroke-dasharray="$length $max" />

Written as a function, it looks like this:

function getPath(cx,cy,r){
  return "M" + cx + "," + cy + "m" + (-r) + ",0a" + r + "," + r + " 0 1,0 " + (r * 2) + ",0a" + r + "," + r + " 0 1,0 " + (-r * 2) + ",0";
}

Adobe Illustrator uses bezier curves like SVG, and for circles it creates four points. You can create a circle with two elliptical arc commands...but then for a circle in SVG I would use a <circle /> :)


These answers are much too complicated.

A simpler way to do this without creating two arcs or convert to different coordinate systems..

This assumes your canvas area has width w and height h.

`M${w*0.5 + radius},${h*0.5}
 A${radius} ${radius} 0 1 0 ${w*0.5 + radius} ${h*0.5001}`

Just use the "long arc" flag, so the full flag is filled. Then make the arcs 99.9999% the full circle. Visually it is the same. Avoid the sweep flag by just starting the circle at the rightmost point in the circle (one radius directly horizontal from the center).


It's a good idea that using two arc command to draw a full circle.

usually, I use ellipse or circle element to draw a full circle.


In reference to Anthony’s solution, here is a function to get the path:

function circlePath(cx, cy, r){
    return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0';
}

Building upon Anthony and Anton's answers I incorporated the ability to rotate the generated circle without affecting it's overall appearance. This is useful if you're using the path for an animation and you need to control where it begins.

function(cx, cy, r, deg){
    var theta = deg*Math.PI/180,
        dx = r*Math.cos(theta),
        dy = -r*Math.sin(theta);
    return "M "+cx+" "+cy+"m "+dx+","+dy+"a "+r+","+r+" 0 1,0 "+-2*dx+","+-2*dy+"a "+r+","+r+" 0 1,0 "+2*dx+","+2*dy;
}

For those like me who were looking for an ellipse attributes to path conversion:

const ellipseAttrsToPath = (rx,cx,ry,cy) =>
`M${cx-rx},${cy}a${rx},${ry} 0 1,0 ${rx*2},0a${rx},${ry} 0 1,0 -${rx*2},0`

Another way would be to use two Cubic Bezier Curves. That's for iOS folks using pocketSVG which doesn't recognize svg arc parameter.

C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)

Cubic Bezier curve

The last set of coordinates here (x,y) are where you want the line to end. The other two are control points. (x1,y1) is the control point for the start of your curve, and (x2,y2) for the end point of your curve.

<path d="M25,0 C60,0, 60,50, 25,50 C-10,50, -10,0, 25,0" />

Examples related to svg

How to extract svg as file from web page How to display svg icons(.svg files) in UI using React Component? Why don’t my SVG images scale using the CSS "width" property? How to show SVG file on React Native? Easiest way to use SVG in Android? IE11 meta element Breaks SVG img src SVG changing the styles with CSS How to use SVG markers in Google Maps API v3 Embedding SVG into ReactJS How to change the color of an svg element?

Examples related to geometry

Circle button css Using atan2 to find angle between two vectors How do I compute the intersection point of two lines? Creating a triangle with for loops Plotting a 3d cube, a sphere and a vector in Matplotlib How to find the Center Coordinate of Rectangle? Evenly distributing n points on a sphere How do CSS triangles work? How to draw circle in html page? Generate a random point within a circle (uniformly)

Examples related to drawing

How to draw a checkmark / tick using CSS? Draw in Canvas by finger, Android How to create a Rectangle object in Java using g.fillRect method c# write text on bitmap Circle drawing with SVG's arc path Creating an empty bitmap and drawing though canvas in Android Drawing circles with System.Drawing Android: How to overlay a bitmap and draw over a bitmap? How To: Best way to draw table in console app (C#) Draw radius around a point in Google map

Examples related to vml

Circle drawing with SVG's arc path

Examples related to geometric-arc

Circle drawing with SVG's arc path