Javascript 如何使用开始和结束角度渲染svg圆
我已经使用start和endAngle渲染了svg圆。它工作得很好。但是当我渲染整个圆(startAngle为70,endAngle为70)时,输出会有很大的不同(除了0、90、180、270)。我犯了什么错误Javascript 如何使用开始和结束角度渲染svg圆,javascript,svg,path,geometry,angle,Javascript,Svg,Path,Geometry,Angle,我已经使用start和endAngle渲染了svg圆。它工作得很好。但是当我渲染整个圆(startAngle为70,endAngle为70)时,输出会有很大的不同(除了0、90、180、270)。我犯了什么错误 function getPathArc(center, start, end, radius) { end -= this.isCompleteAngle(start, end) ? 0.0001 : 0;
function getPathArc(center, start, end, radius) {
end -= this.isCompleteAngle(start, end) ? 0.0001 : 0;
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
return this.getCirclePath(
center, getLocationFromAngle(start, radius, center),
getLocationFromAngle(end, radius, center), radius, (degree < 180) ? 0 : 1
);
}
function getCirclePath(center, start, end, radius, clockWise) {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' +
radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y;
}
function getLocationFromAngle(degree, radius, center) {
var radian = (degree * Math.PI) / 180;
return {
x : Math.cos(radian) * radius + center.x,
y : Math.sin(radian) * radius + center.y
}
}
function isCompleteAngle(startAngle, endAngle) {
var totalAngle = endAngle - startAngle;
totalAngle = totalAngle <= 0 ? (totalAngle + 360) : totalAngle;
return Math.floor(totalAngle / 360) !== 0;
}
函数getPathArc(中心、起点、终点、半径){
end-=此.isCompleteAngle(开始、结束)?0.0001:0;
var度=结束-开始;
度=度<0?(度+360):度;
返回此文件。getCirclePath(
中心,getLocationFromAngle(起点、半径、中心),
getLocationFromAngle(端点、半径、中心)、半径(度<180)?0:1
);
}
函数getCirclePath(中心、起点、终点、半径、顺时针){
返回'M'+start.x+''+start.y+'A'+radius+''+
半径+'0'+顺时针+'1'+末端x+''+末端y;
}
函数getLocationFromAngle(度、半径、中心){
var弧度=(度*数学PI)/180;
返回{
x:Math.cos(弧度)*半径+中心.x,
y:数学。sin(弧度)*半径+中心。y
}
}
函数isCompleteAngle(起始角、结束角){
var totalAngle=endAngle-startAngle;
totalAngle=totalAngle我将建议一个可行的解决方案,但其确切机制我无法解释(编辑:在@LeBeau中解释) 这是代码中的罪魁祸首:
end -= this.isCompleteAngle(start, end) ? 0.0001 : 0;
我们可以清楚地看到,如果我们在三元数为true
时增加值,也就是说,增加end
变量的减法量,奇怪的效果就会消失。让我们展示一下
使用非常小的减法,只需0.00001
,即可使奇异效果更加明显:
函数getPathArc(中心、起点、终点、半径){
end-=此.isCompleteAngle(开始、结束)?0.00001:0;
var度=结束-开始;
度=度<0?(度+360):度;
返回此文件。getCirclePath(
中心,getLocationFromAngle(起点、半径、中心),
getLocationFromAngle(端点、半径、中心)、半径(度<180)?0:1
);
}
函数getCirclePath(中心、起点、终点、半径、顺时针){
返回'M'+start.x+''+start.y+'A'+radius+''+
半径+'0'+顺时针+'1'+末端x+''+末端y;
}
函数getLocationFromAngle(度、半径、中心){
var弧度=(度*数学PI)/180;
返回{
x:Math.cos(弧度)*半径+中心.x,
y:数学。sin(弧度)*半径+中心。y
}
}
函数isCompleteAngle(起始角、结束角){
var totalAngle=endAngle-startAngle;
totalAngle=totalAngle圆之间的差异是由于数值精度的影响。由于SVG圆弧和浮点运算的工作方式,在最终圆弧中,起点和终点的微小变化可能会被夸大。圆弧跨越的角度越大,效果发挥的越大 要绘制圆弧,渲染器需要首先确定圆的中心。如果尝试绘制360度的圆弧,则起点和终点几乎相同 考虑以下示例: 绿色和红色点是圆弧的起点和终点。灰色点是圆的中心,渲染器计算圆以绘制圆弧 图中的圆弧表示大约359度。现在想象一下,将红色和绿色点移近。确定中心点所需的计算将越来越容易受到起点和终点坐标以及浮点算术函数不准确的影响 此外,
sin()
和cos()
函数只是sin和cos曲线的近似值。请记住,浏览器Javascript引擎必须平衡速度和精度
此外,大多数(如果不是全部的话)SVG渲染引擎都使用贝塞尔曲线来近似圆弧,但贝塞尔曲线不能完美地表示圆弧
希望你现在能明白为什么你会得到这样的结果。尝试用一个圆弧来表示大角度是个坏主意。我个人的建议是至少用三个或四个圆弧来表示一个完整的圆
函数getPathArc(中心、起点、终点、半径){
如果(结束==开始)结束+=360;
var度=结束-开始;
度=度<0?(度+360):度;
var点=[];
点。推(getLocationFromAngle(起点、半径、中心));
点.推(getLocationFromAngle(起点+度/3,半径,中心));
点.推(getLocationFromAngle(起点+度*2/3,半径,中心));
点。推(getLocationFromAngle(端点、半径、中心));
返回这个.getCirclePath(点,半径,(度<180)?0:1;
}
函数getCirclePath(点、半径、顺时针){
返回['M',点[0].x,点[0].y,
“A”,半径,半径,0,0,顺时针,点[1]。x,点[1]。y,
“A”,半径,半径,0,0,顺时针,点[2]。x,点[2]。y,
“A”,半径,半径,0,0,顺时针,点[3]。x,点[3]。y
].加入(“”);
}
函数getLocationFromAngle(度、半径、中心){
var弧度=(度*数学PI)/180;
返回{
x:Math.cos(弧度)*半径+中心.x,
y:数学。sin(弧度)*半径+中心。y
}
}
getElementById(“arc1”).setAttribute(“d”,getPathArc({x:250,y:250},90,90,200));
document.getElementById(“arc2”).setAttribute(“d”,getPathArc({x:250,y:250},70,70,200));
@Gerado感谢dude的宝贵评论。回答得很好,我知道一些SVG专家(你)会在这里透露一些信息。