用SVG弧形路径绘制圆形图

时间:2011-04-20 23:57:21

标签: svg geometry drawing vml geometric-arc

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

M 100 100 a 50 50 0 1 0 0.00001 0

但是当它是一个圆圈的99.99999999%时,根本没有任何东西显示出来?

M 100 800 a 50 50 0 1 0 0.00000001 0    

这与100%的圆圈相同(它仍然是圆弧,不是它,只是一个非常完整的圆弧)

M 100 800 a 50 50 0 1 0 0 0 

如何修复?原因是我使用一个函数绘制一个弧的百分比,如果我需要“特殊情况”一个99.9999%或100%弧来使用圆函数,那就太傻了。

同样,使用RaphaelJS的jsfiddle的测试用例是http://jsfiddle.net/DFhUF/46/ (如果它是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分数时,则使用弧函数

13 个答案:

答案 0 :(得分:379)

我知道游戏有点晚了,但是我记得这个问题从新的时候开始我有类似的困难,我意外地找到了“正确”的解决方案,如果有人还在寻找一个:

<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. 两条弧线没有重叠(如果使用标记或图案等,可能会导致问题)。这是一条干净的连续线,虽然是两件式的。
  3. 如果他们只允许文本路径接受形状,这一切都不重要。但我认为他们正在避免这种解决方案,因为像圆圈这样的形状元素在技术上并没有“起点”。

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

    更新

    如果您使用textPath引用的路径并且希望文本在弧的外边缘渲染,则可以使用完全相同的方法,但将sweep-flag从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 :(得分:33)

XAML的弧也一样。只需使用Z关闭99.99%的弧线,就可以得到一个圆圈!

答案 2 :(得分:15)

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

答案 3 :(得分:9)

完全不同的方法:

您可以在伪代码中使用圆形元素并指定stroke-dasharray,而不是摆弄路径来指定svg中的弧:

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

答案 4 :(得分:5)

Adob​​e Illustrator使用像SVG这样的贝塞尔曲线,对于圆圈,它会创建四个点。您可以使用两个elliptical arc commands创建一个圆圈...但是对于SVG中的圆圈,我会使用<circle />:)

答案 5 :(得分:3)

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

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

答案 6 :(得分: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";
}

答案 7 :(得分:2)

在Anthony和Anton的答案的基础上,我结合了旋转生成的圆圈而不影响整体外观的能力。如果您使用动画路径并且需要控制它的开始位置,这将非常有用。

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 :(得分:1)

对于像我这样寻找椭圆属性进行路径转换的人:

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`

答案 9 :(得分:1)

这些答案太复杂了。

更简单的方法是在不创建两个弧或转换为不同坐标系的情况下执行此操作。

这假设您的画布区域的宽度为w,高度为h

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

只需使用&#34;长弧&#34;标志,所以满标志被填满。然后使弧度为99.9999%的整圆。在视觉上它是一样的。只需启动圆圈最右边的圆圈(从中心直接水平的一个半径),避免扫描标记。

答案 10 :(得分:0)

另一种方法是使用两个Cubic Bezier曲线。那些使用pocketSVG的iOS用户不能识别svg arc参数。

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

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

答案 11 :(得分:0)

我在这里做了一个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))

link

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

答案 12 :(得分:-1)

这些例子太复杂了!!!

只需使用es6模板文字即可。

更简单的方法是在不创建两个弧的情况下执行此操作..

这假设您的画布区域的宽度为w,高度为h。

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

只需使用“long arc”标志,即填充完整标志。然后使弧度为99.9999%的整圆。在视觉上它是一样的。只需启动圆圈最右边的圆圈(从中心直接水平的一个半径),避免扫描标记。