基于 SVG 弧形路径的圆图绘制

简短的问题: 使用 SVG 路径,我们可以画一个圆的99.99% ,并显示出来,但当它是一个圆的99.9999999% ,然后圆不会显示出来。怎么修呢?

下面的 SVG 路径可以绘制一个圆的99.99% : (请在下面尝试,看看您是看到4个弧还是只看到2个弧,但请注意,如果它是 IE,它是用 VML 呈现的,而不是 SVG,但有类似的问题)

var paper = Raphael(0, 0, 300, 800);


// Note that there are supposed to be 4 arcs drawn, but you may see only 1, 2, or 3 arcs depending on which browser you use




paper.path("M 100 100 a 50 50 0 1 0 35 85").attr({stroke: "#080", opacity: 1, "stroke-width" : 6})  // this is about 62.5% of a circle, and it shows on most any browsers
    

paper.path("M 100 210 a 50 50 0 1 0 0.0001 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6})    // this one won't show anything if it is IE 8's VML, but will show if it is Chrome or Firefox's SVG.  On IE 8, it needs to be 0.01 to show
    

paper.path("M 100 320 a 50 50 0 1 0 0.0000001 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6})   // this one won't draw anything at all, unless you change the 0.0000001 to 0.0001 on Chrome or Firefox... Safari will show it though...
    

paper.path("M 100 430 a 50 50 0 1 0 0 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6})   // this is 100% of a circle...  even Safari won't show it
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>

M 100 100 a 50 50 0 1 0 0.00001 0

但是当它是一个圆的99.99999999% ,那么什么都不会显示吗?

M 100 100 a 50 50 0 1 0 0.00000001 0

这对于100% 的圆也是一样的(它仍然是一个弧线,不是吗,只是一个非常完整的弧线)

M 100 100 a 50 50 0 1 0 0 0

这要怎么补救?原因是我使用一个函数来绘制一个弧度的百分比,如果我需要“特殊情况”一个99.9999% 或100% 的弧度来使用圆函数,这将是一种愚蠢的。

同样,上面还有一个测试用例 (如果在 IE8上是 VML,甚至第二个圆圈也不会显示... ... 您必须将其更改为0.01)


更新:

这是因为我在我们的系统中为一个分数绘制了一个弧线,所以3.3分得到一个圆的1/3。0.5得到半个圆9.9得到圆的99% 。但是如果我们的系统中有9.99的分数呢?我是否必须检查它是否接近圆的99.999% ,并相应地使用 arc函数或 circle函数?那么9.9987分呢?用哪一个?需要知道什么样的分数会映射到一个“太完整的圆”,并切换到一个圆函数,这是荒谬的,当它是一个圆的“一定99.9%”或9.9987分,然后使用弧函数。

168556 次浏览

XAML 的弧线也是一样。只要用 Z接近99.99% 的弧线,你就得到了一个圆!

Adobe Illustrator 使用像 SVG 这样的 bezier 曲线,对于圆,它创建了四个点。您可以用两个 椭圆弧命令椭圆弧命令创建一个圆... ... 但是对于 SVG 中的一个圆,我会使用一个 <circle />:)

我知道现在有点晚了,但是我记得这个问题,当它还是新的时候,我有一个类似的困境,我偶然发现了“正确”的解决方案,如果有人仍然在寻找的话:

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

换句话说:

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

可以通过以下途径实现:

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

诀窍是有两条弧线,第二条弧线从第一条弧线中断的地方开始,然后利用负直径回到原来的弧线起点。

之所以不能在一个弧线上画一个完整的圆(我只是推测) ,是因为你会告诉它从它自己画一个弧线(比如说150,150)到它自己(150,150) ,它表示为“哦,我已经在那里了,不需要画弧线!”.

我提供的解决方案的好处是:

  1. 很容易从一个圆直接转换成一条路径
  2. 两条弧线没有重叠(如果使用标记或模式等,可能会导致问题)。这是一条干净的连续线,尽管是分成两部分画的。

如果它们只允许文本路径接受形状,那么所有这些都无关紧要。但我认为他们正在避免这种解决方案,因为像圆这样的形状元素在技术上没有一个“起点”。

片段演示:

circle, path {
fill: none;
stroke-width: 5;
stroke-opacity: .5;
}


circle {
stroke: red;
}
path {
stroke: yellow;
}
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="220px" height="220px">


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


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


</svg>

更新:

如果你使用路径作为一个 textPath参考,并且你想要在弧线的外边缘渲染文本,你会使用完全相同的方法,但是把扫描标志从0改为1,这样它就把路径的外部当作表面而不是内部(想象一下 1,0作为坐在中心的人,在他们自己周围画一个圆,而 1,1作为一个人在半径距离内绕着中心走,并拖着他们的粉笔在他们身边,如果这有帮助的话)。下面是上面的代码,但有所改动:

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

使用两个弧形命令画一个完整的圆是一个好主意。

通常,我使用椭圆或圆形元素来画一个完整的圆。

一个完全不同的方法:

不需要在 svg 中修改路径来指定弧,还可以使用一个圆形元素并指定一个笔划 -dasharray,使用伪代码:

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

它的简单性是多弧路径方法的主要优点(例如,在编写脚本时,您只需插入一个值,并且对于任何弧长都可以完成)

弧线从最右边的一点开始,可以使用旋转变换来移动。

注意: Firefox 有一个奇怪的 bug,超过90度的旋转被忽略。因此,要从顶部开始画弧线,请使用:

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

关于 Anthony 的解,这里有一个函数来得到路径:

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

另一种方法是使用两个三次 Bezier 曲线。这是为 iOS 用户使用的 口袋 SVG不识别 svg 弧参数。

C x1 y1,x2 y2,xy (或者 c dx1 dy1,dx2 dy2,dxdy)

Cubic Bezier curve

这里的最后一组坐标(x,y)是您希望直线结束的位置。另外两个是控制点。(x1,y1)是曲线起点的控制点,(x2,y2)是曲线终点的控制点。

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

作为一个函数,它看起来像这样:

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

在安东尼和安东的回答的基础上,我整合了旋转生成的圆圈而不影响它的整体外观的能力。如果您正在为动画使用路径,并且需要控制它的开始位置,那么这是非常有用的。

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

对于那些像我一样寻找路径转换的椭圆属性的人:

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 Z`

我在这里做了个小提琴:

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

链接

您所需要做的就是更改 console.log 的输入并在控制台中获得结果

这些答案太复杂了。

一个更简单的方法来做到这一点,而不需要创建两个弧或转换为不同的坐标系统。

这假设您的画布区域有宽度 w和高度 h

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

只要使用“长弧形”标志,就可以填充完整的标志。然后把弧线画成99.9999% 的圆。在视觉上是一样的。避免扫标志,只是开始在最右边的圆点(一个半径直接从中心水平)。