File size: 4,493 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
<template>

  <div

    class="operate"

    :class="{ 'multi-select': isMultiSelect && !isActive }"

    :style="{

      top: elementInfo.top * canvasScale + 'px',

      left: elementInfo.left * canvasScale + 'px',

      transform: `rotate(${rotate}deg)`,

      transformOrigin: `${elementInfo.width * canvasScale / 2}px ${height * canvasScale / 2}px`,

    }"

  >

    <component

      v-if="isSelected"

      :is="currentOperateComponent"

      :elementInfo="elementInfo"

      :handlerVisible="!elementInfo.lock && (isActiveGroupElement || !isMultiSelect)"

      :rotateElement="rotateElement"

      :scaleElement="scaleElement"

      :dragLineElement="dragLineElement"

      :moveShapeKeypoint="moveShapeKeypoint"

    ></component>



    <div 

      class="animation-index"

      v-if="toolbarState === 'elAnimation' && elementIndexListInAnimation.length"

    >

      <div class="index-item" v-for="index in elementIndexListInAnimation" :key="index">{{index + 1}}</div>

    </div>



    <LinkHandler 

      :elementInfo="elementInfo" 

      :link="elementInfo.link"

      :openLinkDialog="openLinkDialog" 

      v-if="isActive && elementInfo.link" 

      @mousedown.stop=""

    />

  </div>

</template>



<script lang="ts" setup>

import { computed } from 'vue'

import { storeToRefs } from 'pinia'

import { useMainStore, useSlidesStore } from '@/store'

import {

  ElementTypes,

  type PPTElement,

  type PPTLineElement,

  type PPTVideoElement,

  type PPTAudioElement,

  type PPTShapeElement,

  type PPTChartElement,

} from '@/types/slides'

import type { OperateLineHandlers, OperateResizeHandlers } from '@/types/edit'



import ImageElementOperate from './ImageElementOperate.vue'

import TextElementOperate from './TextElementOperate.vue'

import ShapeElementOperate from './ShapeElementOperate.vue'

import LineElementOperate from './LineElementOperate.vue'

import TableElementOperate from './TableElementOperate.vue'

import CommonElementOperate from './CommonElementOperate.vue'

import LinkHandler from './LinkHandler.vue'



const props = defineProps<{

  elementInfo: PPTElement

  isSelected: boolean

  isActive: boolean

  isActiveGroupElement: boolean

  isMultiSelect: boolean

  rotateElement: (e: MouseEvent, element: Exclude<PPTElement, PPTChartElement | PPTLineElement | PPTVideoElement | PPTAudioElement>) => void

  scaleElement: (e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: OperateResizeHandlers) => void

  dragLineElement: (e: MouseEvent, element: PPTLineElement, command: OperateLineHandlers) => void

  moveShapeKeypoint: (e: MouseEvent, element: PPTShapeElement, index: number) => void

  openLinkDialog: () => void

}>()



const { canvasScale, toolbarState } = storeToRefs(useMainStore())

const { formatedAnimations } = storeToRefs(useSlidesStore())



const currentOperateComponent = computed<unknown>(() => {

  const elementTypeMap = {

    [ElementTypes.IMAGE]: ImageElementOperate,

    [ElementTypes.TEXT]: TextElementOperate,

    [ElementTypes.SHAPE]: ShapeElementOperate,

    [ElementTypes.LINE]: LineElementOperate,

    [ElementTypes.TABLE]: TableElementOperate,

    [ElementTypes.CHART]: CommonElementOperate,

    [ElementTypes.LATEX]: CommonElementOperate,

    [ElementTypes.VIDEO]: CommonElementOperate,

    [ElementTypes.AUDIO]: CommonElementOperate,

  }

  return elementTypeMap[props.elementInfo.type] || null

})



const elementIndexListInAnimation = computed(() => {

  const indexList = []

  for (let i = 0; i < formatedAnimations.value.length; i++) {

    const elIds = formatedAnimations.value[i].animations.map(item => item.elId)

    if (elIds.includes(props.elementInfo.id)) indexList.push(i)

  }

  return indexList

})



const rotate = computed(() => 'rotate' in props.elementInfo ? props.elementInfo.rotate : 0)

const height = computed(() => 'height' in props.elementInfo ? props.elementInfo.height : 0)

</script>



<style lang="scss" scoped>

.operate {

  position: absolute;

  z-index: 100;

  user-select: none;



  &.multi-select {

    opacity: 0.2;

  }

}

.animation-index {

  position: absolute;

  top: 0;

  left: -24px;

  font-size: 12px;



  .index-item {

    width: 18px;

    height: 18px;

    background-color: #fff;

    color: $themeColor;

    border: 1px solid $themeColor;

    display: flex;

    justify-content: center;

    align-items: center;



    & + .index-item {

      margin-top: 5px;

    }

  }

}

</style>