refactor: history stack

This commit is contained in:
ShawnPhang 2024-04-18 19:17:21 +08:00
parent 4e5b92ff77
commit 7c9441c264
20 changed files with 303 additions and 132 deletions

View File

@ -24,11 +24,10 @@
- 元素拖拽、组合、缩放、层级调整、对齐等操作。
- 图片素材插入、替换、裁剪,图片容器等功能。
- SVG 素材颜色、透明度编辑,文字花字组合。
- 画布自定义尺寸、滚轮缩放、自适应画布
- 支持图层管理、多画板管理、自适应画布。
- 吸附对齐、辅助引导线、标尺功能。
- 键盘快捷键、右键菜单快捷操作,复制删除等常用操作。
- 风格二维码编辑,支持单色、渐变、自定义 logo 等。
- 图层操作,支持拖拽变更层级。
- 颜色调色板原生级取色器颜色吸管Chrome
## 快速开始

16
package-lock.json generated
View File

@ -22,6 +22,8 @@
"element-plus": "^2.6.3",
"fontfaceobserver": "^2.1.0",
"html2canvas": "^1.4.1",
"immer": "^10.0.4",
"microdiff": "^1.4.0",
"mitt": "^3.0.1",
"moveable": "^0.26.0",
"moveable-helper": "^0.4.0",
@ -2674,6 +2676,15 @@
"node": ">=0.10.0"
}
},
"node_modules/immer": {
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz",
"integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -2991,6 +3002,11 @@
"node": ">= 8"
}
},
"node_modules/microdiff": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.4.0.tgz",
"integrity": "sha512-OBKBOa1VBznvLPb/3ljeJaENVe0fO0lnWl77lR4vhPlQD71UpjEoRV5P0KdQkcjbFlBu1Oy2mEUBMU3wxcBAGg=="
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",

View File

@ -25,6 +25,8 @@
"element-plus": "^2.6.3",
"fontfaceobserver": "^2.1.0",
"html2canvas": "^1.4.1",
"immer": "^10.0.4",
"microdiff": "^1.4.0",
"mitt": "^3.0.1",
"moveable": "^0.26.0",
"moveable-helper": "^0.4.0",

View File

@ -3,13 +3,11 @@
* @Date: 2023-07-10 14:58:48
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-11-22 18:11:15
* @LastEditTime: 2024-04-18 16:17:36
*/
import { useControlStore, useWidgetStore } from "@/store"
// import store from '@/store'
type TInitial = {
offsetX: number
offsetY: number

View File

@ -0,0 +1,76 @@
/*
* @Author: ShawnPhang
* @Date: 2024-04-18 16:10:07
* @Description: WebWorker处理差分补丁
*
*
* left 12.6262638 input 12.63
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-18 18:40:27
*/
import { onMounted } from 'vue'
import WebWorker from '@/utils/plugins/webWorker'
import { useHistoryStore, useWidgetStore } from '@/store'
const blackClass: string[] = ['operation-item', 'icon-undo', 'icon-redo']
const whiteKey: string[] = ['ArrowLeft', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'Backspace']
const historyStore = useHistoryStore()
const widgetStore = useWidgetStore()
const historyWorker = new WebWorker('history')
let processing = false
let historyTimer: any = null
function noPutHistory(target: any) {
const classList = Array.from(target.classList)
return classList.filter((v: any) => blackClass.includes(v)).length > 0
}
export default () => {
historyWorker.start(null, (changes: any) => {
changes.patches.length > 0 && historyStore.changeHistory(changes)
processing = false
})
onMounted(() => {
document.addEventListener(
'mousedown',
(e: any) => {
if (noPutHistory(e.target)) return
historyWorker.send(!processing ? { op: 'diff', data: JSON.stringify(widgetStore.dLayouts) } : null)
processing = true
},
false,
)
document.addEventListener(
'mouseup',
(e: any) => {
if (noPutHistory(e.target)) return
clearTimeout(historyTimer)
historyTimer = setTimeout(() => {
historyWorker.send({ op: 'done', data: JSON.stringify(widgetStore.dLayouts) })
}, 150)
},
false,
)
document.addEventListener(
'keydown',
(e) => {
if (!whiteKey.includes(e.key)) return
historyWorker.send(!processing ? { op: 'diff', data: JSON.stringify(widgetStore.dLayouts) } : null)
processing = true
},
false,
)
document.addEventListener(
'keyup',
(e) => {
if (!whiteKey.includes(e.key)) return
clearTimeout(historyTimer)
historyTimer = setTimeout(() => {
historyWorker.send({ op: 'done', data: JSON.stringify(widgetStore.dLayouts) })
}, 150)
},
false,
)
})
}

View File

@ -1,21 +0,0 @@
/*
* @Author: Jeremy-Yu
* @Date: 2024-02-14 14:58:48
* @Description: vue3 Mapgetters
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-11-22 18:11:15
*/
// import { ComputedRef, computed } from 'vue'
// export function useSetupMapGetters<T extends string>(strList: T[]) {
// const mapData: Partial<{[x in T]: ComputedRef}> = {}
// const getters = useStore().getters
// strList.forEach(val => {
// mapData[val] = computed(() => getters[val])
// })
// return mapData as {[x in T]: ComputedRef}
// }

View File

@ -3,7 +3,7 @@
* @Date: 2024-04-11 17:27:58
* @Description: 多画板操作界面
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-17 11:53:48
* @LastEditTime: 2024-04-18 17:12:34
-->
<template>
<div :style="{ position, bottom: -1 * st + 'px', left: sl + 'px' }" :class="['artboards', isFold ? 'fold' : 'unfold']">
@ -130,7 +130,7 @@ function addLayer() {
controlStore.setShowMoveable(false) //
widgetStore.dLayouts.push({ global: getInitPage(), layers: [] })
canvasStore.dCurrentPage = dLayouts.value.length - 1
widgetStore.setDWidgets(widgetStore.getWidgets)
widgetStore.setDWidgets(widgetStore.getWidgets())
canvasStore.setDPage(getInitPage())
canvasStore.updateDPage()
widgetStore.selectWidget({ uuid: '-1' })
@ -139,7 +139,7 @@ function addLayer() {
function selectPoster(i: number) {
controlStore.setShowMoveable(false) //
canvasStore.dCurrentPage = i
widgetStore.setDWidgets(widgetStore.getWidgets)
widgetStore.setDWidgets(widgetStore.getWidgets())
canvasStore.setDPage(dLayouts.value[i].global)
widgetStore.selectWidget({ uuid: '-1' })
}

View File

@ -37,7 +37,6 @@ const state = reactive({
active: true,
})
const clickClassify = (index: number) => {
console.log('index' ,index)
state.activeWidgetClassify = index
state.active = true
}

View File

@ -3,7 +3,7 @@
* @Date: 2022-03-09 16:29:54
* @Description: ctrl建相关的操作
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-15 17:34:51
* @LastEditTime: 2024-04-18 17:35:57
*/
// import store from '@/store'
import handlePaste from './handlePaste'
@ -85,16 +85,14 @@ function paste() {
*/
function undo(shiftKey: any) {
const historyStore = useHistoryStore()
console.log(historyStore.dHistoryParams);
shiftKey ? historyStore.handleHistory("redo") : historyStore.handleHistory('undo')
if (shiftKey) {
if (!(historyStore.dHistoryParams.index === historyStore.dHistoryParams.length - 1)) {
historyStore.handleHistory("redo")
// store.dispatch('handleHistory', 'redo')
}
} else if (historyStore.dHistoryParams.index !== -1) {
// this.handleHistory('undo')
historyStore.handleHistory('undo')
// store.dispatch('handleHistory', 'undo')
}
// if (shiftKey) {
// if (!(historyStore.dHistoryParams.index === historyStore.dHistoryParams.length - 1)) {
// historyStore.handleHistory("redo")
// }
// } else if (historyStore.dHistoryParams.index !== -1) {
// // this.handleHistory('undo')
// historyStore.handleHistory('undo')
// }
}

View File

@ -4,7 +4,7 @@
* @Date: 2024-03-18 21:00:00
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-16 12:16:25
* @LastEditTime: 2024-04-18 15:02:09
*/
import { Store, defineStore } from 'pinia'

View File

@ -2,40 +2,61 @@
* @Author: Jeremy Yu
* @Date: 2024-03-18 21:00:00
* @Description:
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
* @LastEditTime: 2024-03-27 21:00:00
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-18 18:35:16
*/
import { useControlStore, useCanvasStore, useWidgetStore } from "@/store"
import { THistoryStore } from ".."
import { useControlStore, useCanvasStore, useWidgetStore } from '@/store'
import { THistoryStore } from '..'
import { enablePatches, applyPatches } from 'immer'
enablePatches()
export default function handleHistory(store: THistoryStore, action: "undo" | "redo") {
export default function handleHistory(store: THistoryStore, action: 'undo' | 'redo') {
const pageStore = useCanvasStore()
const controlStore = useControlStore()
const widgetStore = useWidgetStore()
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
// store.commit('setShowMoveable', false) // 清理掉上一次的选择框
const history = store.dHistory
const pageHistory = store.dPageHistory
// controlStore.setShowMoveable(false) // 清理掉上一次的选择框
// // store.commit('setShowMoveable', false) // 清理掉上一次的选择框
// const history = store.dHistory
// const pageHistory = store.dPageHistory
const historyParams = store.dHistoryParams
if (action === 'undo') {
historyParams.index -= 1 // 下标向前移1 撤销
console.log(historyParams.index)
if (historyParams.index > -1) {
widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
}
} else if (action === 'redo') {
historyParams.index += 1 // 下标向后移1 重做
// 如果下标小于历史记录列表长度,直接取出历史记录
// if (historyParams.index < historyParams.length) {
widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
// } else {
// // 否则设置下标为列表最后一项
// historyParams.index = historyParams.length - 1
// store.state.dWidgets = JSON.parse(history[historyParams.index])
// store.state.dPage = JSON.parse(pageHistory[historyParams.index + 1])
// }
const { changes, inverseChanges } = store.dHistoryStack
let index = historyParams.stackPointer
const curLayouts = JSON.parse(JSON.stringify(widgetStore.dLayouts))
switch (action) {
case 'undo':
if (inverseChanges.length > 0 && index >= 0) {
const newLayouts = applyPatches(curLayouts, inverseChanges[index])
widgetStore.setDLayouts(JSON.parse(JSON.stringify(newLayouts)))
historyParams.stackPointer--
}
break
case 'redo':
if (changes.length > 0 && index !== changes.length - 1) {
historyParams.stackPointer++
const newLayouts = applyPatches(curLayouts, changes[index + 1])
widgetStore.setDLayouts(JSON.parse(JSON.stringify(newLayouts)))
}
break
}
}
// if (action === 'undo') {
// historyParams.index -= 1 // 下标向前移1 撤销
// console.log(historyParams.index)
// if (historyParams.index > -1) {
// widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
// pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
// }
// } else if (action === 'redo') {
// historyParams.index += 1 // 下标向后移1 重做
// // 如果下标小于历史记录列表长度,直接取出历史记录
// // if (historyParams.index < historyParams.length) {
// widgetStore.setDWidgets(JSON.parse(history[historyParams.index]))
// pageStore.setDPage(JSON.parse(pageHistory[historyParams.index]))
// // } else {
// // // 否则设置下标为列表最后一项
// // historyParams.index = historyParams.length - 1
// // store.state.dWidgets = JSON.parse(history[historyParams.index])
// // store.state.dPage = JSON.parse(pageHistory[historyParams.index + 1])
// // }
// }
}

View File

@ -3,7 +3,7 @@
* @Date: 2024-03-18 21:00:00
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-02 21:10:53
* @LastEditTime: 2024-04-18 18:17:13
*/
import { useCanvasStore, useWidgetStore } from "@/store"
@ -11,25 +11,27 @@ import { THistoryStore } from ".."
/** push操作历史记录 */
export function pushHistory(store: THistoryStore, msg: string = "") {
const pageStore = useCanvasStore()
const widgetStore = useWidgetStore()
console.log('history压栈', '来源: ' + msg)
// 如果有上一次记录,并且与新纪录相同,那么不继续操作
if (store.dHistory[store.dHistory.length - 1] && store.dHistory[store.dHistory.length - 1] === JSON.stringify(widgetStore.dWidgets)) {
return
}
if (store.dHistoryParams.index < history.length - 1) {
const index = store.dHistoryParams.index + 1
const len = history.length - index
store.dHistory.splice(index, len)
store.dPageHistory.splice(index, len)
store.dHistoryParams.length = store.dHistory.length
store.dHistoryParams.index = store.dHistory.length - 1
}
store.dHistory.push(JSON.stringify(widgetStore.dWidgets))
store.dPageHistory.push(JSON.stringify(pageStore.dPage))
store.dHistoryParams.index = store.dHistory.length - 1
store.dHistoryParams.length = store.dHistory.length
console.error('历史记录功能已重构该方法即将移除pushHistory');
// const pageStore = useCanvasStore()
// const widgetStore = useWidgetStore()
// console.log('history压栈', '来源: ' + msg)
// // 如果有上一次记录,并且与新纪录相同,那么不继续操作
// if (store.dHistory[store.dHistory.length - 1] && store.dHistory[store.dHistory.length - 1] === JSON.stringify(widgetStore.dWidgets)) {
// return
// }
// if (store.dHistoryParams.index < history.length - 1) {
// const index = store.dHistoryParams.index + 1
// const len = history.length - index
// store.dHistory.splice(index, len)
// store.dPageHistory.splice(index, len)
// store.dHistoryParams.length = store.dHistory.length
// store.dHistoryParams.index = store.dHistory.length - 1
// }
// store.dHistory.push(JSON.stringify(widgetStore.dWidgets))
// store.dPageHistory.push(JSON.stringify(pageStore.dPage))
// store.dHistoryParams.index = store.dHistory.length - 1
// store.dHistoryParams.length = store.dHistory.length
}
/** 添加颜色选择历史记录 */

View File

@ -3,7 +3,7 @@
* @Date: 2024-03-18 21:00:00
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-15 16:53:51
* @LastEditTime: 2024-04-18 15:41:25
*/
import { Store, defineStore } from 'pinia'
@ -15,6 +15,11 @@ export type THistoryParamData = {
index: number
length: number
maxLength: number
stackPointer: number
}
export type THsitoryStack = {
changes: any[]
inverseChanges: any[]
}
type THistoryState = {
@ -22,18 +27,18 @@ type THistoryState = {
dHistory: string[]
/** 记录历史操作对应的page */
dPageHistory: string[]
/** 记录差分补丁 */
dHistoryStack: THsitoryStack
/** 记录指针等数据 */
dHistoryParams: THistoryParamData
/** 记录历史选择的颜色 */
dColorHistory: string[]
}
type THistoryAction = {
/**
*
*
* uuid便
*/
pushHistory: (msg?: string) => void
/** 写入历史记录 */
changeHistory: (patches: any) => void
/**
*
* action为undo表示撤销
@ -51,6 +56,11 @@ const HistoryStore = defineStore<'historyStore', THistoryState, {}, THistoryActi
index: -1,
length: 0,
maxLength: 20,
stackPointer: -1
},
dHistoryStack: {
changes: [],
inverseChanges: [],
},
dColorHistory: [],
dPageHistory: [],
@ -60,12 +70,18 @@ const HistoryStore = defineStore<'historyStore', THistoryState, {}, THistoryActi
pushHistory(msg) {
pushHistory(this, msg)
},
changeHistory({ patches, inversePatches }) {
const pointer = ++this.dHistoryParams.stackPointer
// 如若之前撤销过,当新增记录时,后面的记录就清空了
this.dHistoryStack.changes.length = pointer
this.dHistoryStack.inverseChanges.length = pointer
this.dHistoryStack.changes[pointer] = patches
this.dHistoryStack.inverseChanges[pointer] = inversePatches
},
handleHistory(action) {
const widgetStore = useWidgetStore()
const pageStore = useCanvasStore()
handleHistory(this, action)
// 激活组件默认为page
widgetStore.setdActiveElement(pageStore.dPage)
// TODO: 操作后如果当前选中元素还在,则应当保留选择框
// widgetStore.setdActiveElement(pageStore.dPage)
},
pushColorToHistory(color) {
pushColorToHistory(this, color)

View File

@ -3,7 +3,7 @@
* @Date: 2024-03-28 21:00:00
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-16 11:12:40
* @LastEditTime: 2024-04-18 18:49:09
*/
import { useCanvasStore, useHistoryStore } from '@/store'
@ -240,11 +240,21 @@ export function setDWidgets(state: TWidgetStore, e: TdWidgetData[]) {
updateDWidgets(state)
}
export function setDLayouts(state: TWidgetStore, data: any[]) {
state.dLayouts = data
state.dWidgets = state.getWidgets()
const pageStore = useCanvasStore()
pageStore.setDPage(data[pageStore.dCurrentPage].global)
setTimeout(() => {
state.dActiveElement = pageStore.dPage
}, 150);
}
export function updateDWidgets(state: TWidgetStore) {
const pageStore = useCanvasStore()
const { dCurrentPage } = pageStore
state.dLayouts[dCurrentPage].layers = state.dWidgets
state.dWidgets = state.getWidgets
state.dWidgets = state.getWidgets()
}
// 锁定所有图层 / 再次调用时还原图层

View File

@ -3,7 +3,7 @@
* @Date: 2024-03-28 14:00:00
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-15 16:54:45
* @LastEditTime: 2024-04-18 15:14:48
*/
import { useCanvasStore } from '@/store'
@ -17,7 +17,7 @@ export type TWidgetJsonData = TPageState & {
/** 返回组件Json数据 */
export function widgetJsonData(state: TWidgetState) {
const pageStore = useCanvasStore()
const { dCurrentPage } = pageStore
// const page: TWidgetJsonData = JSON.parse(JSON.stringify(pageStore.dPage))
return state.dLayouts[dCurrentPage].layers
!state.dLayouts[pageStore.dCurrentPage] && pageStore.dCurrentPage--
return state.dLayouts[pageStore.dCurrentPage].layers
}

View File

@ -3,20 +3,21 @@
* @Date: 2024-03-18 21:00:00
* @Description: Store方法export
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-16 10:07:13
* @LastEditTime: 2024-04-18 17:11:51
*/
import { Store, defineStore } from "pinia";
import { useCanvasStore } from '@/store'
import { TInidDMovePayload, TMovePayload, dMove, initDMove, setDropOver, setMouseEvent, setdActiveElement, updateGroupSize, updateHoverUuid } from "./actions";
import { TPageState } from "@/store/design/canvas/d";
import { TInitResize, TSize, TdResizePayload, dResize, initDResize, resize, autoResizeAll } from "./actions/resize";
import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, updateDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets } from "./actions/widget";
import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, updateDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets, setDLayouts } from "./actions/widget";
import { addGroup } from "./actions/group";
import { setTemplate } from "./actions/template";
import { copyWidget, pasteWidget } from "./actions/clone";
import { TSelectWidgetData, TselectItem, selectItem, selectWidget, selectWidgetsInOut } from "./actions/select";
import { TUpdateAlignData, updateAlign } from "./actions/align";
import { TWidgetJsonData, widgetJsonData } from "./getter";
// import { TWidgetJsonData, widgetJsonData } from "./getter";
import { TupdateLayerIndexData, ungroup, updateLayerIndex } from "./actions/layer";
import pageDefault from "../canvas/page-default";
@ -80,7 +81,7 @@ export type TWidgetState = {
}
type TGetter = {
getWidgets(state: TWidgetState): TWidgetJsonData
// getWidgets(state: TWidgetState): TWidgetJsonData
}
type TAction = {
@ -124,11 +125,13 @@ type TAction = {
resize: (data: TSize) => void
setWidgetStyle: (data: TsetWidgetStyleData) => void
setDWidgets: (data: TdWidgetData[]) => void
setDLayouts: (data: TdLayout) => void
updateDWidgets: () => void
lockWidgets: () => void
setMouseEvent: (e: MouseEvent | null) => void
setdActiveElement: (data: TdWidgetData) => void
autoResizeAll: (data: TSize) => void
getWidgets: () => TdWidgetData[]
}
const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("widgetStore", {
@ -160,11 +163,11 @@ const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("
dCopyElement: [], // 复制的组件(可能是单个也可能是数组)
}),
getters: {
getWidgets(store) {
return widgetJsonData(store)
}
},
// getters: {
// getWidgets(store) {
// return widgetJsonData(store)
// }
// },
actions: {
initDMove(payload) { initDMove(this, payload) },
@ -195,7 +198,13 @@ const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("
lockWidgets() { lockWidgets(this) },
setMouseEvent(event) { setMouseEvent(this, event) },
setdActiveElement(data) { setdActiveElement(this, data) },
autoResizeAll(data) { autoResizeAll(this, data) }
autoResizeAll(data) { autoResizeAll(this, data) },
setDLayouts(data) { setDLayouts(this, data) },
getWidgets() {
const pageStore = useCanvasStore()
!this.dLayouts[pageStore.dCurrentPage] && pageStore.dCurrentPage--
return this.dLayouts[pageStore.dCurrentPage].layers
}
}
})

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang
* @Date: 2022-03-06 13:53:30
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
* @LastEditTime: 2024-03-05 12:00:00
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-17 15:58:53
*/
export default class WebWorker {
private worker: Worker | undefined
@ -19,17 +19,20 @@ export default class WebWorker {
}))
}
}
public start(data: any) {
public start(data?: any, cb?: Function) {
return new Promise((resolve) => {
if (!this.worker) resolve('')
else {
// 监听Web Worker的消息
this.worker.onmessage = (e) => {
resolve(e.data)
cb ? cb(e.data) : resolve(e.data)
}
// 发送数据给Web Worker
this.worker.postMessage(data)
}
})
}
public send(data?: any) {
this.worker?.postMessage(data)
}
}

View File

@ -0,0 +1,42 @@
/*
* @Author: ShawnPhang
* @Date: 2023-09-14 11:33:44
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-18 13:59:47
*/
import diff from 'microdiff'
import { produce, applyPatches, enablePatches } from 'immer'
enablePatches()
const ops: any = {
CHANGE: 'replace',
CREATE: 'add',
REMOVE: 'remove',
}
let cloneData = ''
onmessage = async (e) => {
if (!e.data) {
return
}
if (e.data.op === 'done') {
if (!cloneData) return
let fork = JSON.parse(cloneData)
let curArray = JSON.parse(e.data.data)
// 比较数据差异
let diffData: any = diff(fork, curArray)
// 生成差分补丁
fork = produce(
fork,
(draft) => {
for (const d of diffData) {
d.op = ops[d.type]
}
draft = applyPatches(draft, diffData)
},
(patches, inversePatches) => {
self.postMessage({ patches, inversePatches })
},
)
cloneData = ''
} else cloneData = e.data.data
}

View File

@ -4,7 +4,7 @@
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastUpdateContent: Support typescript
* @LastEditTime: 2024-04-16 11:35:11
* @LastEditTime: 2024-04-18 18:14:36
-->
<template>
<div id="page-design-index" ref="pageDesignIndex" class="page-design-bg-color">
@ -89,6 +89,8 @@ import type { ButtonInstance } from 'element-plus'
import Tour from './components/Tour.vue'
import createDesign from '@/components/business/create-design'
import multipleBoards from '@/components/modules/layout/multipleBoards'
import useHistory from '@/common/hooks/history'
useHistory()
const ref1 = ref<ButtonInstance>()
const ref2 = ref<ButtonInstance>()
@ -113,7 +115,7 @@ const historyStore = useHistoryStore()
const groupStore = useGroupStore()
const { dPage } = storeToRefs(useCanvasStore())
const { dZoom } = storeToRefs(useCanvasStore())
const { dHistoryParams } = storeToRefs(useHistoryStore())
const { dHistoryParams, dHistoryStack } = storeToRefs(useHistoryStore())
const state = reactive<TState>({
style: {
@ -149,13 +151,14 @@ function jump2home() {
}
const undoable = computed(() => {
return !(
dHistoryParams.value.index === -1 ||
(dHistoryParams.value.index === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
return dHistoryParams.value.stackPointer >= 0
// return !(
// dHistoryParams.value.index === -1 ||
// (dHistoryParams.value.index === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
})
const redoable = computed(() => {
return !(dHistoryParams.value.index === dHistoryParams.value.length - 1)
return !(dHistoryParams.value.stackPointer === dHistoryStack.value.changes.length - 1)
})
function zoomSub() {
@ -195,11 +198,9 @@ onBeforeUnmount(() => {
document.removeEventListener('keyup', handleKeyup(controlStore, checkCtrl), false)
document.oncontextmenu = null
})
// ...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
function handleHistory(data: "undo" | "redo") {
historyStore.handleHistory(data)
// store.dispatch('handleHistory', data)
}
function changeLineGuides() {

View File

@ -3,7 +3,7 @@
* @Date: 2022-01-12 11:26:53
* @Description: 顶部操作按钮组
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-16 15:38:39
* @LastEditTime: 2024-04-18 17:13:24
-->
<template>
<div class="top-title"><el-input v-model="state.title" placeholder="未命名的设计" class="input-wrap" /></div>
@ -221,10 +221,10 @@ async function load(cb: () => void) {
} else {
if (Array.isArray(data)) {
widgetStore.dLayouts = data
widgetStore.setDWidgets(widgetStore.getWidgets)
widgetStore.setDWidgets(widgetStore.getWidgets())
} else {
widgetStore.dLayouts = [{global: data.page, layers: data.widgets}]
id ? widgetStore.setDWidgets(widgetStore.getWidgets) : widgetStore.setTemplate(widgetStore.getWidgets)
id ? widgetStore.setDWidgets(widgetStore.getWidgets()) : widgetStore.setTemplate(widgetStore.getWidgets())
}
pageStore.setDPage(pageStore.getDPage)
// id ? widgetStore.setDWidgets(data.widgets) : widgetStore.setTemplate(data.widgets)