diff --git a/src/hooks/useUniformDisplayElement.ts b/src/hooks/useUniformDisplayElement.ts
index 2a2dd9a1..a64d52a8 100644
--- a/src/hooks/useUniformDisplayElement.ts
+++ b/src/hooks/useUniformDisplayElement.ts
@@ -4,9 +4,33 @@ import { PPTElement, Slide } from '@/types/slides'
import { getElementRange, getElementListRange, getRectRotatedOffset } from '@/utils/element'
import useHistorySnapshot from './useHistorySnapshot'
-interface SortedElementData {
+interface ElementItem {
+ min: number;
+ max: number;
el: PPTElement;
+}
+
+interface GroupItem {
+ groupId: string;
+ els: PPTElement[];
+}
+
+interface GroupElementsItem {
+ min: number;
+ max: number;
+ els: PPTElement[];
+}
+
+type Item = ElementItem | GroupElementsItem
+
+interface ElementWithPos {
pos: number;
+ el: PPTElement;
+}
+
+interface LastPos {
+ min: number;
+ max: number;
}
export default () => {
@@ -17,44 +41,95 @@ export default () => {
const { addHistorySnapshot } = useHistorySnapshot()
+ const displayItemCount = computed(() => {
+ let count = 0
+ const groupIdList: string[] = []
+ for (const el of activeElementList.value) {
+ if (!el.groupId) count += 1
+ else if (!groupIdList.includes(el.groupId)) {
+ groupIdList.push(el.groupId)
+ count += 1
+ }
+ }
+ return count
+ })
// 水平均匀排列
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
- })
+ // 分别获取普通元素和组合元素集合,并记录下每一项的范围
+ const singleElemetList: ElementItem[] = []
+ let groupList: GroupItem[] = []
+ for (const el of copyOfActiveElementList) {
+ if (!el.groupId) {
+ const { minX, maxX } = getElementRange(el)
+ singleElemetList.push({ min: minX, max: maxX, el })
+ }
+ else {
+ const groupEl = groupList.find(item => item.groupId === el.groupId)
+ if (!groupEl) groupList.push({ groupId: el.groupId, els: [el] })
+ else {
+ groupList = groupList.map(item => item.groupId === el.groupId ? { ...item, els: [...item.els, el] } : item)
+ }
+ }
+ }
+ const formatedGroupList: GroupElementsItem[] = []
+ for (const groupItem of groupList) {
+ const { minX, maxX } = getElementListRange(groupItem.els)
+ formatedGroupList.push({ min: minX, max: maxX, els: groupItem.els })
+ }
+
+ // 将普通元素和组合元素集合组合在一起,然后将每一项按位置(从左到右)排序
+ const list: Item[] = [...singleElemetList, ...formatedGroupList]
+ list.sort((itemA, itemB) => itemA.min - itemB.min)
// 计算元素均匀分布所需要的间隔:
// (所选元素整体范围 - 所有所选元素宽度和) / (所选元素数 - 1)
let totalWidth = 0
- for (const element of activeElementList.value) {
- const { minX: elMinX, maxX: elMaxX } = getElementRange(element)
- totalWidth += (elMaxX - elMinX)
+ for (const item of list) {
+ const width = item.max - item.min
+ totalWidth += width
}
- const span = ((maxX - minX) - totalWidth) / (activeElementList.value.length - 1)
+ const span = ((maxX - minX) - totalWidth) / (list.length - 1)
- // 将所选元素按位置顺序依次计算目标位置
- // 注意pos并非元素目标left值,而是目标位置范围最小值(元素旋转后的left值 ≠ 范围最小值)
- const sortedElementData: SortedElementData[] = []
- for (const element of copyOfActiveElementList) {
- if (!sortedElementData.length) {
- const { minX: firstElMinX } = getElementRange(element)
- sortedElementData.push({ el: element, pos: firstElMinX })
- continue
+ // 按位置顺序依次计算每一个元素的目标位置
+ // 第一项中的元素即为起点,无序计算
+ // 从第二项开始,每一项的位置应该为:上一项位置 + 上一项宽度 + 间隔
+ // 注意此处计算的位置(pos)并非元素最终的left值,而是目标位置范围最小值(元素旋转后的left值 ≠ 范围最小值)
+ const sortedElementData: ElementWithPos[] = []
+
+ const firstItem = list[0]
+ let lastPos: LastPos = { min: firstItem.min, max: firstItem.max }
+
+ if ('el' in firstItem) {
+ sortedElementData.push({ pos: firstItem.min, el: firstItem.el })
+ }
+ else {
+ for (const el of firstItem.els) {
+ const { minX: pos } = getElementRange(el)
+ sortedElementData.push({ pos, el })
+ }
+ }
+
+ for (let i = 1; i < list.length; i++) {
+ const item = list[i]
+ const lastWidth = lastPos.max - lastPos.min
+ const currentPos = lastPos.min + lastWidth + span
+ const currentWidth = item.max - item.min
+ lastPos = { min: currentPos, max: currentPos + currentWidth }
+
+ if ('el' in item) {
+ sortedElementData.push({ pos: currentPos, el: item.el })
+ }
+ else {
+ for (const el of item.els) {
+ const { minX } = getElementRange(el)
+ const offset = minX - item.min
+ sortedElementData.push({ pos: currentPos + offset, el })
+ }
}
-
- 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 })
}
// 根据目标位置计算元素最终目标left值
@@ -89,33 +164,69 @@ export default () => {
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
- })
+ const singleElemetList: ElementItem[] = []
+ let groupList: GroupItem[] = []
+ for (const el of copyOfActiveElementList) {
+ if (!el.groupId) {
+ const { minY, maxY } = getElementRange(el)
+ singleElemetList.push({ min: minY, max: maxY, el })
+ }
+ else {
+ const groupEl = groupList.find(item => item.groupId === el.groupId)
+ if (!groupEl) groupList.push({ groupId: el.groupId, els: [el] })
+ else {
+ groupList = groupList.map(item => item.groupId === el.groupId ? { ...item, els: [...item.els, el] } : item)
+ }
+ }
+ }
+ const formatedGroupList: GroupElementsItem[] = []
+ for (const groupItem of groupList) {
+ const { minY, maxY } = getElementListRange(groupItem.els)
+ formatedGroupList.push({ min: minY, max: maxY, els: groupItem.els })
+ }
+
+ const list: Item[] = [...singleElemetList, ...formatedGroupList]
+ list.sort((itemA, itemB) => itemA.min - itemB.min)
let totalHeight = 0
- for (const element of activeElementList.value) {
- const { minY: elMinY, maxY: elMaxY } = getElementRange(element)
- totalHeight += (elMaxY - elMinY)
+ for (const item of list) {
+ const height = item.max - item.min
+ totalHeight += height
}
- const span = ((maxY - minY) - totalHeight) / (activeElementList.value.length - 1)
+ const span = ((maxY - minY) - totalHeight) / (list.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 sortedElementData: ElementWithPos[] = []
+
+ const firstItem = list[0]
+ let lastPos: LastPos = { min: firstItem.min, max: firstItem.max }
+
+ if ('el' in firstItem) {
+ sortedElementData.push({ pos: firstItem.min, el: firstItem.el })
+ }
+ else {
+ for (const el of firstItem.els) {
+ const { minY: pos } = getElementRange(el)
+ sortedElementData.push({ pos, el })
+ }
+ }
+
+ for (let i = 1; i < list.length; i++) {
+ const item = list[i]
+ const lastHeight = lastPos.max - lastPos.min
+ const currentPos = lastPos.min + lastHeight + span
+ const currentHeight = item.max - item.min
+ lastPos = { min: currentPos, max: currentPos + currentHeight }
+
+ if ('el' in item) {
+ sortedElementData.push({ pos: currentPos, el: item.el })
+ }
+ else {
+ for (const el of item.els) {
+ const { minY } = getElementRange(el)
+ const offset = minY - item.min
+ sortedElementData.push({ pos: currentPos + offset, el })
+ }
}
-
- 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) {
@@ -143,6 +254,7 @@ export default () => {
}
return {
+ displayItemCount,
uniformHorizontalDisplay,
uniformVerticalDisplay,
}
diff --git a/src/views/Editor/Toolbar/MultiPositionPanel.vue b/src/views/Editor/Toolbar/MultiPositionPanel.vue
index 83e65ba0..49b743df 100644
--- a/src/views/Editor/Toolbar/MultiPositionPanel.vue
+++ b/src/views/Editor/Toolbar/MultiPositionPanel.vue
@@ -22,7 +22,7 @@
-
+
@@ -55,7 +55,7 @@ export default defineComponent({
const { combineElements, uncombineElements } = useCombineElement()
const { alignActiveElement } = useAlignActiveElement()
const { alignElementToCanvas } = useAlignElementToCanvas()
- const { uniformHorizontalDisplay, uniformVerticalDisplay } = useUniformDisplayElement()
+ const { displayItemCount, uniformHorizontalDisplay, uniformVerticalDisplay } = useUniformDisplayElement()
// 判断当前多选的几个元素是否可以组合
const canCombine = computed(() => {
@@ -75,7 +75,7 @@ export default defineComponent({
}
return {
- activeElementList,
+ displayItemCount,
canCombine,
combineElements,
uncombineElements,