带有SVG弧线路径的圆图


146

简短的问题:使用SVG路径,我们可以绘制99.99%的圆并显示出来,但是当它是99.99999999%的圆时,该圆就不会显示。如何解决?

以下SVG路径可以绘制99.99%的圆:(在http://jsfiddle.net/DFhUF/1381/上尝试一下,看看是否看到4个圆弧或只有2个圆弧,但是请注意,如果是IE,则为以VML而非SVG呈现,但存在类似问题)

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%的圆弧,那将是很愚蠢的。

同样,在http://jsfiddle.net/DFhUF/1381/上使用RaphaelJS进行jsfiddle的测试用例
(如果在IE 8上是VML,则即使第二个圆圈也不会显示...您必须将其更改为0.01)


更新:

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


@minitech当然有效...那么它就是一个圆的99%(大致来说)。情况是,它可以绘制98%,99%,99.99%的圆,但不能绘制99.9999999%或100%
极性2011年

1
这两个链接都指向同一个事物,并且在Safari中工作正常。
Mark Bessey

是的,相同的链接,我只希望人们早些看到测试用例,所以我在问题的开头添加了链接。正确的野生动物园将做到这一点,多么好... Chrome和Firefox不会...有点奇怪,因为Safari和Chrome都是Webkit ...但是SVG引擎是否依赖Webkit?
nonopolarity 2011年

@Marcin看起来很好吗?您看到4弧还是2弧?你甚至看过代码吗?
极性2011年

2
更新的jsfiddle,其中包含Raphael作为库,以避开跨域错误加载raphael.js:jsfiddle.net/DFhUF/1381
ericsoco 2013年

Answers:


35

与XAML的弧相同。只需用a闭合99.99%的弧度,Z您就会有一个圆圈!


那么您可以关闭jsfiddle示例中的第三种情况并使其起作用吗?
nonopolarity 2011年

将值降低到0.0001,是的。这个问题听起来与WebKit的各种浏览器实现有关,而不是与SVG本身有关。但这就是在SVG / XAMLs Arc组件中画圆的方式。
Todd Main

作弊,永远是最好的解决方案。仍然需要处理100%的情况,而只是“舍入”到99.999%,而不是使用整个单独的代码分支。
SimonR '16

有演示吗?这个答案不能满足
Medet Tleukabiluly

@MedetTleukabilu您在问题中有上面的弧线,在z末尾添加一个并完成。您可能必须删除零,例如,在我必须编写0.0001才能使它工作的最新版Chrome中。如果要查找路径字符串的放置位置,请查看MDN上的路径
TWiStErRob '16

415

我知道游戏还有些晚,但是我从新游戏开始就记得这个问题,我也有类似的问题,如果有人还在寻找,我偶然找到了“正确”的解决方案:

<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. 两条弧线之间没有重叠(如果使用标记或图案等,可能会引起问题)。这是一条干净的连续线,尽管分为两部分。

如果它们仅允许文本路径接受形状,则这无关紧要。但是我认为他们正在避免这种解决方案,因为从技术上讲,像圆形这样的形状元素没有“起点”。

jsfiddle演示:http : //jsfiddle.net/crazytonyi/mNt2g/

更新:

如果您将路径用作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
    "
/>

1
+1,谢谢你的公式。当然,前两个命令可以合并。
John Gietzen 2013年

一般而言,+ 1代表解决方案的清晰性和实用性,但特别是对于“圆形之类的形状元素从技术上讲,没有“起点”” -这种表达问题的清晰方法。
David John Welsh

11
我认为这里的问题不是“哦,我已经在那儿了,没有弧!”,因为通过提供1作为大弧标志,您明确地告诉引擎您希望它继续前进。真正的问题是,有无数的圆圈满足通过点的约束。这解释了为什么当您想要360 *弧度时,引擎不知道该怎么办。它对于359.999不起作用的原因是,这在数值上是不稳定的计算,并且从技术上讲,恰好有一个与请求匹配的圆,但无论如何它可能都不是您想要的
qbolec 2013年

@qbolec-没错,我是在考虑大弧和横扫以及弧线没有终点的问题。或者至少,即使启用了大弧度和扫掠功能,也存在一些基本设计,将弧线定义为两点之间的曲线(因此,如果使用一个点两次,则将其视为折叠的单个点。)圆弧的视觉可能会围绕一个点绘制360个圆是有意义的,尽管如果定义了中心会折叠成一个圆,这就提出了一个问题:如果确实存在一个中心,则单个圆弧能否形成一个完整的圆?
安东尼

1
“像圆形这样的形状元素在技术上没有“起点””。这实际上是不正确的。SVG规范绝对指定所有形状的起点在哪里。为了使破折号阵列可以在形状上工作,必须这样做。
Paul LeBeau

17

关于安东尼的解决方案,以下是获取路径的函数:

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

10

完全不同的方法:

除了使用svg指定路径以指定弧线外,还可以使用一个伪元素使用一个circle元素并指定一个stroke-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有一个奇怪的错误,即超过90度或更大的旋转会被忽略。因此,要从顶部开始弧,请使用:

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

请注意,此解决方案仅适用于以下情况:不使用任何类型的填充,并且只需要没有偏差的弧段。当您要绘制扇区时,您甚至需要一个新的svg路径节点,否则可以在单个路径标签中进行处理。
mxfh 2015年

@mxfh并非如此,如果您将笔划宽度设为r值的两倍,则会得到完美的扇区。
mvds

stroke-dasharray="0 10cm 5cm 1000cm"可能避免这种转变
stenci's

@stenci是的,但缺点是您无法在仪表板中使用一个参数将填充比例从0%缩放到100%(这是我的目标之一)
mvds

5

Adobe Illustrator使用像SVG这样的贝塞尔曲线,并为圆形创建四个点。您可以使用两个椭圆弧命令创建一个圆...但是对于SVG中的一个圆,我将使用<circle />:)


“您可以使用两个椭圆弧命令创建一个圆”?你什么意思?你不能只用一个吗?至少要使它从(0,0)变为(0.01,0),以使其呈现出某种效果。要使用circle,请查看问题中的更新
nonopolarity 2011年

不,我认为您不能只使用一个。您已经证明了自己做不到,而且HTML5 Canvas圆弧也存在类似的问题。
Phrogz

您的意思是,使用arc左弧和右弧创建一个完整的圆?所以弧不能画出一个完整的圆...这样做arc需要两条路径
极性2011年

2
@动静能量正确,需要两条弧线(或者一条弧线在大多数情况下都是丑陋的,然后使用closepath命令一直直线到最后)。
Phrogz

1
插画家很烂。您无法使用贝塞尔曲线制作圆。只有接近圆的东西,但仍然不是圆。
adius 2014年

4

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

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


5
svg的主要局限性是形状元素不能用于文本路径。这可能是每个访问此问题的人的主要动机。
安东尼

1
@Anthony他们现在可以了。Firefox支持任何形状的textPath。我怀疑Chrome也是如此。
罗伯特·朗森

@RobertLongson-您能否提供示例或示例链接?很好奇它如何确定在没有传统起点的情况下绘制文本路径的起点,以及它是位于外部还是内部(等)。
安东尼

@Anthony请参见SVG 2规范,例如w3.org/TR/SVG2/shapes.html#CircleElement,以及新的textPath附加属性
Robert

4

在安东尼和安东的答案的基础上,我合并了旋转生成的圆而不会影响其整体外观的功能。如果您要使用动画路径,并且需要控制动画的开始位置,则此功能很有用。

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

这正是我所需要的。我正在使用greensock morph插件将圆形路径变形为矩形路径,并且需要稍微旋转才能使其看起来恰到好处。
RoboKozo

3

对于像我这样的人,他们希望将椭圆属性转换为路径:

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`

2

作为函数编写,看起来像这样:

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

2
这是一个很好的答案!只是一个很小的补充:这条道路是绘制成东,北,西,南。如果你想圆的行为完全像一个<circle>,你要的方向改变为东,南,西,北: "M" + cx + "," + cy + "m" + (r) + ",0" + "a" + r + "," + r + " 0 1,1 " + (-r * 2) + ",0" + "a" + r + "," + r + " 0 1,1 " + (r * 2) + ",0" 优点是,stroke-dashoffsetstartOffset现在的工作方式相同。
loominade

2

这些答案太复杂了。

一种简单的方法,无需创建两个弧或将其转换为不同的坐标系。

假设您的画布区域具有width w和height h

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

只需使用“长弧”标志,即可填充完整标志。然后将弧度设为整个圆的99.9999%。在视觉上是相同的。通过仅从圆的最右边的点(一个圆心直接从中心水平开始)来避免扫掠标记。


1

另一种方法是使用两个三次贝塞尔曲线。适用于使用PocketSVG的 iOS 用户不识别svg arc参数的。

C x1 y1,x2 y2,xy(或c dx1 dy1,dx2 dy2,dx dy)

三次贝塞尔曲线

您要在此处结束的最后一组坐标(x,y)。其他两个是控制点。(x1,y1)是曲线起点的控制点,(x2,y2)是曲线终点的控制点。

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

1

我做了一个jsfiddle在这里做:

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的输入并在console中获取结果


这正是我想要的。最好的答案在这里!给予好评这家伙
芒达尔斯特伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.