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, } }