如何计算圆弧(圆)的SVG路径
给定一个以(200200)为圆心,半径为25的圆,如何从270度到135度以及从270度到45度绘制圆弧 0度表示它正好位于x轴(右侧)(表示它是3点钟位置) 270度表示它是12点钟位置,90度表示它是6点钟位置 更一般地说,圆弧的路径是什么如何计算圆弧(圆)的SVG路径,svg,Svg,给定一个以(200200)为圆心,半径为25的圆,如何从270度到135度以及从270度到45度绘制圆弧 0度表示它正好位于x轴(右侧)(表示它是3点钟位置) 270度表示它是12点钟位置,90度表示它是6点钟位置 更一般地说,圆弧的路径是什么 x, y, r, d1, d2, direction 意义 center (x,y), radius r, degree_start, degree_end, direction 你想用这个。不幸的是,这需要指定起点和终点的笛卡尔坐标(x,y),而不
x, y, r, d1, d2, direction
意义
center (x,y), radius r, degree_start, degree_end, direction
你想用这个。不幸的是,这需要指定起点和终点的笛卡尔坐标(x,y),而不是现有的极坐标(半径、角度),因此必须进行一些数学计算。下面是一个JavaScript函数,它应该可以工作(尽管我还没有测试过),我希望它是不言自明的:
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];
}
哪个角度对应于哪个时钟位置取决于坐标系;只要根据需要交换和/或否定sin/cos术语即可
arc命令具有以下参数:
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
第一个例子是:
rx
=ry
=25和x轴旋转
=0,因为您想要的是圆而不是椭圆。您可以使用上述函数计算起始坐标(应M
ove to)和结束坐标(x,y),分别得到(200,175)和(182.322,217.678)左右。考虑到目前为止的这些约束,实际上可以绘制四条圆弧,因此两个标志选择其中一条。我猜你可能想画一个小弧线(意思是大弧线标志
=0),沿角度减小的方向(意思是扫掠标志
=0)。总之,SVG路径是:
M 200 175 A 25 25 0 0 0 182.322 217.678
M 200 175 A 25 25 0 1 0 217.678 217.678
对于第二个示例(假设您的意思是朝同一方向走,因此是一个大圆弧),SVG路径是:
M 200 175 A 25 25 0 0 0 182.322 217.678
M 200 175 A 25 25 0 1 0 217.678 217.678
再说一次,我还没有测试过这些
(编辑2016-06-01)如果像@clocksmith一样,你想知道他们为什么选择这个API,请看一下。他们描述了两种可能的圆弧参数化,“端点参数化”(他们选择的那个)和“中心参数化”(这与问题所使用的类似)。在“端点参数化”的描述中,他们说:
端点参数化的优点之一是它允许一致的路径语法,其中所有路径命令都以新“当前点”的坐标结束
因此,基本上,这是一个副作用的弧被视为一个更大的路径,而不是他们自己的单独对象的一部分。我认为,如果SVG渲染器不完整,它可以跳过它不知道如何渲染的任何路径组件,只要它知道它们使用了多少参数。或者,它可以使用许多组件对路径的不同块进行并行渲染。或者他们这样做是为了确保舍入误差不会沿着复杂路径的长度累积
实现说明对于原始问题也很有用,因为它们有更多的数学伪代码用于在两个参数化之间转换(我第一次写这个答案时没有意识到这一点)。扩展@wdebeaum的伟大答案,下面是一个生成弧形路径的方法:
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;
}
在你的html中
<path id="arc1" fill="none" stroke="#446688" stroke-width="20" />
我对圆形部分进行了轻微修改并制作了支撑填充。
JS
函数极坐标(centerX、centerY、半径、角度等){
var angleInRadians=(angleInDegrees-90)*Math.PI/180.0;
返回{
x:centerX+(半径*数学坐标(角半径)),
y:中心y+(半径*数学正弦(角度半径))
};
}
函数描述C(x,y,半径,星形,端角){
var起点=极笛卡尔坐标(x,y,半径,端角);
var end=极笛卡尔坐标(x,y,半径,星形);
var arcSweep=endAngle-startAnglewdebeaum的原始极笛卡尔函数是正确的:
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”绘制“正常”计数器时钟方向的圆弧,
我认为这更直截了当。
参见我想对@Ahtenus answer发表评论,特别是对Ray Hulha的评论,他说代码笔没有显示任何弧度,但我的声誉不够高
这个代码笔不工作的原因是它的html错误,笔划宽度为零
我修复了它,并在这里添加了第二个示例:
html:
<svg>
<path id="theSvgArc"/>
<path id="theSvgArc2"/>
</svg>
javascript:
document.getElementById("theSvgArc").setAttribute("d", describeArc(150, 150, 100, 0, 180));
document.getElementById("theSvgArc2").setAttribute("d", describeArc(300, 150, 100, 45, 190));
对@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));
函数极坐标(centerX、centerY、半径、角度等){
var angleInRadians=(angleInDegrees-90)*Math.PI/180.0;
返回{
x:centerX+(半径*数学坐标(角半径)),
y:中心y+(半径*数学正弦(角度半径))
};
}
函数描述C(x,y,半径,星形,端角){
var endAngleOriginal=endAngle;
if(endAngleOriginal-startAngle==360){
端角=359;
}
var起点=极笛卡尔坐标(x,y,半径,端角);
var end=极笛卡尔坐标(x,y,半径,星形);
var arcSweep=endAngle-startAngle@opsb的答案很简洁,但中心点并不准确,而且,正如@Jithin所指出的,如果角度是360度,则根本不会绘制任何图形
@Jithin修复了360度的问题,但是如果选择小于360度,则会得到一条闭合圆弧环的线,这不是必需的
我修复了这个问题,并在下面的代码中添加了一些动画:
函数myArc(cx,cy,半径,max){
var circle=document.getElementById(“弧”);
var e=circle.getAttribute(“d”);
var d=“M”+(cx+半径)+++cy;
var角=0;
window.timer=window.setInterval(
函数(){
var弧度=ang
document.getElementById("theSvgArc").setAttribute("d", describeArc(150, 150, 100, 0, 180));
document.getElementById("theSvgArc2").setAttribute("d", describeArc(300, 150, 100, 45, 190));
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));
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;
console.log(describeArc(255,255,220,30,180));
console.log(describeArc(CenterX,CenterY,Radius,startAngle,EndAngle))
const angleInRadians = angleInDegrees => (angleInDegrees - 90) * (Math.PI / 180.0);
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
const a = angleInRadians(angleInDegrees);
return {
x: centerX + (radius * Math.cos(a)),
y: centerY + (radius * Math.sin(a)),
};
};
const arc = (x, y, radius, startAngle, endAngle) => {
const fullCircle = endAngle - startAngle === 360;
const start = polarToCartesian(x, y, radius, endAngle - 0.01);
const end = polarToCartesian(x, y, radius, startAngle);
const arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
const d = [
'M', start.x, start.y,
'A', radius, radius, 0, arcSweep, 0, end.x, end.y,
].join(' ');
if (fullCircle) d.push('z');
return d;
};
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, xf, yf