如何计算弧(圆)的SVGpath

给定以(200,200),半径25为中心的圆,我如何绘制270度到135度的弧线和270度到45度的弧线?

0度表示在x轴上(右侧)(意思是3点钟位置),270度表示12点钟位置,90表示6点钟位置

更一般地说,圆的一部分是什么是一个弧的path

x, y, r, d1, d2, direction 

含义

 center (x,y), radius r, degree_start, degree_end, direction 

在@ wdebeaum的最佳答案上展开,下面是一个生成弧形path的方法:

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

使用

 document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 180)); 

并在你的HTML

 <path id="arc1" fill="none" stroke="#446688" stroke-width="20" /> 

现场演示

你想要使用椭圆A rc命令 。 不幸的是,这需要你指定开始点和结束点的笛卡尔坐标(x,y),而不是你所拥有的极坐标(半径,angular度),所以你必须做一些math计算。 这里有一个JavaScript函数可以工作(尽pipe我没有testing过),我希望这个函数是不言而喻的:

 function polarToCartesian(centerX, centerY, radius, angleInDegrees) { var angleInRadians = angleInDegrees * Math.PI / 180.0; var x = centerX + radius * Math.cos(angleInRadians); var y = centerY + radius * Math.sin(angleInRadians); return [x,y]; } 

哪个angular度对应于哪个时钟位置取决于坐标系统; 只是在必要时交换和/或否定sin / cos项。

arc命令有这些参数:

 rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y 

举个例子:

rx = ry = 25和x-axis-rotation = 0,因为你想要一个圆而不是一个椭圆。 你可以使用上面的函数计算起始坐标(你应该到的)和结束坐标(x,y),分别产生(200,175)和大约(182.322,217.678)。 鉴于迄今为止的这些限制,实际上有四个弧可以被绘制,所以两个标志select其中之一。 我猜你可能想要在减小angular度(意思是sweep-flag = 0)的方向上绘制一个小圆弧(意思是large-arc-flag sweep-flag = 0)。 总之,SVG的path是:

 M 200 175 A 25 25 0 0 0 182.322 217.678 

对于第二个例子(假设你的意思是相同的方向,因此一个大弧),SVGpath是:

 M 200 175 A 25 25 0 1 0 217.678 217.678 

再次,我没有testing这些。

(编辑2016-06-01)如果像@clocksmith一样,你想知道他们为什么select这个API,那么看一下实现注释 。 他们描述了两个可能的电弧参数化,“端点参数化”(他们select的)和“中心参数化”(就像问题所使用的那样)。 在“端点参数化”的描述中,他们说:

端点参数化的优点之一是它允许一致的path语法,其中所有的path命令都以新的“当前点”的坐标结束。

所以基本上这是一个弧的副作用被认为是一个更大的path的一部分,而不是他们自己的单独的对象。 我想如果你的SVG渲染器是不完整的,只要知道它有多less个参数,就可以跳过任何不知道如何渲染的path组件。 或者,也许它可以并行渲染具有许多组件的path的不同块。 或者也许他们这样做是为了确保四舍五入的错误不会沿着复杂的path延伸。

实现注释对于原始问题也是有用的,因为它们在两个参数化之间有更多的math伪代码(当我第一次写这个答案时我没有意识到)。

我略微修改了opsb的答案,并支持填充圈子部门。 http://codepen.io/anon/pen/AkoGx

JS

 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 arcSweep = endAngle - startAngle <= 180 ? "0" : "1"; var d = [ "M", start.x, start.y, "A", radius, radius, 0, arcSweep, 0, end.x, end.y, "L", x,y, "L", start.x, start.y ].join(" "); return d; } document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 220)); 

HTML

 <svg> <path id="arc1" fill="orange" stroke="#446688" stroke-width="0" /> </svg> 

我想评论一下@Ahtenus的回答,特别是Ray Hulha的评论,他说codepen没有显示任何弧线,但是我的声望还不够高。

这个codepen不起作用的原因是它的html是错误的,零的中风宽度。

我修复了这个问题,并在这里添加了第二个示例: http : //codepen.io/AnotherLinuxUser/pen/QEJmkN 。

html:

 <svg> <path id="theSvgArc"/> <path id="theSvgArc2"/> </svg> 

相关的CSS:

 svg { width : 500px; height : 500px; } path { stroke-width : 5; stroke : lime; fill : #151515; } 

javascript:

 document.getElementById("theSvgArc").setAttribute("d", describeArc(150, 150, 100, 0, 180)); document.getElementById("theSvgArc2").setAttribute("d", describeArc(300, 150, 100, 45, 190)); 

wdebeaum的原始polarToCartesian函数是正确的:

 var angleInRadians = angleInDegrees * Math.PI / 180.0; 

通过使用以下命令来反转开始点和结束点:

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

是混乱(对我),因为这将扭转扫旗。 使用:

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

sweep-flag =“0”绘制“正常的”反时钟方向的弧线,我认为这是更直接的。 见https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths

对@ opsb的答案稍作修改。 我们不能用这个方法画一个完整的圆。 即如果我们给(0,360),它将不会画任何东西。 所以稍作修改以解决这个问题。 显示有时达到100%的分数可能是有用的。

 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 endAngleOriginal = endAngle; if(endAngleOriginal - startAngle === 360){ endAngle = 359; } var start = polarToCartesian(x, y, radius, endAngle); var end = polarToCartesian(x, y, radius, startAngle); var arcSweep = endAngle - startAngle <= 180 ? "0" : "1"; if(endAngleOriginal - startAngle === 360){ var d = [ "M", start.x, start.y, "A", radius, radius, 0, arcSweep, 0, end.x, end.y, "z" ].join(" "); } else{ var d = [ "M", start.x, start.y, "A", radius, radius, 0, arcSweep, 0, end.x, end.y ].join(" "); } return d; } document.getElementById("arc1").setAttribute("d", describeArc(120, 120, 100, 0, 359)); 

@ opsb的答案是整齐的,但中心点是不准确的,此外,正如@Jithin指出的,如果angular度是360,那么什么都不是。

@Jithin修正了360问题,但是如果你select了小于360度,那么你会得到一个closures弧线的线,这是不需要的。

我修正了这个问题,并在下面的代码中添加了一些animation:

 function myArc(cx, cy, radius, max){ var circle = document.getElementById("arc"); var e = circle.getAttribute("d"); var d = " M "+ (cx + radius) + " " + cy; var angle=0; window.timer = window.setInterval( function() { var radians= angle * (Math.PI / 180); // convert degree to radians var x = cx + Math.cos(radians) * radius; var y = cy + Math.sin(radians) * radius; d += " L "+x + " " + y; circle.setAttribute("d", d) if(angle==max)window.clearInterval(window.timer); angle++; } ,5) } myArc(110, 110, 100, 360); 
 <svg xmlns="http://www.w3.org/2000/svg" style="width:220; height:220;"> <path d="" id="arc" fill="none" stroke="red" stroke-width="2" /> </svg> 

这是一个古老的问题,但我发现代码有用,并保存了我三分钟的思维:)所以我给@opsb的答案增加了一个小的扩展。

如果你想把这个弧转换成一个片(为了填充),我们可以稍微修改一下代码:

 function describeArc(x, y, radius, spread, startAngle, endAngle){ var innerStart = polarToCartesian(x, y, radius, endAngle); var innerEnd = polarToCartesian(x, y, radius, startAngle); var outerStart = polarToCartesian(x, y, radius + spread, endAngle); var outerEnd = polarToCartesian(x, y, radius + spread, startAngle); var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; var d = [ "M", outerStart.x, outerStart.y, "A", radius + spread, radius + spread, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y, "L", innerEnd.x, innerEnd.y, "A", radius, radius, 0, largeArcFlag, 1, innerStart.x, innerStart.y, "L", outerStart.x, outerStart.y, "Z" ].join(" "); return d; } 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)) }; } var path = describeArc(150, 150, 50, 30, 0, 50) document.getElementById("p").innerHTML = path document.getElementById("path").setAttribute('d',path) 
 <p id="p"> </p> <svg width="300" height="300" style="border:1px gray solid"> <path id="path" fill="blue" stroke="cyan"></path> </svg> 

基于所选答案的ReactJS组件:

 import React from 'react'; const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => { const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + (radius * Math.cos(angleInRadians)), y: centerY + (radius * Math.sin(angleInRadians)) }; }; const describeSlice = (x, y, radius, startAngle, endAngle) => { const start = polarToCartesian(x, y, radius, endAngle); const end = polarToCartesian(x, y, radius, startAngle); const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; const d = [ "M", 0, 0, start.x, start.y, "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y ].join(" "); return d; }; const path = (degrees = 90, radius = 10) => { return describeSlice(0, 0, radius, 0, degrees) + 'Z'; }; export const Arc = (props) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"> <g transform="translate(150,150)" stroke="#000" strokeWidth="2"> <path d={path(props.degrees, props.radius)} fill="#333"/> </g> </svg>; export default Arc; 

你可以使用JSFiddle代码,我为上面的答案:

https://jsfiddle.net/tyw6nfee/

所有你需要做的是改变最后一行console.log代码,并给它你自己的参数:

  console.log(describeArc(255,255,220,30,180)); console.log(describeArc(CenterX,CenterY,Radius,startAngle,EndAngle))