elementRotate.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { OPERATE_KEYS } from '@/types/edit'
  2. // 给定一个坐标,计算该坐标到(0, 0)点连线的弧度值
  3. // 注意,Math.atan2的一般用法是Math.atan2(y, x)返回的是原点(0,0)到(x,y)点的线段与X轴正方向之间的弧度值
  4. // 这里将使用时将x与y的传入顺序交换了,为的是获取原点(0,0)到(x,y)点的线段与Y轴正方向之间的弧度值
  5. export const getAngleFromCoordinate = (x: number, y: number) => {
  6. const radian = Math.atan2(x, y)
  7. const angle = 180 / Math.PI * radian
  8. return angle
  9. }
  10. // 计算元素被旋转一定角度后,八个操作点的新坐标
  11. interface RotateElementData {
  12. left: number;
  13. top: number;
  14. width: number;
  15. height: number;
  16. }
  17. export const getRotateElementPoints = (element: RotateElementData, angle: number) => {
  18. const { left, top, width, height } = element
  19. const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2
  20. const auxiliaryAngle = Math.atan(height / width) * 180 / Math.PI
  21. const tlbraRadian = (180 - angle - auxiliaryAngle) * Math.PI / 180
  22. const trblaRadian = (auxiliaryAngle - angle) * Math.PI / 180
  23. const taRadian = (90 - angle) * Math.PI / 180
  24. const raRadian = angle * Math.PI / 180
  25. const halfWidth = width / 2
  26. const halfHeight = height / 2
  27. const middleLeft = left + halfWidth
  28. const middleTop = top + halfHeight
  29. const leftTopPoint = {
  30. left: middleLeft + radius * Math.cos(tlbraRadian),
  31. top: middleTop - radius * Math.sin(tlbraRadian),
  32. }
  33. const topPoint = {
  34. left: middleLeft + halfHeight * Math.cos(taRadian),
  35. top: middleTop - halfHeight * Math.sin(taRadian),
  36. }
  37. const rightTopPoint = {
  38. left: middleLeft + radius * Math.cos(trblaRadian),
  39. top: middleTop - radius * Math.sin(trblaRadian),
  40. }
  41. const rightPoint = {
  42. left: middleLeft + halfWidth * Math.cos(raRadian),
  43. top: middleTop + halfWidth * Math.sin(raRadian),
  44. }
  45. const rightBottomPoint = {
  46. left: middleLeft - radius * Math.cos(tlbraRadian),
  47. top: middleTop + radius * Math.sin(tlbraRadian),
  48. }
  49. const bottomPoint = {
  50. left: middleLeft - halfHeight * Math.sin(raRadian),
  51. top: middleTop + halfHeight * Math.cos(raRadian),
  52. }
  53. const leftBottomPoint = {
  54. left: middleLeft - radius * Math.cos(trblaRadian),
  55. top: middleTop + radius * Math.sin(trblaRadian),
  56. }
  57. const leftPoint = {
  58. left: middleLeft - halfWidth * Math.cos(raRadian),
  59. top: middleTop - halfWidth * Math.sin(raRadian),
  60. }
  61. return { leftTopPoint, topPoint, rightTopPoint, rightPoint, rightBottomPoint, bottomPoint, leftBottomPoint, leftPoint }
  62. }
  63. // 获取元素某个操作点对角线上另一端的操作点坐标(例如:左上 <-> 右下)
  64. export const getOppositePoint = (direction: number, points: ReturnType<typeof getRotateElementPoints>): { left: number; top: number } => {
  65. const oppositeMap = {
  66. [OPERATE_KEYS.RIGHT_BOTTOM]: points.leftTopPoint,
  67. [OPERATE_KEYS.LEFT_BOTTOM]: points.rightTopPoint,
  68. [OPERATE_KEYS.LEFT_TOP]: points.rightBottomPoint,
  69. [OPERATE_KEYS.RIGHT_TOP]: points.leftBottomPoint,
  70. [OPERATE_KEYS.TOP]: points.bottomPoint,
  71. [OPERATE_KEYS.BOTTOM]: points.topPoint,
  72. [OPERATE_KEYS.LEFT]: points.rightPoint,
  73. [OPERATE_KEYS.RIGHT]: points.leftPoint,
  74. }
  75. return oppositeMap[direction]
  76. }