CatPtain's picture
Upload 339 files
89ce340 verified
raw
history blame
3.62 kB
import type { Ref } from 'vue'
import { useSlidesStore } from '@/store'
import type { PPTElement, PPTLineElement, PPTVideoElement, PPTAudioElement, PPTChartElement } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
/**
* 计算给定坐标到原点连线的弧度
* @param x 坐标x
* @param y 坐标y
*/
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)
// 靠近45倍数的角度时有吸附效果
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,
}
}