子元素响应鼠标指针旋转
本帖最后由 马黑黑 于 2025-9-14 14:06 编辑 <br /><br /><div class="codebox" data-prev="1"><style>
#pa {
margin: 20px auto;
padding: 10px;
width: 700px;
height: 600px;
border: 1px solid gray;
background:
linear-gradient(gray,gray) no-repeat 50%/100% 1px,
linear-gradient(gray,gray) no-repeat 50%/1px 100%;
position: relative;
}
#son {
--deg: 0deg;
position: absolute;
left: 50%;
top: calc(50% - 10px);
width: 150px;
height: 20px;
background: linear-gradient(90deg, teal 90%, red 91%, red);
transform-origin: 0 50%;
transform: rotate(var(--deg));
}
</style>
<div id="pa">
<div id="son"></div>
<output id="aMsg">0</output>
</div>
<script>
pa.onmousemove = (e) => {
// 旋转中心 : pa元素中央
const center = {x: pa.clientWidth/2, y: pa.clientHeight/2};
// 动态点(A): 鼠标指针所在点
const point = {x: e.clientX, y: e.clientY};
// 获取角度 : 参数是pa父元素和两个坐标点对象
let a = getAngle(pa, center, point);
// 驱动son子元素旋转
son.style.setProperty('--deg', a + 'deg');
// 输出角度信息
aMsg.value = '角度 : ' + a;
};
function getAngle(element, pointC, pointA) {
const rect = element.getBoundingClientRect();
// 旋转中心
const cx = pointC.x, cy = pointC.y;
// 计算点A的X、Y坐标
const px = pointA.x - rect.left, py = pointA.y - rect.top;
// 计算点A和旋转中心的坐标差值
const dx = px - cx, dy = py - cy;
// 计算西塔(θ)夹角
let angle = Math.atan2(dy, dx) * 180 / Math.PI;
// 1、2象限角度为负数,若需要处理
//if (angle < 0) angle += 360;
return angle;
}
</script>
</div>
<script type="module">
import linenumber from 'https://638183.freep.cn/638183/web/js/linenumber.js';
linenumber();
</script> 一、关于旋转中心:
指旋转对象即子元素的旋转中心坐标基于父元素的坐标值。比如本例,子元素 #son 的 transition-origin 属性设置为 0 50%,再依据其所定位的 left 和 top 属性值,可以得知,子元素旋转的中心点恰好位于 #pa 元素的正中央,就以 {x: pa.clientWidth/2, y: pa.clientHeight/2} 为旋转中心点坐标传值给 getAngle() 函数。
假如子元素随意布局,例如,left: 200px; top: 180px;,则需要计算一下子元素 #son 的旋转中心点位于父元素 #pa 坐标系的位置,需要结合 transform-origin 属性进行计算,保持 0 50% 不变的话,得到的应该是 {x: 200, y: 170},传值就用这个。
二、关于动态点(A)
pointA 是动态点,是鼠标指针移动或点击时从 event 那里拿到的 clientX 和 clientY 坐标值,拿到值后直接传值,函数 getAngle() 会对该值进行偏移等相关处理。
三、关于 getAngle() 函数
此函数其实是计算 θ 夹角。大概意思是,已知中心点(中心点)坐标和点A(动态点)坐标,求点A的θ夹角。点A的坐标值基于直角坐标系,但没有四个象限,因为HTML是以矩形的左上角当作坐标的起点,我们需要把这个起点“挪动”也是,这就需要将点A的坐标值 x 和 y 分别减去所在元素 element 的 left 和 top 属性值,这两个值通过元素的 getBoundingClientRect() 方法得到。然后计算点A和点C的X、Y坐标值的差值,通过反正切三角函数算出θ夹角角度,该夹角即为点A与点C及穿过中心点右向水平线所形成的角(∠ACX)。
象限是直角坐标系(迪卡尔坐标系)的分区,以中心点 O 为中心,画水平线和垂直线相交于O点,可将区域划分为四个部分:右上为第一象限(角度为负数值),左上为第二象限(角度为负数值),左下为第三象限(角度为正数值),右下为第四象限(角度为正数值)。O所在点不属于任何一个象限。OX指向三点钟方向,是 0 度。
getAngle() 函数可能编写的不够严谨,使用时如碰上问题再研究、调整。 马黑黑 发表于 2025-9-14 13:17
一、关于旋转中心:
指旋转对象即子元素的旋转中心坐标基于父元素的坐标值。比如本例,子元素 # ...
貌似反正切三角函数的值在一三象限是正,二四象限是负。{:4_173:} 这个指针完全跟着鼠标转动,非常灵活,太神奇了{:4_199:} 指针完全跟着鼠标转动,非常灵活,太神奇了.{:4_199:} 梦江南 发表于 2025-9-14 17:24
指针完全跟着鼠标转动,非常灵活,太神奇了.
好玩吧 红影 发表于 2025-9-14 14:09
这个指针完全跟着鼠标转动,非常灵活,太神奇了
{:4_190:} 红影 发表于 2025-9-14 14:09
貌似反正切三角函数的值在一三象限是正,二四象限是负。
你说的是坐标值吧?我提到的是西塔角度值 马黑黑 发表于 2025-9-14 17:27
好玩吧
嗯,太好玩了。老师厉害! 梦江南 发表于 2025-9-14 17:34
嗯,太好玩了。老师厉害!
哪里哪里 这个指针随粘着鼠标不放了。。走哪跟哪{:4_170:}
中间的钉子钉得很牢啊。。。扯不掉。。 这算法厉害,不仅能随鼠标移动,还能实时显示角度,右边开始,顺为正,逆为负。。。
通篇就一个大写的字:牛。。。 马黑黑 发表于 2025-9-14 17:27
你说的是坐标值吧?我提到的是西塔角度值
也是哦,那里面直接显示角度的,的确是一二象限是负呢。是的,我说的是坐标值,原来和西塔角度值还是有区别的呢。 马黑黑 发表于 2025-9-14 17:27
这个反应好快啊,所有的都是直接反应的。 红影 发表于 2025-9-14 18:29
这个反应好快啊,所有的都是直接反应的。
是的吧 红影 发表于 2025-9-14 18:28
也是哦,那里面直接显示角度的,的确是一二象限是负呢。是的,我说的是坐标值,原来和西塔角度值还是有区 ...
之前做过的圆形进度条,使用的是判断坐标值,会有点繁琐 花飞飞 发表于 2025-9-14 18:03
这算法厉害,不仅能随鼠标移动,还能实时显示角度,右边开始,顺为正,逆为负。。。
通篇就一个大写的字: ...
取得西塔夹角的角度是前提 花飞飞 发表于 2025-9-14 17:50
这个指针随粘着鼠标不放了。。走哪跟哪
中间的钉子钉得很牢啊。。。扯不掉。。
是滴 马黑黑 发表于 2025-9-14 18:29
是的吧
特别神奇{:4_187:} 马黑黑 发表于 2025-9-14 18:30
之前做过的圆形进度条,使用的是判断坐标值,会有点繁琐
现在知道了,这里的是以3点钟方向为0,9点钟方向为正负180,上面的从逆时针0到-180,下面的顺时针0到180,这样的角度规定也很奇特。