PPTist/src/hooks/useAlignActiveElement.ts
2022-02-27 16:44:36 +08:00

173 lines
6.5 KiB
TypeScript

import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import { PPTElement } from '@/types/slides'
import { ElementAlignCommands } from '@/types/edit'
import { getElementListRange, getRectRotatedOffset } from '@/utils/element'
import useHistorySnapshot from './useHistorySnapshot'
export default () => {
const slidesStore = useSlidesStore()
const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
const { currentSlide } = storeToRefs(slidesStore)
const { addHistorySnapshot } = useHistorySnapshot()
/**
* 对齐选中的元素
* @param command 对齐方向
*/
const alignActiveElement = (command: ElementAlignCommands) => {
const { minX, maxX, minY, maxY } = getElementListRange(activeElementList.value)
const elementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
// 如果所选择的元素为组合元素的成员,需要计算该组合的整体范围
const groupElementRangeMap = {}
for (const activeElement of activeElementList.value) {
if (activeElement.groupId && !groupElementRangeMap[activeElement.groupId]) {
const groupElements = activeElementList.value.filter(item => item.groupId === activeElement.groupId)
groupElementRangeMap[activeElement.groupId] = getElementListRange(groupElements)
}
}
// 根据不同的命令,计算对齐的位置
if (command === ElementAlignCommands.LEFT) {
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
if ('rotate' in element && element.rotate) {
const { offsetX } = getRectRotatedOffset({
left: element.left,
top: element.top,
width: element.width,
height: element.height,
rotate: element.rotate,
})
element.left = minX - offsetX
}
else element.left = minX
}
else {
const range = groupElementRangeMap[element.groupId]
const offset = range.minX - minX
element.left = element.left - offset
}
}
})
}
else if (command === ElementAlignCommands.RIGHT) {
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
const elWidth = element.type === 'line' ? Math.max(element.start[0], element.end[0]) : element.width
if ('rotate' in element && element.rotate) {
const { offsetX } = getRectRotatedOffset({
left: element.left,
top: element.top,
width: element.width,
height: element.height,
rotate: element.rotate,
})
element.left = maxX - elWidth + offsetX
}
else element.left = maxX - elWidth
}
else {
const range = groupElementRangeMap[element.groupId]
const offset = range.maxX - maxX
element.left = element.left - offset
}
}
})
}
else if (command === ElementAlignCommands.TOP) {
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
if ('rotate' in element && element.rotate) {
const { offsetY } = getRectRotatedOffset({
left: element.left,
top: element.top,
width: element.width,
height: element.height,
rotate: element.rotate,
})
element.top = minY - offsetY
}
else element.top = minY
}
else {
const range = groupElementRangeMap[element.groupId]
const offset = range.minY - minY
element.top = element.top - offset
}
}
})
}
else if (command === ElementAlignCommands.BOTTOM) {
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
const elHeight = element.type === 'line' ? Math.max(element.start[1], element.end[1]) : element.height
if ('rotate' in element && element.rotate) {
const { offsetY } = getRectRotatedOffset({
left: element.left,
top: element.top,
width: element.width,
height: element.height,
rotate: element.rotate,
})
element.top = maxY - elHeight + offsetY
}
else element.top = maxY - elHeight
}
else {
const range = groupElementRangeMap[element.groupId]
const offset = range.maxY - maxY
element.top = element.top - offset
}
}
})
}
else if (command === ElementAlignCommands.HORIZONTAL) {
const horizontalCenter = (minX + maxX) / 2
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
const elWidth = element.type === 'line' ? Math.max(element.start[0], element.end[0]) : element.width
element.left = horizontalCenter - elWidth / 2
}
else {
const range = groupElementRangeMap[element.groupId]
const center = (range.maxX + range.minX) / 2
const offset = center - horizontalCenter
element.left = element.left - offset
}
}
})
}
else if (command === ElementAlignCommands.VERTICAL) {
const verticalCenter = (minY + maxY) / 2
elementList.forEach(element => {
if (activeElementIdList.value.includes(element.id)) {
if (!element.groupId) {
const elHeight = element.type === 'line' ? Math.max(element.start[1], element.end[1]) : element.height
element.top = verticalCenter - elHeight / 2
}
else {
const range = groupElementRangeMap[element.groupId]
const center = (range.maxY + range.minY) / 2
const offset = center - verticalCenter
element.top = element.top - offset
}
}
})
}
slidesStore.updateSlide({ elements: elementList })
addHistorySnapshot()
}
return {
alignActiveElement,
}
}