马黑黑 发表于 2025-9-14 12:42

子元素响应鼠标指针旋转

本帖最后由 马黑黑 于 2025-9-14 14:06 编辑 <br /><br /><div class="codebox" data-prev="1">
&lt;style&gt;
        #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));
        }
&lt;/style&gt;

&lt;div id="pa"&gt;
        &lt;div id="son"&gt;&lt;/div&gt;
        &lt;output id="aMsg"&gt;0&lt;/output&gt;
&lt;/div&gt;

&lt;script&gt;
        pa.onmousemove = (e) =&gt; {
                // 旋转中心 : 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 &lt; 0) angle += 360;
                return angle;
        }
&lt;/script&gt;
</div>

<script type="module">
import linenumber from 'https://638183.freep.cn/638183/web/js/linenumber.js';
linenumber();
</script>

马黑黑 发表于 2025-9-14 13:17

一、关于旋转中心:

      指旋转对象即子元素的旋转中心坐标基于父元素的坐标值。比如本例,子元素 #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 14:09

马黑黑 发表于 2025-9-14 13:17
一、关于旋转中心:

      指旋转对象即子元素的旋转中心坐标基于父元素的坐标值。比如本例,子元素 # ...

貌似反正切三角函数的值在一三象限是正,二四象限是负。{:4_173:}

红影 发表于 2025-9-14 14:09

这个指针完全跟着鼠标转动,非常灵活,太神奇了{:4_199:}

梦江南 发表于 2025-9-14 17:24

指针完全跟着鼠标转动,非常灵活,太神奇了.{:4_199:}

马黑黑 发表于 2025-9-14 17:27

梦江南 发表于 2025-9-14 17:24
指针完全跟着鼠标转动,非常灵活,太神奇了.

好玩吧

马黑黑 发表于 2025-9-14 17:27

红影 发表于 2025-9-14 14:09
这个指针完全跟着鼠标转动,非常灵活,太神奇了

{:4_190:}

马黑黑 发表于 2025-9-14 17:27

红影 发表于 2025-9-14 14:09
貌似反正切三角函数的值在一三象限是正,二四象限是负。
你说的是坐标值吧?我提到的是西塔角度值

梦江南 发表于 2025-9-14 17:34

马黑黑 发表于 2025-9-14 17:27
好玩吧

嗯,太好玩了。老师厉害!

马黑黑 发表于 2025-9-14 17:35

梦江南 发表于 2025-9-14 17:34
嗯,太好玩了。老师厉害!

哪里哪里

花飞飞 发表于 2025-9-14 17:50

这个指针随粘着鼠标不放了。。走哪跟哪{:4_170:}
中间的钉子钉得很牢啊。。。扯不掉。。

花飞飞 发表于 2025-9-14 18:03

这算法厉害,不仅能随鼠标移动,还能实时显示角度,右边开始,顺为正,逆为负。。。
通篇就一个大写的字:牛。。。

红影 发表于 2025-9-14 18:28

马黑黑 发表于 2025-9-14 17:27
你说的是坐标值吧?我提到的是西塔角度值

也是哦,那里面直接显示角度的,的确是一二象限是负呢。是的,我说的是坐标值,原来和西塔角度值还是有区别的呢。

红影 发表于 2025-9-14 18:29

马黑黑 发表于 2025-9-14 17:27


这个反应好快啊,所有的都是直接反应的。

马黑黑 发表于 2025-9-14 18:29

红影 发表于 2025-9-14 18:29
这个反应好快啊,所有的都是直接反应的。

是的吧

马黑黑 发表于 2025-9-14 18:30

红影 发表于 2025-9-14 18:28
也是哦,那里面直接显示角度的,的确是一二象限是负呢。是的,我说的是坐标值,原来和西塔角度值还是有区 ...

之前做过的圆形进度条,使用的是判断坐标值,会有点繁琐

马黑黑 发表于 2025-9-14 18:30

花飞飞 发表于 2025-9-14 18:03
这算法厉害,不仅能随鼠标移动,还能实时显示角度,右边开始,顺为正,逆为负。。。
通篇就一个大写的字: ...

取得西塔夹角的角度是前提

马黑黑 发表于 2025-9-14 18:30

花飞飞 发表于 2025-9-14 17:50
这个指针随粘着鼠标不放了。。走哪跟哪
中间的钉子钉得很牢啊。。。扯不掉。。

是滴

红影 发表于 2025-9-14 18:45

马黑黑 发表于 2025-9-14 18:29
是的吧

特别神奇{:4_187:}

红影 发表于 2025-9-14 18:49

马黑黑 发表于 2025-9-14 18:30
之前做过的圆形进度条,使用的是判断坐标值,会有点繁琐

现在知道了,这里的是以3点钟方向为0,9点钟方向为正负180,上面的从逆时针0到-180,下面的顺时针0到180,这样的角度规定也很奇特。
页: [1] 2 3 4 5 6 7 8
查看完整版本: 子元素响应鼠标指针旋转