gpt4 book ai didi

javascript - 如何使用 start 和 endAngle 渲染 svg 圆

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:30:43 26 4
gpt4 key购买 nike

我已经使用 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;
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;
}

示例链接:https://jsfiddle.net/fNPvf/43106/

enter image description here

绿色圆圈呈现正确,因为开始和结束 Angular 为 90,即使我将 Angular 更改为 0、180、270 和 360,它也能正常工作。但实际问题是我使用 70 的红色圆圈,除了那些 Angular (0、90、180、270、360)之外,问题也会出现。

如何解决这个问题?

最佳答案

圆圈之间的这种差异是由于数值精度的影响。由于 SVG 弧线和浮点运算的工作方式,起点和终点的微小变化可能会在最终弧线中被夸大。弧线跨越的 Angular 越大,效果就越明显。

要绘制圆弧,渲染器需要先确定圆心。如果你试图做一个 360 度的圆弧,你的起点和终点将几乎相同。

考虑下图:

enter image description here

绿色和红色的点是圆弧的起点和终点。灰色点是渲染器为了绘制圆弧而计算的圆心。

图中的圆弧代表大约 359 度。现在想象将红点和绿点移得更近。确定中心点所需的计算将变得越来越容易受到起点和终点坐标以及浮点运算函数不准确的影响。

此外,sin()cos() 函数只是 sin 和 cos 曲线的近似值。请记住,浏览器 Javascript 引擎必须平衡速度和准确性。

此外,大多数(如果不是全部)SVG 渲染引擎使用贝塞尔曲线来近似圆弧。但是贝塞尔曲线不能完美地表示圆弧。

希望您现在可以了解为什么会得到这样的结果。试图用单个圆弧表示大 Angular 是个坏主意。我个人的建议是一个完整的圆至少使用三到四个弧。

function getPathArc(center, start, end, radius) {
if (end == start) end += 360;
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
var points = [];
points.push( getLocationFromAngle(start, radius, center) );
points.push( getLocationFromAngle(start+degree/3, radius, center) );
points.push( getLocationFromAngle(start+degree*2/3, radius, center) );
points.push( getLocationFromAngle(end, radius, center) );
return this.getCirclePath(points, radius, (degree < 180) ? 0 : 1);
}

function getCirclePath(points, radius, clockWise) {
return ['M', points[0].x, points[0].y,
'A', radius, radius, 0, 0, clockWise, points[1].x, points[1].y,
'A', radius, radius, 0, 0, clockWise, points[2].x, points[2].y,
'A', radius, radius, 0, 0, clockWise, points[3].x, points[3].y
].join(' ');
}

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

document.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));
<svg width="500" height="500">
<path id="arc1" fill="none" stroke="green" stroke-width="8" />
<path id="arc2" fill="none" stroke="red" stroke-width="3" />
</svg>

关于javascript - 如何使用 start 和 endAngle 渲染 svg 圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45094884/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com