diff --git a/src/configs/animation.ts b/src/configs/animation.ts deleted file mode 100644 index 08dd5173..00000000 --- a/src/configs/animation.ts +++ /dev/null @@ -1,160 +0,0 @@ -export const ANIMATIONS_TYPES = ['弹跳', '淡入', '翻转', '旋转', '滑入', '缩放'] - -export const ANIMATIONS = [ - { - key: 'bounceIn', - type: '弹跳', - name: '弹跳', - icon: 'icon-anime-bounce' - }, - { - key: 'bounceInDown', - type: '弹跳', - name: '向下弹跳', - icon: 'icon-anime-bounce-down', - }, - { - key: 'bounceInLeft', - type: '弹跳', - name: '从左弹跳', - icon: 'icon-anime-bounce-left', - }, - { - key: 'bounceInRight', - type: '弹跳', - name: '从右弹跳', - icon: 'icon-anime-bounce-right', - }, - { - key: 'bounceInUp', - type: '弹跳', - name: '向上弹跳', - icon: 'icon-anime-bounce-up', - }, - { - key: 'fadeIn', - type: '淡入', - name: '淡入', - icon: 'icon-anime-fade', - }, - { - key: 'fadeInDown', - type: '淡入', - name: '向下淡入', - icon: 'icon-anime-fade-down', - }, - { - key: 'fadeInLeft', - type: '淡入', - name: '从左淡入', - icon: 'icon-anime-fade-left', - }, - { - key: 'fadeInRight', - type: '淡入', - name: '从右淡入', - icon: 'icon-anime-fade-right', - }, - { - key: 'fadeInUp', - type: '淡入', - name: '向上淡入', - icon: 'icon-anime-fade-up', - }, - { - key: 'flipInX', - type: '翻转', - name: '水平翻转', - icon: 'icon-anime-flip-x', - }, - { - key: 'flipInY', - type: '翻转', - name: '垂直翻转', - icon: 'icon-anime-flip-y', - }, - { - key: 'rotateIn', - type: '旋转', - name: '旋转', - icon: 'icon-anime-rotate', - }, - { - key: 'rotateInDownLeft', - type: '旋转', - name: '从左下旋转', - icon: 'icon-anime-rotate-up-right', - }, - { - key: 'rotateInDownRight', - type: '旋转', - name: '从右下旋转', - icon: 'icon-anime-rotate-up-left', - }, - { - key: 'rotateInUpLeft', - type: '旋转', - name: '从左上旋转', - icon: 'icon-anime-rotate-down-right', - }, - { - key: 'rotateInUpRight', - type: '旋转', - name: '从右上旋转', - icon: 'icon-anime-rotate-down-left', - }, - { - key: 'slideInDown', - type: '滑入', - name: '向下滑入', - icon: 'icon-anime-slide-down', - }, - { - key: 'slideInLeft', - type: '滑入', - name: '从左滑入', - icon: 'icon-anime-slide-left', - }, - { - key: 'slideInRight', - type: '滑入', - name: '从右滑入', - icon: 'icon-anime-slide-right', - }, - { - key: 'slideInUp', - type: '滑入', - name: '向上滑入', - icon: 'icon-anime-slide-up', - }, - { - key: 'zoomIn', - type: '缩放', - name: '放大', - icon: 'icon-anime-zoom', - }, - { - key: 'zoomInDown', - type: '缩放', - name: '向下放大', - icon: 'icon-anime-zoom-down', - }, - { - key: 'zoomInLeft', - type: '缩放', - name: '从左放大', - icon: 'icon-anime-zoom-left', - }, - { - key: 'zoomInRight', - type: '缩放', - name: '从右放大', - icon: 'icon-anime-zoom-right', - }, - { - key: 'zoomInUp', - type: '缩放', - name: '向上放大', - icon: 'icon-anime-zoom-up', - }, -] \ No newline at end of file diff --git a/src/hooks/useAddHistorySnapshot.ts b/src/hooks/useAddHistorySnapshot.ts deleted file mode 100644 index 662be2ef..00000000 --- a/src/hooks/useAddHistorySnapshot.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useStore } from 'vuex' -import debounce from 'lodash/debounce' -import { State, ActionTypes } from '@/store' - -export default () => { - const store = useStore() - - const addHistorySnapshot = debounce(function() { - store.dispatch(ActionTypes.ADD_SNAPSHOT) - }, 300, { trailing: true }) - - return { - addHistorySnapshot, - } -} \ No newline at end of file diff --git a/src/hooks/useCombineElement.ts b/src/hooks/useCombineElement.ts index fb7bc85f..4770a79b 100644 --- a/src/hooks/useCombineElement.ts +++ b/src/hooks/useCombineElement.ts @@ -3,6 +3,7 @@ import { useStore } from 'vuex' import { State, MutationTypes } from '@/store' import { PPTElement, Slide } from '@/types/slides' import { createRandomCode } from '@/utils/common' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() @@ -10,6 +11,8 @@ export default () => { const activeElementList: Ref = computed(() => store.getters.activeElementList) const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + // 组合元素(为当前所有激活元素添加一个相同的groupId) const combineElements = () => { if(!activeElementList.value.length) return @@ -34,6 +37,7 @@ export default () => { newElementList.splice(insertIndex, 0, ...combineElementList) store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } // 取消组合元素(移除所有被激活元素的groupId) @@ -47,6 +51,7 @@ export default () => { if(activeElementIdList.value.includes(element.elId) && element.groupId) delete element.groupId } store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } return { diff --git a/src/hooks/useCreateElement.ts b/src/hooks/useCreateElement.ts index e46eadd6..f46e808e 100644 --- a/src/hooks/useCreateElement.ts +++ b/src/hooks/useCreateElement.ts @@ -12,6 +12,7 @@ import { DEFAULT_CHART, DEFAULT_TABLE, } from '@/configs/element' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' interface CommonElementPosition { top: number; @@ -30,9 +31,12 @@ interface LineElementPosition { export default () => { const store = useStore() + const { addHistorySnapshot } = useHistorySnapshot() + const createElement = (element: PPTElement) => { store.commit(MutationTypes.ADD_ELEMENT, element) store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [element.elId]) + addHistorySnapshot() } const createImageElement = (imgUrl: string) => { diff --git a/src/hooks/useDeleteElement.ts b/src/hooks/useDeleteElement.ts index 48b2d923..2070272f 100644 --- a/src/hooks/useDeleteElement.ts +++ b/src/hooks/useDeleteElement.ts @@ -2,23 +2,28 @@ import { Ref, computed } from 'vue' import { useStore } from 'vuex' import { State, MutationTypes } from '@/store' import { Slide } from '@/types/slides' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() const activeElementIdList = computed(() => store.state.activeElementIdList) const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + const deleteElement = () => { if(!activeElementIdList.value.length) return const newElementList = currentSlide.value.elements.filter(el => !activeElementIdList.value.includes(el.elId)) store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, []) store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } const deleteAllElements = () => { if(!currentSlide.value.elements.length) return store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, []) store.commit(MutationTypes.UPDATE_SLIDE, { elements: [] }) + addHistorySnapshot() } return { diff --git a/src/hooks/useRedoAndUndo.ts b/src/hooks/useHistorySnapshot.ts similarity index 70% rename from src/hooks/useRedoAndUndo.ts rename to src/hooks/useHistorySnapshot.ts index 5454f23a..5a0ce578 100644 --- a/src/hooks/useRedoAndUndo.ts +++ b/src/hooks/useHistorySnapshot.ts @@ -1,10 +1,15 @@ import { useStore } from 'vuex' +import debounce from 'lodash/debounce' import throttle from 'lodash/throttle' import { State, ActionTypes } from '@/store' export default () => { const store = useStore() + const addHistorySnapshot = debounce(function() { + store.dispatch(ActionTypes.ADD_SNAPSHOT) + }, 300, { trailing: true }) + const redo = throttle(function() { store.dispatch(ActionTypes.RE_DO) }, 100, { leading: true, trailing: false }) @@ -14,6 +19,7 @@ export default () => { }, 100, { leading: true, trailing: false }) return { + addHistorySnapshot, redo, undo, } diff --git a/src/hooks/useLockElement.ts b/src/hooks/useLockElement.ts index 970ef5ea..4c2eb297 100644 --- a/src/hooks/useLockElement.ts +++ b/src/hooks/useLockElement.ts @@ -2,12 +2,15 @@ import { useStore } from 'vuex' import { Ref, computed } from 'vue' import { State, MutationTypes } from '@/store' import { PPTElement, Slide } from '@/types/slides' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() const activeElementIdList = computed(() => store.state.activeElementIdList) const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + const lockElement = () => { const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements)) @@ -15,6 +18,7 @@ export default () => { if(activeElementIdList.value.includes(element.elId)) element.isLock = true } store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } const unlockElement = (handleElement: PPTElement) => { @@ -34,6 +38,7 @@ export default () => { } } store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } return { diff --git a/src/hooks/useMoveElement.ts b/src/hooks/useMoveElement.ts index c424fa72..89a8d67d 100644 --- a/src/hooks/useMoveElement.ts +++ b/src/hooks/useMoveElement.ts @@ -3,12 +3,15 @@ import { useStore } from 'vuex' import { State, MutationTypes } from '@/store' import { Slide } from '@/types/slides' import { KEYS } from '@/configs/hotkey' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() const activeElementIdList = computed(() => store.state.activeElementIdList) const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + const moveElement = (command: string) => { const newElementList = currentSlide.value.elements.map(el => { if(activeElementIdList.value.includes(el.elId)) { @@ -33,6 +36,7 @@ export default () => { return el }) store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } return { diff --git a/src/hooks/useOrderElement.ts b/src/hooks/useOrderElement.ts index 88bc4884..6801f186 100644 --- a/src/hooks/useOrderElement.ts +++ b/src/hooks/useOrderElement.ts @@ -3,11 +3,14 @@ import { useStore } from 'vuex' import { State, MutationTypes } from '@/store' import { PPTElement, Slide } from '@/types/slides' import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + // 获取组合元素层级范围(组合成员中的最大层级和最小层级) const getCombineElementIndexRange = (elementList: PPTElement[], combineElementList: PPTElement[]) => { const minIndex = elementList.findIndex(_element => _element.elId === combineElementList[0].elId) @@ -174,6 +177,7 @@ export default () => { else if(command === ElementOrderCommands.BOTTOM) newElementList = moveBottomElement(currentSlide.value.elements, element) store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList }) + addHistorySnapshot() } return { diff --git a/src/hooks/usePasteTextClipboardData.ts b/src/hooks/usePasteTextClipboardData.ts index 653741d8..bdbfdde9 100644 --- a/src/hooks/usePasteTextClipboardData.ts +++ b/src/hooks/usePasteTextClipboardData.ts @@ -4,6 +4,7 @@ import { MutationTypes, State } from '@/store' import { decrypt } from '@/utils/crypto' import { PPTElement, Slide } from '@/types/slides' import { createRandomCode } from '@/utils/common' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' interface PasteTextClipboardDataOptions { onlySlide?: boolean; @@ -14,6 +15,8 @@ export default () => { const store = useStore() const currentSlide: Ref = computed(() => store.getters.currentSlide) + const { addHistorySnapshot } = useHistorySnapshot() + const pasteElement = (elements: PPTElement[]) => { const groupIdMap = {} const elIdMap = {} @@ -40,10 +43,12 @@ export default () => { } store.commit(MutationTypes.ADD_ELEMENT, elements) store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, Object.values(elIdMap)) + addHistorySnapshot() } const pasteSlide = (slide: Slide) => { store.commit(MutationTypes.ADD_SLIDE, slide) + addHistorySnapshot() } const pasteText = (text: string) => { diff --git a/src/hooks/useSlideHandler.ts b/src/hooks/useSlideHandler.ts index 9b2c0337..c3be9de4 100644 --- a/src/hooks/useSlideHandler.ts +++ b/src/hooks/useSlideHandler.ts @@ -8,6 +8,7 @@ import { encrypt } from '@/utils/crypto' import { KEYS } from '@/configs/hotkey' import { message } from 'ant-design-vue' import usePasteTextClipboardData from '@/hooks/usePasteTextClipboardData' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default () => { const store = useStore() @@ -16,6 +17,7 @@ export default () => { const currentSlide: Ref = computed(() => store.getters.currentSlide) const { pasteTextClipboardData } = usePasteTextClipboardData() + const { addHistorySnapshot } = useHistorySnapshot() const updateSlideIndex = (command: string) => { let targetIndex = 0 @@ -51,14 +53,17 @@ export default () => { elements: [], } store.commit(MutationTypes.ADD_SLIDE, emptySlide) + addHistorySnapshot() } const copyAndPasteSlide = () => { store.commit(MutationTypes.ADD_SLIDE, currentSlide.value) + addHistorySnapshot() } const deleteSlide = () => { store.commit(MutationTypes.DELETE_SLIDE, currentSlide.value.id) + addHistorySnapshot() } const cutSlide = () => { diff --git a/src/store/actions.ts b/src/store/actions.ts index 95a1da76..1f668bac 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -5,14 +5,22 @@ import { ActionTypes, MutationTypes } from './constants' import db, { Snapshot } from '@/utils/database' export const actions: ActionTree = { - async [ActionTypes.INIT_SNAPSHOT_DATABASE]({ commit }) { + async [ActionTypes.INIT_SNAPSHOT_DATABASE]({ commit, state }) { const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray() - const snapshot = snapshots.slice(-1)[0] + const lastSnapshot = snapshots.slice(-1)[0] - if(snapshot) { + if(lastSnapshot) { db.snapshots.clear() - commit(MutationTypes.SET_SLIDES, snapshot.slides) + // commit(MutationTypes.SET_SLIDES, lastSnapshot.slides) } + + const newFirstSnapshot = { + index: state.slideIndex, + slides: state.slides, + } + await db.snapshots.add(newFirstSnapshot) + commit(MutationTypes.SET_SNAPSHOT_CURSOR, 0) + commit(MutationTypes.SET_SNAPSHOT_LENGTH, 1) }, async [ActionTypes.ADD_SNAPSHOT]({ state, commit }) { @@ -44,7 +52,7 @@ export const actions: ActionTree = { }, async [ActionTypes.UN_DO]({ state, commit }) { - if(state.snapshotCursor > 0) return + if(state.snapshotCursor <= 0) return const snapshotCursor = state.snapshotCursor - 1 const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray() @@ -58,7 +66,7 @@ export const actions: ActionTree = { }, async [ActionTypes.RE_DO]({ state, commit }) { - if(state.snapshotCursor < state.snapshotLength - 1) return + if(state.snapshotCursor >= state.snapshotLength - 1) return const snapshotCursor = state.snapshotCursor + 1 const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray() diff --git a/src/views/Editor/Canvas/hooks/useDragElement.ts b/src/views/Editor/Canvas/hooks/useDragElement.ts index 84d584a0..0f449f40 100644 --- a/src/views/Editor/Canvas/hooks/useDragElement.ts +++ b/src/views/Editor/Canvas/hooks/useDragElement.ts @@ -5,6 +5,7 @@ import { ElementTypes, PPTElement } from '@/types/slides' import { AlignmentLineProps } from '@/types/edit' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' import { getRectRotatedRange, AlignLine, uniqAlignLines } from '@/utils/element' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' export default ( elementList: Ref, @@ -15,6 +16,8 @@ export default ( const activeElementIdList = computed(() => store.state.activeElementIdList) const canvasScale = computed(() => store.state.canvasScale) + const { addHistorySnapshot } = useHistorySnapshot() + const dragElement = (e: MouseEvent, element: PPTElement) => { if(!activeElementIdList.value.includes(element.elId)) return let isMouseDown = true @@ -305,6 +308,7 @@ export default ( if(startPageX === currentPageX && startPageY === currentPageY) return store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value }) + addHistorySnapshot() } } diff --git a/src/views/Editor/Canvas/hooks/useRotateElement.ts b/src/views/Editor/Canvas/hooks/useRotateElement.ts index e1e64667..4b8e7766 100644 --- a/src/views/Editor/Canvas/hooks/useRotateElement.ts +++ b/src/views/Editor/Canvas/hooks/useRotateElement.ts @@ -2,11 +2,12 @@ import { Ref, computed } from 'vue' import { useStore } from 'vuex' import { State, MutationTypes } from '@/store' import { PPTElement, PPTTextElement, PPTImageElement, PPTShapeElement } from '@/types/slides' +import useHistorySnapshot from '@/hooks/useHistorySnapshot' // 给定一个坐标,计算该坐标到(0, 0)点连线的弧度值 // 注意,Math.atan2的一般用法是Math.atan2(y, x)返回的是原点(0,0)到(x,y)点的线段与X轴正方向之间的弧度值 // 这里将使用时将x与y的传入顺序交换了,为的是获取原点(0,0)到(x,y)点的线段与Y轴正方向之间的弧度值 -export const getAngleFromCoordinate = (x: number, y: number) => { +const getAngleFromCoordinate = (x: number, y: number) => { const radian = Math.atan2(x, y) const angle = 180 / Math.PI * radian return angle @@ -16,6 +17,8 @@ export default (elementList: Ref, viewportRef: Ref() const canvasScale = computed(() => store.state.canvasScale) + const { addHistorySnapshot } = useHistorySnapshot() + const rotateElement = (element: PPTTextElement | PPTImageElement | PPTShapeElement) => { let isMouseDown = true let angle = 0 @@ -67,6 +70,7 @@ export default (elementList: Ref, viewportRef: Ref { +const getRotateElementPoints = (element: RotateElementData, angle: number) => { const { left, top, width, height } = element const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2 @@ -67,7 +68,7 @@ export const getRotateElementPoints = (element: RotateElementData, angle: number } // 获取元素某个操作点对角线上另一端的操作点坐标(例如:左上 <-> 右下) -export const getOppositePoint = (direction: number, points: ReturnType): { left: number; top: number } => { +const getOppositePoint = (direction: number, points: ReturnType): { left: number; top: number } => { const oppositeMap = { [OperatePoints.RIGHT_BOTTOM]: points.leftTopPoint, [OperatePoints.LEFT_BOTTOM]: points.rightTopPoint, @@ -91,6 +92,8 @@ export default ( const ctrlOrShiftKeyActive: Ref = computed(() => store.getters.ctrlOrShiftKeyActive) const canvasScale = computed(() => store.state.canvasScale) + const { addHistorySnapshot } = useHistorySnapshot() + const scaleElement = (e: MouseEvent, element: Exclude, command: ElementScaleHandler) => { let isMouseDown = true @@ -383,6 +386,7 @@ export default ( if(startPageX === e.pageX && startPageY === e.pageY) return store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value }) + addHistorySnapshot() } } @@ -486,6 +490,7 @@ export default ( if(startPageX === e.pageX && startPageY === e.pageY) return store.commit(MutationTypes.UPDATE_SLIDE, { elements: elementList.value }) + addHistorySnapshot() } } diff --git a/src/views/Editor/CanvasTool/index.vue b/src/views/Editor/CanvasTool/index.vue index 0e34e507..901234c5 100644 --- a/src/views/Editor/CanvasTool/index.vue +++ b/src/views/Editor/CanvasTool/index.vue @@ -1,8 +1,8 @@