Circle drawing with SVG's arc path

落花浮王杯 提交于 2019-11-26 03:26:20

问题


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.


回答1:


Same for XAML's arc. Just close the 99.99% arc with a Z and you've got a circle!




回答2:


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
    "
/>



回答3:


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



回答4:


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" />



回答5:


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 /> :)




回答6:


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.




回答7:


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



回答8:


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



回答9:


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).




回答10:


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`



回答11:


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)

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" />



回答12:


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



来源:https://stackoverflow.com/questions/5737975/circle-drawing-with-svgs-arc-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!