|
import type { Ref } from 'vue' |
|
import { useSlidesStore } from '@/store' |
|
import type { PPTElement, PPTLineElement, PPTVideoElement, PPTAudioElement, PPTChartElement } from '@/types/slides' |
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot' |
|
|
|
|
|
|
|
|
|
|
|
|
|
const getAngleFromCoordinate = (x: number, y: number) => { |
|
const radian = Math.atan2(x, y) |
|
const angle = 180 / Math.PI * radian |
|
return angle |
|
} |
|
|
|
export default ( |
|
elementList: Ref<PPTElement[]>, |
|
viewportRef: Ref<HTMLElement | undefined>, |
|
canvasScale: Ref<number>, |
|
) => { |
|
const slidesStore = useSlidesStore() |
|
|
|
const { addHistorySnapshot } = useHistorySnapshot() |
|
|
|
|
|
const rotateElement = (e: MouseEvent | TouchEvent, element: Exclude<PPTElement, PPTChartElement | PPTLineElement | PPTVideoElement | PPTAudioElement>) => { |
|
const isTouchEvent = !(e instanceof MouseEvent) |
|
if (isTouchEvent && (!e.changedTouches || !e.changedTouches[0])) return |
|
|
|
let isMouseDown = true |
|
let angle = 0 |
|
const elOriginRotate = element.rotate || 0 |
|
|
|
const elLeft = element.left |
|
const elTop = element.top |
|
const elWidth = element.width |
|
const elHeight = element.height |
|
|
|
|
|
const centerX = elLeft + elWidth / 2 |
|
const centerY = elTop + elHeight / 2 |
|
|
|
if (!viewportRef.value) return |
|
const viewportRect = viewportRef.value.getBoundingClientRect() |
|
|
|
const handleMousemove = (e: MouseEvent | TouchEvent) => { |
|
if (!isMouseDown) return |
|
|
|
const currentPageX = e instanceof MouseEvent ? e.pageX : e.changedTouches[0].pageX |
|
const currentPageY = e instanceof MouseEvent ? e.pageY : e.changedTouches[0].pageY |
|
|
|
|
|
const mouseX = (currentPageX - viewportRect.left) / canvasScale.value |
|
const mouseY = (currentPageY - viewportRect.top) / canvasScale.value |
|
const x = mouseX - centerX |
|
const y = centerY - mouseY |
|
|
|
angle = getAngleFromCoordinate(x, y) |
|
|
|
|
|
const sorptionRange = 5 |
|
if ( Math.abs(angle) <= sorptionRange ) angle = 0 |
|
else if ( angle > 0 && Math.abs(angle - 45) <= sorptionRange ) angle -= (angle - 45) |
|
else if ( angle < 0 && Math.abs(angle + 45) <= sorptionRange ) angle -= (angle + 45) |
|
else if ( angle > 0 && Math.abs(angle - 90) <= sorptionRange ) angle -= (angle - 90) |
|
else if ( angle < 0 && Math.abs(angle + 90) <= sorptionRange ) angle -= (angle + 90) |
|
else if ( angle > 0 && Math.abs(angle - 135) <= sorptionRange ) angle -= (angle - 135) |
|
else if ( angle < 0 && Math.abs(angle + 135) <= sorptionRange ) angle -= (angle + 135) |
|
else if ( angle > 0 && Math.abs(angle - 180) <= sorptionRange ) angle -= (angle - 180) |
|
else if ( angle < 0 && Math.abs(angle + 180) <= sorptionRange ) angle -= (angle + 180) |
|
|
|
elementList.value = elementList.value.map(el => element.id === el.id ? { ...el, rotate: angle } : el) |
|
} |
|
|
|
const handleMouseup = () => { |
|
isMouseDown = false |
|
document.onmousemove = null |
|
document.onmouseup = null |
|
|
|
if (elOriginRotate === angle) return |
|
|
|
slidesStore.updateSlide({ elements: elementList.value }) |
|
addHistorySnapshot() |
|
} |
|
|
|
if (isTouchEvent) { |
|
document.ontouchmove = handleMousemove |
|
document.ontouchend = handleMouseup |
|
} |
|
else { |
|
document.onmousemove = handleMousemove |
|
document.onmouseup = handleMouseup |
|
} |
|
} |
|
|
|
return { |
|
rotateElement, |
|
} |
|
} |