mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 多元素自动水平/垂直均匀分布
This commit is contained in:
parent
7c7ec3d52d
commit
5be272f77e
158
src/hooks/useUniformDisplayElement.ts
Normal file
158
src/hooks/useUniformDisplayElement.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import { computed } from 'vue'
|
||||
import { MutationTypes, useStore } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { getElementRange, getElementListRange, getRectRotatedRange } from '@/utils/element'
|
||||
import useHistorySnapshot from './useHistorySnapshot'
|
||||
|
||||
interface SortedElementData {
|
||||
el: PPTElement;
|
||||
pos: number;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||
const activeElementList = computed<PPTElement[]>(() => store.getters.activeElementList)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
// 水平均匀排列
|
||||
const uniformHorizontalDisplay = () => {
|
||||
const { minX, maxX } = getElementListRange(activeElementList.value)
|
||||
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
||||
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
|
||||
|
||||
copyOfActiveElementList.sort((elementA, elementB) => {
|
||||
const { minX: elAMinX } = getElementRange(elementA)
|
||||
const { minX: elBMinX } = getElementRange(elementB)
|
||||
return elAMinX - elBMinX
|
||||
})
|
||||
|
||||
let totaiWidth = 0
|
||||
for (const element of activeElementList.value) {
|
||||
const { minX: elMinX, maxX: elMaxX } = getElementRange(element)
|
||||
totaiWidth += (elMaxX - elMinX)
|
||||
}
|
||||
const span = ((maxX - minX) - totaiWidth) / (activeElementList.value.length - 1)
|
||||
|
||||
const sortedElementData: SortedElementData[] = []
|
||||
for (const element of copyOfActiveElementList) {
|
||||
if (!sortedElementData.length) {
|
||||
const { minX: firstElMinX } = getElementRange(element)
|
||||
sortedElementData.push({ el: element, pos: firstElMinX })
|
||||
continue
|
||||
}
|
||||
|
||||
const lastItemElement = sortedElementData[sortedElementData.length - 1].el
|
||||
const lastItemPos = sortedElementData[sortedElementData.length - 1].pos
|
||||
const { minX: lastElementMinX, maxX: lastElementMaxX } = getElementRange(lastItemElement)
|
||||
const lastElementWidth = lastElementMaxX - lastElementMinX
|
||||
|
||||
sortedElementData.push({ el: element, pos: lastItemPos + lastElementWidth + span })
|
||||
}
|
||||
|
||||
for (const element of newElementList) {
|
||||
if (!activeElementIdList.value.includes(element.id)) continue
|
||||
|
||||
for (const sortedItem of sortedElementData) {
|
||||
if (sortedItem.el.id === element.id) {
|
||||
if ('rotate' in element && element.rotate) {
|
||||
const { xRange: originXRange } = getRectRotatedRange({
|
||||
left: element.left,
|
||||
top: element.top,
|
||||
width: element.width,
|
||||
height: element.height,
|
||||
rotate: 0,
|
||||
})
|
||||
const { xRange: rotatedXRange } = getRectRotatedRange({
|
||||
left: element.left,
|
||||
top: element.top,
|
||||
width: element.width,
|
||||
height: element.height,
|
||||
rotate: element.rotate,
|
||||
})
|
||||
const offsetX = rotatedXRange[0] - originXRange[0]
|
||||
element.left = sortedItem.pos - offsetX
|
||||
}
|
||||
else element.left = sortedItem.pos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
// 垂直均匀排列
|
||||
const uniformVerticalDisplay = () => {
|
||||
const { minY, maxY } = getElementListRange(activeElementList.value)
|
||||
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
||||
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
|
||||
|
||||
copyOfActiveElementList.sort((elementA, elementB) => {
|
||||
const { minY: elAMinY } = getElementRange(elementA)
|
||||
const { minY: elBMinY } = getElementRange(elementB)
|
||||
return elAMinY - elBMinY
|
||||
})
|
||||
|
||||
let totaiHeight = 0
|
||||
for (const element of activeElementList.value) {
|
||||
const { minY: elMinY, maxY: elMaxY } = getElementRange(element)
|
||||
totaiHeight += (elMaxY - elMinY)
|
||||
}
|
||||
const span = ((maxY - minY) - totaiHeight) / (activeElementList.value.length - 1)
|
||||
|
||||
const sortedElementData: SortedElementData[] = []
|
||||
for (const element of copyOfActiveElementList) {
|
||||
if (!sortedElementData.length) {
|
||||
const { minY: firstElMinY } = getElementRange(element)
|
||||
sortedElementData.push({ el: element, pos: firstElMinY })
|
||||
continue
|
||||
}
|
||||
|
||||
const lastItemElement = sortedElementData[sortedElementData.length - 1].el
|
||||
const lastItemPos = sortedElementData[sortedElementData.length - 1].pos
|
||||
const { minY: lastElementMinY, maxY: lastElementMaxY } = getElementRange(lastItemElement)
|
||||
const lastElementHeight = lastElementMaxY - lastElementMinY
|
||||
|
||||
sortedElementData.push({ el: element, pos: lastItemPos + lastElementHeight + span })
|
||||
}
|
||||
|
||||
for (const element of newElementList) {
|
||||
if (!activeElementIdList.value.includes(element.id)) continue
|
||||
|
||||
for (const sortedItem of sortedElementData) {
|
||||
if (sortedItem.el.id === element.id) {
|
||||
if ('rotate' in element && element.rotate) {
|
||||
const { yRange: originYRange } = getRectRotatedRange({
|
||||
left: element.left,
|
||||
top: element.top,
|
||||
width: element.width,
|
||||
height: element.height,
|
||||
rotate: 0,
|
||||
})
|
||||
const { yRange: rotatedYRange } = getRectRotatedRange({
|
||||
left: element.left,
|
||||
top: element.top,
|
||||
width: element.width,
|
||||
height: element.height,
|
||||
rotate: element.rotate,
|
||||
})
|
||||
const offsetY = rotatedYRange[0] - originYRange[0]
|
||||
element.top = sortedItem.pos - offsetY
|
||||
}
|
||||
else element.top = sortedItem.pos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
return {
|
||||
uniformHorizontalDisplay,
|
||||
uniformVerticalDisplay,
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@
|
||||
<Button style="flex: 1;" @click="alignActiveElement('bottom')"><IconAlignBottom /></Button>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup class="row" v-if="activeElementList.length > 2">
|
||||
<Button style="flex: 1;" @click="uniformHorizontalDisplay()">水平均匀分布</Button>
|
||||
<Button style="flex: 1;" @click="uniformVerticalDisplay()">垂直均匀分布</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Divider />
|
||||
|
||||
@ -38,6 +42,7 @@ import { useStore } from '@/store'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import useCombineElement from '@/hooks/useCombineElement'
|
||||
import useAlignActiveElement from '@/hooks/useAlignActiveElement'
|
||||
import useUniformDisplayElement from '@/hooks/useUniformDisplayElement'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'multi-position-panel',
|
||||
@ -47,6 +52,7 @@ export default defineComponent({
|
||||
|
||||
const { combineElements, uncombineElements } = useCombineElement()
|
||||
const { alignActiveElement } = useAlignActiveElement()
|
||||
const { uniformHorizontalDisplay, uniformVerticalDisplay } = useUniformDisplayElement()
|
||||
|
||||
// 判断当前多选的几个元素是否可以组合
|
||||
const canCombine = computed(() => {
|
||||
@ -58,10 +64,13 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
return {
|
||||
activeElementList,
|
||||
canCombine,
|
||||
combineElements,
|
||||
uncombineElements,
|
||||
alignActiveElement,
|
||||
uniformHorizontalDisplay,
|
||||
uniformVerticalDisplay,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user