JS:求圆周点坐标
求圆周上任意一点的坐标,需要的已知条件有:圆心坐标:x,y
半径:r
角度:a
当然,还有圆周率(PI)必不可少,所用到的数学知识还有相关的三角函数,余弦和正弦(初三知识),对应JS内置的余弦函数 cos() 和正弦函数 sin()。cos()和sin()都需要弧度参数(数学中说的是非直角对边或邻边与斜边之比),而弧度的计算公式是:
2*PI/360*a (a为已知角度)
上面弧度计算公式可以简化为:a*PI/180,用JS表达则为:a * Math.PI / 180。
得到已知角度的弧度后,根据三角形余弦、正弦原理,半径乘以弧度加上圆心坐标将分别得到该角度对应圆周上的点的x、y坐标。故此,设圆周上的任意一点为x1、y1,则:
x1 = x + r * cos(a * PI / 180)
y1 = y + r * sin(a * PI / 180)
根据以上推算的原理,我们封装一个函数,用以获取圆周上任意点的xy坐标。
function calcCirclePos({x,y,r,a}) {
let x1 = x + r * Math.cos((a * Math.PI) / 180);
let y1 = y + r * Math.sin((a * Math.PI) / 180);
return {x1,y1};
}
函数完全就是数学运算的演绎,不同的是用上了JS特定的 Math 数学方法,比如 Math.cos()、Math.sin、Math.PI,分别对应于 cos、sin和PI。calcCirclePos() 函数以对象为参数,放在花括号 {} 里,其中,x、y为圆心坐标值,r为半径,a为角度。函数将返回一个对象,该对象有两个属性,x1 和 y1。
关于对象,我们之前几乎没有系统介绍,这里简单说一说,然后再回到我们的主题。在JS里,一个对象可以这样表达:
let person = {
name: '张三',
age: 18,
qq: 123456,
phone: 33669988
}
person 是一个对象,该对象有诸多属性(还可以有方法),属性与属性值用小角冒号隔开。当我们想知道 person 的QQ号时,直接读取person的qq属性即可,记为 person.qq:
console.log(person.qq);
这将在控制台打印出 123456 这个QQ号(谁的QQ号呢?张三。qq和name都是person的属性)。
那么,回到我们的 calcCirclePos() 函数,它通过对已知条件(花括号对象传递过来的参数)的相关计算,将返回一个对象,对象的名称就是调用该函数的变量:
let pos = calcCirclePos({
x: 100,
y: 100,
r: 100,
a: 60
});
pos就是一个对象。上面说过,calcCirclePos() 函数所接受的参数也是对象,所以我们用花括号将圆形坐标x和y、半径r、角度a等传递给函数,叫函数为我们求出60度所对应的圆周上的点的xy坐标值,同时通过声明变量创建了一个对象 pos ,pos 对象则通过调用 calcCirclePos() 函数返回对象的属性和属性值,该对象属性有两个,x1 和 y1 即60度角对应圆周点的xy坐标:
console.log(pos.x1,pos.y1);
控制台显示:150 186.60254037844385,这是我们所需要的结果。
应用场景举例:在一个圆形元素中随机分布N多个小球(演示:二楼,代码三楼)。
<style>
#circle {
margin: 50px auto 0;
width: 400px;
height: 400px;
border-radius: 50%;
background: radial-gradient(transparent,green);
position: relative;
}
.ball {
position: absolute;
width: 20px;
height: 20px;
border-radius: 50%;
background: linear-gradient(120deg,#eee,red);
}
</style>
<div id="circle"></div>
<script>
let total = 20;
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;
for(j=0; j<total; j++) {
let ele = document.createElement('span');
ele.className = 'ball';
let pos = calcCirclePos({x: 200, y: 200, r: num(0,180), a: num(0,360)});
ele.style.left = pos.x1 - 10 + 'px';
ele.style.top = pos.y1 - 10 + 'px';
circle.appendChild(ele);
}
let balls = document.querySelectorAll('.ball');
//求圆周点坐标函数: x、y 圆心坐标,r 半径,a 角度
function calcCirclePos({x,y,r,a}) {
let x1 = x + r * Math.cos((a * Math.PI) / 180);
let y1 = y + r * Math.sin((a * Math.PI) / 180);
return {x1,y1};
}
</script> 本帖最后由 马黑黑 于 2022-7-11 19:53 编辑
代码
<style>
#circle {
margin: 50px auto 0;
width: 400px;
height: 400px;
border-radius: 50%;
background: radial-gradient(transparent,green);
position: relative;
}
.ball {
position: absolute;
width: 20px;
height: 20px;
border-radius: 50%;
background: linear-gradient(120deg,#eee,red);
}
</style>
<div id="circle"></div>
<script>
let total = 20;
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;
for(j=0; j<total; j++) {
let ele = document.createElement('span');
ele.className = 'ball';
let pos = calcCirclePos({x: 200, y: 200, r: num(0,180), a: num(0,360)});
ele.style.left = pos.x1 - 10 + 'px';
ele.style.top = pos.y1 - 10 + 'px';
circle.appendChild(ele);
}
//求圆周点坐标函数: x、y 圆心坐标,r 半径,a 角度
function calcCirclePos({x,y,r,a}) {
let x1 = x + r * Math.cos((a * Math.PI) / 180);
let y1 = y + r * Math.sin((a * Math.PI) / 180);
return {x1,y1};
}
</script>
半径的取值r: num(0,180)是用实际半径200扣掉小球的直径20来的吧,这样所有的小球至少离开边线10 ,要是出现紧贴边线的,扣除10就可以了吧{:4_204:} 黑黑的讲解条理清晰,非常清楚,很赞{:4_199:} 红影 发表于 2022-7-11 20:43
黑黑的讲解条理清晰,非常清楚,很赞
可能数学部分没讲的深透,不过那真实初中的知识点 红影 发表于 2022-7-11 20:42
半径的取值r: num(0,180)是用实际半径200扣掉小球的直径20来的吧,这样所有的小球至少离开边线10 ,要是出 ...
理论上是这样 来学习 马黑黑 发表于 2022-7-11 20:53
可能数学部分没讲的深透,不过那真实初中的知识点
这个真不用讲,的确是初中的东西。估计较难理解的是很多人对弧度难理解点,只是一个度数和弧度转换而已。
通常半径容易获得,角度很难知道吧,所以这个也只能是随机的点了{:4_173:} 马黑黑 发表于 2022-7-11 20:54
理论上是这样
对于固定的半径,这个公式是圆周上的点,对变化的半径,而且是在大圆环范围内的,所以,现在得到的虽然是一个个半径下的圆周点,但实际也是大圆环内的随机点。对大圆环来说并不是圆周点。 红影 发表于 2022-7-12 09:00
对于固定的半径,这个公式是圆周上的点,对变化的半径,而且是在大圆环范围内的,所以,现在得到的虽然是 ...
对。取值如果不做这样的范围设定,且赋left和top值时减去小球的宽或高的一半,则所有的小球都串在圆周线上 红影 发表于 2022-7-12 08:58
这个真不用讲,的确是初中的东西。估计较难理解的是很多人对弧度难理解点,只是一个度数和弧度转换而已。 ...
可以计算。比如说,均匀分布10个小球,则 360 / 10 就能得到每个小球的角度。这个,看应用情景。 加林森 发表于 2022-7-12 08:25
来学习
喝水{:4_191:} 马黑黑 发表于 2022-7-12 12:06
喝水
谢谢。 马黑黑 发表于 2022-7-12 12:05
对。取值如果不做这样的范围设定,且赋left和top值时减去小球的宽或高的一半,则所有的小球都串在圆周线 ...
嗯,如果用相同的角度,就会均匀地在圆周上。 马黑黑 发表于 2022-7-12 12:06
可以计算。比如说,均匀分布10个小球,则 360 / 10 就能得到每个小球的角度。这个,看应用情景。
我是说在大圆环里的分布。其实只要半径随机了,角度不一定随机。哦,不对,那会有某个方向上少一部分。 红影 发表于 2022-7-12 19:40
我是说在大圆环里的分布。其实只要半径随机了,角度不一定随机。哦,不对,那会有某个方向上少一部分。
那个随机,都考虑过的 红影 发表于 2022-7-12 19:37
嗯,如果用相同的角度,就会均匀地在圆周上。
不是的。角度相同,就在一个方向上,如果半径、圆心形同,则在同一个圆周点上。 马黑黑 发表于 2022-7-12 20:01
那个随机,都考虑过的
嗯嗯,现在知道了{:4_204:} 马黑黑 发表于 2022-7-12 20:03
不是的。角度相同,就在一个方向上,如果半径、圆心形同,则在同一个圆周点上。
我是顺着前面说的,就是指半径相同和同心的情况呀{:4_173:}