useRotateElement.ts 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { Ref, computed } from 'vue'
  2. import { MutationTypes, useStore } from '@/store'
  3. import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides'
  4. import useHistorySnapshot from '@/hooks/useHistorySnapshot'
  5. /**
  6. * 计算给定坐标到原点连线的弧度
  7. * @param x 坐标x
  8. * @param y 坐标y
  9. */
  10. const getAngleFromCoordinate = (x: number, y: number) => {
  11. const radian = Math.atan2(x, y)
  12. const angle = 180 / Math.PI * radian
  13. return angle
  14. }
  15. export default (elementList: Ref<PPTElement[]>, viewportRef: Ref<HTMLElement | undefined>) => {
  16. const store = useStore()
  17. const canvasScale = computed(() => store.state.canvasScale)
  18. const { addHistorySnapshot } = useHistorySnapshot()
  19. // 旋转元素
  20. const rotateElement = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => {
  21. let isMouseDown = true
  22. let angle = 0
  23. const elOriginRotate = element.rotate || 0
  24. const elLeft = element.left
  25. const elTop = element.top
  26. const elWidth = element.width
  27. const elHeight = element.height
  28. // 元素中心点(旋转中心点)
  29. const centerX = elLeft + elWidth / 2
  30. const centerY = elTop + elHeight / 2
  31. if (!viewportRef.value) return
  32. const viewportRect = viewportRef.value.getBoundingClientRect()
  33. document.onmousemove = e => {
  34. if (!isMouseDown) return
  35. // 计算当前鼠标位置相对元素中心点连线的角度(弧度)
  36. const mouseX = (e.pageX - viewportRect.left) / canvasScale.value
  37. const mouseY = (e.pageY - viewportRect.top) / canvasScale.value
  38. const x = mouseX - centerX
  39. const y = centerY - mouseY
  40. angle = getAngleFromCoordinate(x, y)
  41. // 靠近45倍数的角度时有吸附效果
  42. const sorptionRange = 5
  43. if ( Math.abs(angle) <= sorptionRange ) angle = 0
  44. else if ( angle > 0 && Math.abs(angle - 45) <= sorptionRange ) angle -= (angle - 45)
  45. else if ( angle < 0 && Math.abs(angle + 45) <= sorptionRange ) angle -= (angle + 45)
  46. else if ( angle > 0 && Math.abs(angle - 90) <= sorptionRange ) angle -= (angle - 90)
  47. else if ( angle < 0 && Math.abs(angle + 90) <= sorptionRange ) angle -= (angle + 90)
  48. else if ( angle > 0 && Math.abs(angle - 135) <= sorptionRange ) angle -= (angle - 135)
  49. else if ( angle < 0 && Math.abs(angle + 135) <= sorptionRange ) angle -= (angle + 135)
  50. else if ( angle > 0 && Math.abs(angle - 180) <= sorptionRange ) angle -= (angle - 180)
  51. else if ( angle < 0 && Math.abs(angle + 180) <= sorptionRange ) angle -= (angle + 180)
  52. elementList.value = elementList.value.map(el => element.id === el.id ? { ...el, rotate: angle } : el)
  53. }
  54. document.onmouseup = () => {
  55. isMouseDown = false
  56. document.onmousemove = null
  57. document.onmouseup = null
  58. if (elOriginRotate === angle) return
  59. store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value })
  60. addHistorySnapshot()
  61. }
  62. }
  63. return {
  64. rotateElement,
  65. }
  66. }