File size: 6,789 Bytes
89ce340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { PPTElement } from '@/types/slides'
import { ElementAlignCommands } from '@/types/edit'
import { getElementListRange, getRectRotatedOffset } from '@/utils/element'
import useHistorySnapshot from './useHistorySnapshot'

interface RangeMap {
  [id: string]: ReturnType<typeof getElementListRange> 
}

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: RangeMap = {}
    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,
  }
}