如何使用 start 和 endAngle 渲染 svg 圆

2024-04-17

我使用 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/ https://jsfiddle.net/fNPvf/43106/

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

如何清除这个问题?


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

为了绘制圆弧,渲染器需要首先确定圆心。如果您尝试制作 360 度的圆弧,则起点和终点将几乎相同。

考虑下图:

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

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

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

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

希望您现在能明白为什么会得到这样的结果。尝试用单个弧线表示大角度是一个坏主意。我个人的建议是至少使用三个或四个圆弧来形成一个完整的圆。

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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 start 和 endAngle 渲染 svg 圆 的相关文章

随机推荐

  • 从 GoDaddy 托管的 ASP.NET MVC 应用程序发送邮件消息时出现问题

    我在 GoDaddy 托管的 MVC Web 应用程序上有一个表单 用户可以填写该表单并发送给我们的办公室 我目前正在使用 Gmail 帐户和 GoDaddy 电子邮件帐户 链接到我的托管空间 对其进行测试 使用 Gmail 代码后 电子邮
  • 如何使用自动生成的列隐藏 ASP.NET GridView 中的列?

    即使 SqlDataSource1 DataBind GridView1 Columns Count 也始终为零 但网格没问题 I can do for int i 0 i lt GridView1 HeaderRow Cells Coun
  • Android CursorLoader 带有选择和selectionArgs[]

    我在用Loader for RecyclerView Adapter列出项目 我想列出数据库表中的特定项目 所以我做了 public Loader
  • 从 csv 文件创建代理时使用 to-reports

    我的问题有点长 如果您能阅读全部内容 我真的很感激 并且我将非常感谢您的任何建议 我有与 2 位海龟消费者相关的数据 他们对笔记本电脑的功能进行了评级 笔记本电脑有两种特征 屏幕尺寸和电池寿命 每个都有一些级别 例如电池续航时间有5小时 1
  • 从 firebase 渲染 FlatList 中的数据

    我正在使用 React Native 0 49 我从 firebase 中获取了数据 用户列表users 这个列表中的每一项都是这样设置的firebase database ref users userId set userInfo 用户
  • bigquery 允许的表数量是否有限制

    BigQuery 中可以拥有的表数量有限制吗 我正在尝试创建多个小表以减少查询成本 谢谢 表的数量没有限制 由于查询字符串的长度有 10k 的限制 因此您可能会在查询所有这些内容时遇到问题
  • 使用承诺 - 在失败处理程序中记录堆栈跟踪

    我对 Nodejs 相当陌生 所以我将更详细地解释我想要做什么 我有一个网络服务器 如果请求失败 我想记录该异常的堆栈跟踪 但提供错误页面而不是使服务器崩溃 例如 处理请求的函数 var Q require q var requestHan
  • 使用 awk 对单独行上的多个字段进行数学运算

    我一直在对 3 字段 x 2 行文件进行一些数学运算 如下所示 3216 01 2724 81 1708 25 1762 48 617 436 1650 79 我的问题是如何引用第一行的第一个字段并在同一计算中引用第二行的第一个字段 为了完
  • 使用逻辑回归时sklearn重要特征错误

    以下代码使用随机森林模型为我提供一个显示特征重要性的图表 from sklearn feature selection import SelectFromModel import matplotlib clf RandomForestCla
  • Gradle-与外部项目的多项目?

    在 Gradle 多项目设置中是否无法使用主项目文件夹之外的外部依赖项 就像在settings gradle文件 我可以没有类似的东西吗 include C some path to dependent project ChildA Chi
  • 检查 python 调试器中的复杂变量,例如 pudb

    如何使用 python 调试器检查复杂变量 列表 字典 对象 值 我是 python 新手 我尝试了 pudb 看起来当变量类型为复杂类型时 调试器仅显示变量的类型 而不显示变量的类型价值 是否可以使用 pudb 检查值 或者有其他 pyt
  • 二叉树类型实例化的高度过高

    我正在尝试类型系统 目前正在尝试在类型级别进行反向级别顺序遍历 这些是我正在使用的类型 type LEFT 0 type VALUE 1 type RIGHT 2 type List ReadonlyArray
  • django.core 序列化器和 Django Rest Framework 序列化器之间的区别

    我现在正在学习 Django 刚刚听说 Django Rest Framework DRF 我想知道 django core 序列化器和 rest framework 序列化器之间有什么区别 是的 我知道 DRF 用于 API django
  • ContentCachingResponseWrapper 生成空响应

    我正在尝试实现过滤器来记录请求和响应Spring MVC应用 我使用以下代码 Component public class LoggingFilter extends OncePerRequestFilter private static
  • 如何在 Three.js 中从三角面获取多边形?

    我在网上查了一下是否有人遇到同样的问题 我正在使用 Three js 我有一个 3DObject 其中可能包含孔 面是三角形的 假设我想从上面看到它 我的目标是获得一个代表顶面周长的多边形 这对我来说意味着不再有三角面 而只有 1 个多边形
  • 在 PHP 中,如何判断 pg_query() 是否是返回数据的查询?

    那么一次成功的mysqli query 如果没有数据则返回 true 并且返回一个mysqli result对象如果有数据 即查询是SELECT SHOW DESCRIBE or EXPLAIN 但随着成功的pg query 无论是否有任何
  • 如何将样式应用于列表中的相邻元素

    我可以只使用 CSS 来完成这个场景吗 我有一个任意长度的元素的无序列表 这些元素排列成一个由四个元素组成的网格 当用户将鼠标悬停在某个元素上时 一些附加内容将在该元素下方下拉 并将其下方的行向下推 Content is here
  • 如何将 CSS 翻译添加到现有翻译中?

    我使用 CSS 翻译将 DIV 元素放置在屏幕上 这工作得很好 除了当稍后位移相同的元素时 原始位移被丢弃 使用 javascript 设置 CSS 起始位置 div style transform translate 800px 400p
  • 监控我的应用程序在 Android 中占用的内存

    我正在尝试优化我的应用程序消耗的内存量 当我的应用程序加载时 按住 home 键 然后选择任务管理器 我可以看到该应用程序占用了 17MB 但该值不会刷新 我如何实时跟踪该值 DDMS 有这个选项吗 请具体说明我已经搜索了很多但没有找到 提
  • 如何使用 start 和 endAngle 渲染 svg 圆

    我使用 start 和 endAngle 渲染了 svg 圆 效果很好 但是当我渲染完整的圆 startAngle为70 endAngle为70 时 输出有很大的不同 0 90 180 270除外 我为这段代码做错了什么 function