Fork me on Bolg '◡'

JS如何使用Math.atan2获取两点之间角度的实践案例

本文主要介绍使用如何实现手动拖拽旋转元素的效果。

1、简述

最近在研究如何实现手动控制元素的旋转效果,在网上找了很多,都没有找出类似的实现,因此经过一些调研和计算,最终完美实现效果,在这里记录下来。

2、效果展示

通过手动旋转的方式,实现组件的360度无缝旋转。图示是实现结果的几个截图:

  • 0deg

  • 顺时针转到 66deg

  • 逆时针转到 315deg

  • 转到 180deg

3、实现分析

如图所示,实现难点在于计算出两点间连线的倾斜角 angle

这里需要掌握的几个知识点:

3.1 获取转动的角度

使用 Math.atan2() 函数可以非常高效的实现之,它是返回点与原点之间的倾斜角,如图所示,如果想计算出点 (x1,y1) 与 原点 (cx,cy) 与X轴的角度,只需要执行:

Math.atan2(y1 - cy, x1 - cx)

需要注意的是,它的取值范围是[-PI, PI]。
当 (x1, y1) 在第一象限, 0 < θ < PI/2

当 (x1, y1) 在第二象限 PI/2 < θ≤PI

当 (x1, y1) 在第三象限, -PI < θ < -PI/2

当 (x1, y1) 在第四象限, -PI/2 < θ < 0

3.2 角度与弧度之间的转换

角度 = 弧度 * 180 / Math.PI;
弧度= 角度 * Math.PI / 180;

3.3 组件中心点位置计算

使用getBoundingClientRect() 的方法可以获取出容器的位置信息,用当前位置减去宽/高的一半,即可获取中心点位置。

  //中心点
  cx = x + width / 2;
  cy = y + height / 2;

4、最终代码

/**
 * 获得旋转夹角
 * @param {*} x1 旋转点1
 * @param {*} y1 
 * @param {*} x2 旋转点2
 * @param {*} y2 
 */
function getAngle(x1, y1, x2, y2) {
  // 获取组件的位置信息
  let rect = document.getElementsByClassName('active-ele')[0].getBoundingClientRect();
  let {
    x,
    y,
    width,
    height
  } = rect;

  //中心点
  let cx = x + width / 2;
  let cy = y + height / 2;

  //2个点之间的角度获取
  let c1 = Math.atan2(y1 - cy, x1 - cx) * 180 / (Math.PI);
  let c2 = Math.atan2(y2 - cy, x2 - cx) * 180 / (Math.PI);
  let angle;
  c1 = c1 <= -90 ? (360 + c1) : c1;
  c2 = c2 <= -90 ? (360 + c2) : c2;

  //夹角获取
  angle = Math.floor(c2 - c1);
  angle = angle < 0 ? angle + 360 : angle;
  return angle;
}
    /**
     * 获得旋转夹角
     * @param startPos.x 指的是初始位置的x坐标
     * @param startPos.y 指的是初始位置的y坐标
     * @param startPos.r 指的是初始的旋转角度
     */
    let angle = getAngle(startPos.x, startPos.y, e.x, e.y);
    let startAngle = startPos.r;
    let deg;

    // 赋值的旋转角度
    let rotate;

    // 顺时针旋转
    if (e.x - startX > 0) {
      deg = startAngle + angle;
      rotate = deg > 360 ? deg - 360 : deg;
    } else {
    // 逆时针旋转
      angle = 360 - angle;
      deg = startAngle - angle;
      rotate = deg < 0 ? deg + 360 : deg;
    }
posted @ 2018-09-25 16:12  webhmy  阅读(6631)  评论(1编辑  收藏  举报