马黑黑 发表于 2022-7-11 19:50

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多个小球(演示:二楼,代码三楼)。


马黑黑 发表于 2022-7-11 19:51

<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:51

本帖最后由 马黑黑 于 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>


红影 发表于 2022-7-11 20:42

半径的取值r: num(0,180)是用实际半径200扣掉小球的直径20来的吧,这样所有的小球至少离开边线10 ,要是出现紧贴边线的,扣除10就可以了吧{:4_204:}

红影 发表于 2022-7-11 20:43

黑黑的讲解条理清晰,非常清楚,很赞{:4_199:}

马黑黑 发表于 2022-7-11 20:53

红影 发表于 2022-7-11 20:43
黑黑的讲解条理清晰,非常清楚,很赞

可能数学部分没讲的深透,不过那真实初中的知识点

马黑黑 发表于 2022-7-11 20:54

红影 发表于 2022-7-11 20:42
半径的取值r: num(0,180)是用实际半径200扣掉小球的直径20来的吧,这样所有的小球至少离开边线10 ,要是出 ...

理论上是这样

加林森 发表于 2022-7-12 08:25

来学习

红影 发表于 2022-7-12 08:58

马黑黑 发表于 2022-7-11 20:53
可能数学部分没讲的深透,不过那真实初中的知识点

这个真不用讲,的确是初中的东西。估计较难理解的是很多人对弧度难理解点,只是一个度数和弧度转换而已。

通常半径容易获得,角度很难知道吧,所以这个也只能是随机的点了{:4_173:}

红影 发表于 2022-7-12 09:00

马黑黑 发表于 2022-7-11 20:54
理论上是这样

对于固定的半径,这个公式是圆周上的点,对变化的半径,而且是在大圆环范围内的,所以,现在得到的虽然是一个个半径下的圆周点,但实际也是大圆环内的随机点。对大圆环来说并不是圆周点。

马黑黑 发表于 2022-7-12 12:05

红影 发表于 2022-7-12 09:00
对于固定的半径,这个公式是圆周上的点,对变化的半径,而且是在大圆环范围内的,所以,现在得到的虽然是 ...

对。取值如果不做这样的范围设定,且赋left和top值时减去小球的宽或高的一半,则所有的小球都串在圆周线上

马黑黑 发表于 2022-7-12 12:06

红影 发表于 2022-7-12 08:58
这个真不用讲,的确是初中的东西。估计较难理解的是很多人对弧度难理解点,只是一个度数和弧度转换而已。 ...

可以计算。比如说,均匀分布10个小球,则 360 / 10 就能得到每个小球的角度。这个,看应用情景。

马黑黑 发表于 2022-7-12 12:06

加林森 发表于 2022-7-12 08:25
来学习

喝水{:4_191:}

加林森 发表于 2022-7-12 12:10

马黑黑 发表于 2022-7-12 12:06
喝水

谢谢。

红影 发表于 2022-7-12 19:37

马黑黑 发表于 2022-7-12 12:05
对。取值如果不做这样的范围设定,且赋left和top值时减去小球的宽或高的一半,则所有的小球都串在圆周线 ...

嗯,如果用相同的角度,就会均匀地在圆周上。

红影 发表于 2022-7-12 19:40

马黑黑 发表于 2022-7-12 12:06
可以计算。比如说,均匀分布10个小球,则 360 / 10 就能得到每个小球的角度。这个,看应用情景。

我是说在大圆环里的分布。其实只要半径随机了,角度不一定随机。哦,不对,那会有某个方向上少一部分。

马黑黑 发表于 2022-7-12 20:01

红影 发表于 2022-7-12 19:40
我是说在大圆环里的分布。其实只要半径随机了,角度不一定随机。哦,不对,那会有某个方向上少一部分。

那个随机,都考虑过的

马黑黑 发表于 2022-7-12 20:03

红影 发表于 2022-7-12 19:37
嗯,如果用相同的角度,就会均匀地在圆周上。

不是的。角度相同,就在一个方向上,如果半径、圆心形同,则在同一个圆周点上。

红影 发表于 2022-7-13 22:02

马黑黑 发表于 2022-7-12 20:01
那个随机,都考虑过的

嗯嗯,现在知道了{:4_204:}

红影 发表于 2022-7-13 22:02

马黑黑 发表于 2022-7-12 20:03
不是的。角度相同,就在一个方向上,如果半径、圆心形同,则在同一个圆周点上。

我是顺着前面说的,就是指半径相同和同心的情况呀{:4_173:}
页: [1] 2 3 4
查看完整版本: JS:求圆周点坐标