MultiSelectOperate.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <template>
  2. <div
  3. class="multi-select-operate"
  4. :style="{
  5. left: minX + 'px',
  6. top: minY + 'px',
  7. transform: `scale(${1 / canvasScale})`,
  8. }"
  9. >
  10. <BorderLine v-for="line in borderLines" :key="line.type" :type="line.type" :style="line.style" />
  11. <template v-if="!disableResizablePoint">
  12. <ResizablePoint
  13. v-for="point in resizablePoints"
  14. :key="point.type"
  15. :type="point.type"
  16. :style="point.style"
  17. @mousedown.stop="scaleMultiElement($event, { minX, maxX, minY, maxY }, point.direction)"
  18. />
  19. </template>
  20. </div>
  21. </template>
  22. <script lang="ts">
  23. import { computed, defineComponent, reactive, PropType, watchEffect, toRefs } from 'vue'
  24. import { useStore } from 'vuex'
  25. import { State } from '@/store'
  26. import { PPTElement, ElementTypes } from '@/types/slides'
  27. import { getElementListRange } from '@/utils/element'
  28. import { ElementScaleHandler, OperateResizablePointTypes, OperateBorderLineTypes, MultiSelectRange, OperatePoints } from '@/types/edit'
  29. import ResizablePoint from '@/views/_common/_operate/ResizablePoint.vue'
  30. import BorderLine from '@/views/_common/_operate/BorderLine.vue'
  31. export default defineComponent({
  32. name: 'multi-select-operate',
  33. components: {
  34. ResizablePoint,
  35. BorderLine,
  36. },
  37. props: {
  38. elementList: {
  39. type: Array as PropType<PPTElement[]>,
  40. required: true,
  41. },
  42. scaleMultiElement: {
  43. type: Function as PropType<(e: MouseEvent, range: MultiSelectRange, command: ElementScaleHandler) => void>,
  44. required: true,
  45. },
  46. },
  47. setup(props) {
  48. const store = useStore<State>()
  49. const activeElementIdList = computed(() => store.state.activeElementIdList)
  50. const canvasScale = computed(() => store.state.canvasScale)
  51. const localActiveElementList = computed(() => props.elementList.filter(el => activeElementIdList.value.includes(el.id)))
  52. const range = reactive({
  53. minX: 0,
  54. maxX: 0,
  55. minY: 0,
  56. maxY: 0,
  57. })
  58. const width = computed(() => (range.maxX - range.minX) * canvasScale.value)
  59. const height = computed(() => (range.maxY - range.minY) * canvasScale.value)
  60. const resizablePoints = computed(() => {
  61. return [
  62. { type: OperateResizablePointTypes.TL, direction: OperatePoints.LEFT_TOP, style: {} },
  63. { type: OperateResizablePointTypes.TC, direction: OperatePoints.TOP, style: {left: width.value / 2 + 'px'} },
  64. { type: OperateResizablePointTypes.TR, direction: OperatePoints.RIGHT_TOP, style: {left: width.value + 'px'} },
  65. { type: OperateResizablePointTypes.ML, direction: OperatePoints.LEFT, style: {top: height.value / 2 + 'px'} },
  66. { type: OperateResizablePointTypes.MR, direction: OperatePoints.RIGHT, style: {left: width.value + 'px', top: height.value / 2 + 'px'} },
  67. { type: OperateResizablePointTypes.BL, direction: OperatePoints.LEFT_BOTTOM, style: {top: height.value + 'px'} },
  68. { type: OperateResizablePointTypes.BC, direction: OperatePoints.BOTTOM, style: {left: width.value / 2 + 'px', top: height.value + 'px'} },
  69. { type: OperateResizablePointTypes.BR, direction: OperatePoints.RIGHT_BOTTOM, style: {left: width.value + 'px', top: height.value + 'px'} },
  70. ]
  71. })
  72. const borderLines = computed(() => {
  73. return [
  74. { type: OperateBorderLineTypes.T, style: {width: width.value + 'px'} },
  75. { type: OperateBorderLineTypes.B, style: {top: height.value + 'px', width: width.value + 'px'} },
  76. { type: OperateBorderLineTypes.L, style: {height: height.value + 'px'} },
  77. { type: OperateBorderLineTypes.R, style: {left: width.value + 'px', height: height.value + 'px'} },
  78. ]
  79. })
  80. const disableResizablePoint = computed(() => {
  81. return localActiveElementList.value.some(item => {
  82. if(
  83. (item.type === ElementTypes.IMAGE || item.type === ElementTypes.SHAPE) &&
  84. !item.rotate
  85. ) return false
  86. return true
  87. })
  88. })
  89. const setRange = () => {
  90. const { minX, maxX, minY, maxY } = getElementListRange(localActiveElementList.value)
  91. range.minX = minX
  92. range.maxX = maxX
  93. range.minY = minY
  94. range.maxY = maxY
  95. }
  96. watchEffect(setRange)
  97. return {
  98. ...toRefs(range),
  99. borderLines,
  100. disableResizablePoint,
  101. resizablePoints,
  102. }
  103. },
  104. })
  105. </script>
  106. <style lang="scss" scoped>
  107. .multi-select-operate {
  108. position: absolute;
  109. top: 0;
  110. left: 0;
  111. z-index: 100;
  112. }
  113. </style>