index.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <template>
  2. <div
  3. class="operate"
  4. :class="{ 'multi-select': isMultiSelect && !isActive }"
  5. :style="{
  6. top: elementInfo.top * canvasScale + 'px',
  7. left: elementInfo.left * canvasScale + 'px',
  8. transform: `rotate(${rotate}deg)`,
  9. transformOrigin: `${elementInfo.width * canvasScale / 2}px ${height * canvasScale / 2}px`,
  10. }"
  11. >
  12. <component
  13. v-if="isSelected"
  14. :is="currentOperateComponent"
  15. :elementInfo="elementInfo"
  16. :handlerVisible="!elementInfo.lock && (isActiveGroupElement || !isMultiSelect)"
  17. :rotateElement="rotateElement"
  18. :scaleElement="scaleElement"
  19. :dragLineElement="dragLineElement"
  20. :moveShapeKeypoint="moveShapeKeypoint"
  21. ></component>
  22. <div
  23. class="animation-index"
  24. v-if="toolbarState === 'elAnimation' && elementIndexListInAnimation.length"
  25. >
  26. <div class="index-item" v-for="index in elementIndexListInAnimation" :key="index">{{index + 1}}</div>
  27. </div>
  28. <LinkHandler
  29. :elementInfo="elementInfo"
  30. :link="elementInfo.link"
  31. :openLinkDialog="openLinkDialog"
  32. v-if="isActive && elementInfo.link"
  33. @mousedown.stop=""
  34. />
  35. </div>
  36. </template>
  37. <script lang="ts" setup>
  38. import { computed } from 'vue'
  39. import { storeToRefs } from 'pinia'
  40. import { useMainStore, useSlidesStore } from '@/store'
  41. import {
  42. ElementTypes,
  43. type PPTElement,
  44. type PPTLineElement,
  45. type PPTVideoElement,
  46. type PPTAudioElement,
  47. type PPTShapeElement,
  48. type PPTChartElement,
  49. } from '@/types/slides'
  50. import type { OperateLineHandlers, OperateResizeHandlers } from '@/types/edit'
  51. import ImageElementOperate from './ImageElementOperate.vue'
  52. import TextElementOperate from './TextElementOperate.vue'
  53. import ShapeElementOperate from './ShapeElementOperate.vue'
  54. import LineElementOperate from './LineElementOperate.vue'
  55. import TableElementOperate from './TableElementOperate.vue'
  56. import CommonElementOperate from './CommonElementOperate.vue'
  57. import LinkHandler from './LinkHandler.vue'
  58. const props = defineProps<{
  59. elementInfo: PPTElement
  60. isSelected: boolean
  61. isActive: boolean
  62. isActiveGroupElement: boolean
  63. isMultiSelect: boolean
  64. rotateElement: (e: MouseEvent, element: Exclude<PPTElement, PPTChartElement | PPTLineElement | PPTVideoElement | PPTAudioElement>) => void
  65. scaleElement: (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: OperateResizeHandlers) => void
  66. dragLineElement: (e: MouseEvent, element: PPTLineElement, command: OperateLineHandlers) => void
  67. moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement, index: number) => void
  68. openLinkDialog: () => void
  69. }>()
  70. const { canvasScale, toolbarState } = storeToRefs(useMainStore())
  71. const { formatedAnimations } = storeToRefs(useSlidesStore())
  72. const currentOperateComponent = computed<unknown>(() => {
  73. const elementTypeMap = {
  74. [ElementTypes.IMAGE]: ImageElementOperate,
  75. [ElementTypes.TEXT]: TextElementOperate,
  76. [ElementTypes.SHAPE]: ShapeElementOperate,
  77. [ElementTypes.LINE]: LineElementOperate,
  78. [ElementTypes.TABLE]: TableElementOperate,
  79. [ElementTypes.CHART]: CommonElementOperate,
  80. [ElementTypes.LATEX]: CommonElementOperate,
  81. [ElementTypes.VIDEO]: CommonElementOperate,
  82. [ElementTypes.AUDIO]: CommonElementOperate,
  83. }
  84. return elementTypeMap[props.elementInfo.type] || null
  85. })
  86. const elementIndexListInAnimation = computed(() => {
  87. const indexList = []
  88. for (let i = 0; i < formatedAnimations.value.length; i++) {
  89. const elIds = formatedAnimations.value[i].animations.map(item => item.elId)
  90. if (elIds.includes(props.elementInfo.id)) indexList.push(i)
  91. }
  92. return indexList
  93. })
  94. const rotate = computed(() => 'rotate' in props.elementInfo ? props.elementInfo.rotate : 0)
  95. const height = computed(() => 'height' in props.elementInfo ? props.elementInfo.height : 0)
  96. </script>
  97. <style lang="scss" scoped>
  98. .operate {
  99. position: absolute;
  100. z-index: 100;
  101. user-select: none;
  102. &.multi-select {
  103. opacity: 0.2;
  104. }
  105. }
  106. .animation-index {
  107. position: absolute;
  108. top: 0;
  109. left: -24px;
  110. font-size: 12px;
  111. .index-item {
  112. width: 18px;
  113. height: 18px;
  114. background-color: #fff;
  115. color: $themeColor;
  116. border: 1px solid $themeColor;
  117. display: flex;
  118. justify-content: center;
  119. align-items: center;
  120. & + .index-item {
  121. margin-top: 5px;
  122. }
  123. }
  124. }
  125. </style>