File size: 4,356 Bytes
7d93f04 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> |