| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <div
- class="editable-element"
- ref="elementRef"
- :id="'editable-element-' + elementInfo.elId"
- :style="{ zIndex: elementIndex }"
- >
- <component
- :is="currentElementComponent"
- :canvasScale="canvasScale"
- :elementInfo="elementInfo"
- :isActive="isActive"
- :isHandleEl="isHandleEl"
- :isActiveGroupElement="isActiveGroupElement"
- :isMultiSelect="isMultiSelect"
- :animationIndex="animationIndex"
- :selectElement="selectElement"
- :rotateElement="rotateElement"
- :scaleElement="scaleElement"
- :contextmenus="contextmenus"
- ></component>
- </div>
- </template>
- <script lang="ts">
- import { computed, defineComponent, PropType } from 'vue'
- import { useStore } from 'vuex'
- import { State } from '@/store'
- import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement, PPTLineElement } from '@/types/slides'
- import { ContextmenuItem } from '@/components/Contextmenu/types'
- import useLockElement from '@/hooks/useLockElement'
- import useDeleteElement from '@/hooks/useDeleteElement'
- import useCombineElement from '@/hooks/useCombineElement'
- import useOrderElement from '@/hooks/useOrderElement'
- import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas'
- import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
- import { ElementOrderCommands, ElementAlignCommands, ElementScaleHandler } from '@/types/edit'
- import ImageElement from './ImageElement/index.vue'
- import TextElement from './TextElement/index.vue'
- export default defineComponent({
- name: 'editable-element',
- props: {
- elementInfo: {
- type: Object as PropType<PPTElement>,
- required: true,
- },
- elementIndex: {
- type: Number,
- required: true,
- },
- isActive: {
- type: Boolean,
- required: true,
- },
- isHandleEl: {
- type: Boolean,
- required: true,
- },
- isActiveGroupElement: {
- type: Boolean,
- required: true,
- },
- isMultiSelect: {
- type: Boolean,
- required: true,
- },
- animationIndex: {
- type: Number,
- default: -1,
- },
- selectElement: {
- type: Function as PropType<(e: MouseEvent, element: PPTElement, canMove?: boolean) => void>,
- required: true,
- },
- rotateElement: {
- type: Function as PropType<(element: PPTTextElement | PPTImageElement | PPTShapeElement) => void>,
- required: true,
- },
- scaleElement: {
- type: Function as PropType<(e: MouseEvent, element: Exclude<PPTElement, PPTLineElement>, command: ElementScaleHandler) => void>,
- required: true,
- },
- },
- setup(props) {
- const store = useStore<State>()
- const canvasScale = computed(() => store.state.canvasScale)
- const currentElementComponent = computed(() => {
- const elementTypeMap = {
- 'image': ImageElement,
- 'text': TextElement,
- }
- return elementTypeMap[props.elementInfo.type] || null
- })
- const { orderElement } = useOrderElement()
- const { alignElementToCanvas } = useAlignElementToCanvas()
- const { combineElements, uncombineElements } = useCombineElement()
- const { deleteElement } = useDeleteElement()
- const { lockElement, unlockElement } = useLockElement()
- const { copyElement, cutElement } = useCopyAndPasteElement()
- const contextmenus = (): ContextmenuItem[] => {
- if(props.elementInfo.isLock) {
- return [{
- text: '解锁',
- icon: 'icon-unlock',
- handler: () => unlockElement(props.elementInfo),
- }]
- }
- return [
- {
- text: '剪切',
- subText: 'Ctrl + X',
- icon: 'icon-scissor',
- handler: cutElement,
- },
- {
- text: '复制',
- subText: 'Ctrl + C',
- icon: 'icon-copy',
- handler: copyElement,
- },
- { divider: true },
- {
- text: '层级排序',
- icon: 'icon-top-layer',
- disable: props.isMultiSelect && !props.elementInfo.groupId,
- children: [
- { text: '置顶层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.TOP) },
- { text: '置底层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.BOTTOM) },
- { divider: true },
- { text: '上移一层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.UP) },
- { text: '下移一层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.DOWN) },
- ],
- },
- {
- text: '水平对齐',
- icon: 'icon-align-left',
- children: [
- { text: '水平居中', handler: () => alignElementToCanvas(ElementAlignCommands.HORIZONTAL) },
- { text: '左对齐', handler: () => alignElementToCanvas(ElementAlignCommands.LEFT) },
- { text: '右对齐', handler: () => alignElementToCanvas(ElementAlignCommands.RIGHT) },
- ],
- },
- {
- text: '垂直对齐',
- icon: 'icon-align-bottom',
- children: [
- { text: '垂直居中', handler: () => alignElementToCanvas(ElementAlignCommands.VERTICAL) },
- { text: '上对齐', handler: () => alignElementToCanvas(ElementAlignCommands.TOP) },
- { text: '下对齐', handler: () => alignElementToCanvas(ElementAlignCommands.BOTTOM) },
- ],
- },
- { divider: true },
- {
- text: props.elementInfo.groupId ? '取消组合' : '组合',
- subText: 'Ctrl + G',
- icon: 'icon-block',
- handler: props.elementInfo.groupId ? uncombineElements : combineElements,
- hide: !props.isMultiSelect,
- },
- {
- text: '锁定',
- subText: 'Ctrl + L',
- icon: 'icon-lock',
- handler: lockElement,
- },
- {
- text: '删除',
- subText: 'Delete',
- icon: 'icon-delete',
- handler: deleteElement,
- },
- ]
- }
- return {
- canvasScale,
- currentElementComponent,
- contextmenus,
- }
- },
- })
- </script>
|