From 7ff411b98845ec2481bad433c2f92afb552b99ab Mon Sep 17 00:00:00 2001 From: Siklos Date: Mon, 15 Aug 2022 11:52:17 -0400 Subject: [PATCH] Implement webworker for save operation + Limit the history size (#29) - Implement webworker for save operation - Limit the history size Reviewed-on: https://git.siklos-chaneru.duckdns.org/Siklos/svg-layout-designer-react/pulls/29 --- src/Components/Editor/Editor.tsx | 8 +++++- src/Components/Editor/Save.ts | 41 ++++++++++++++++++++---------- src/Components/History/History.tsx | 4 +-- src/utils/default.ts | 2 ++ src/workers/worker.js | 25 ++++++++++++++++++ tsconfig.json | 2 +- 6 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 src/workers/worker.js diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 4337365..3a728e3 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -10,6 +10,7 @@ import { onKeyDown } from './Shortcuts'; import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations'; import EditorEvents from '../../Events/EditorEvents'; import { IEditorState } from '../../Interfaces/IEditorState'; +import { MAX_HISTORY } from '../../utils/default'; interface IEditorProps { configuration: IConfiguration @@ -17,7 +18,12 @@ interface IEditorProps { historyCurrentStep: number } -export const getCurrentHistory = (history: IHistoryState[], historyCurrentStep: number): IHistoryState[] => history.slice(0, historyCurrentStep + 1); +export const getCurrentHistory = (history: IHistoryState[], historyCurrentStep: number): IHistoryState[] => + history.slice( + Math.max(0, history.length - MAX_HISTORY), // change this to 0 for unlimited (not recommanded because of overflow) + historyCurrentStep + 1 + ); + export const getCurrentHistoryState = (history: IHistoryState[], historyCurrentStep: number): IHistoryState => history[historyCurrentStep]; const Editor: React.FunctionComponent = (props) => { diff --git a/src/Components/Editor/Save.ts b/src/Components/Editor/Save.ts index 5717a41..159959a 100644 --- a/src/Components/Editor/Save.ts +++ b/src/Components/Editor/Save.ts @@ -3,27 +3,38 @@ import { IConfiguration } from '../../Interfaces/IConfiguration'; import { getCircularReplacer } from '../../utils/saveload'; import { ID } from '../SVG/SVG'; import { IEditorState } from '../../Interfaces/IEditorState'; +import Worker from '../../workers/worker?worker'; export function SaveEditorAsJSON( history: IHistoryState[], historyCurrentStep: number, configuration: IConfiguration ): void { - const exportName = 'state'; + const exportName = 'state.json'; const spaces = import.meta.env.DEV ? 4 : 0; const editorState: IEditorState = { history, historyCurrentStep, configuration }; + + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (window.Worker) { + // use webworker for the stringify to avoid freezing + const myWorker = new Worker(); + myWorker.postMessage({ editorState, spaces }); + myWorker.onmessage = (event) => { + const data = event.data; + const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`; + createDownloadNode(exportName, dataStr); + myWorker.terminate(); + }; + return; + } + const data = JSON.stringify(editorState, getCircularReplacer(), spaces); const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`; - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute('href', dataStr); - downloadAnchorNode.setAttribute('download', `${exportName}.json`); - document.body.appendChild(downloadAnchorNode); // required for firefox - downloadAnchorNode.click(); - downloadAnchorNode.remove(); + createDownloadNode(exportName, dataStr); } export function SaveEditorAsSVG(): void { @@ -32,10 +43,14 @@ export function SaveEditorAsSVG(): void { const preface = '\r\n'; const svgBlob = new Blob([preface, svg.outerHTML], { type: 'image/svg+xml;charset=utf-8' }); const svgUrl = URL.createObjectURL(svgBlob); - const downloadLink = document.createElement('a'); - downloadLink.href = svgUrl; - downloadLink.download = 'newesttree.svg'; - document.body.appendChild(downloadLink); - downloadLink.click(); - document.body.removeChild(downloadLink); + createDownloadNode('state.svg', svgUrl); +} + +function createDownloadNode(filename: string, datastring: string) { + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.href = datastring; + downloadAnchorNode.download = filename; + document.body.appendChild(downloadAnchorNode); // required for firefox + downloadAnchorNode.click(); + downloadAnchorNode.remove(); } diff --git a/src/Components/History/History.tsx b/src/Components/History/History.tsx index 30778bd..36e8e80 100644 --- a/src/Components/History/History.tsx +++ b/src/Components/History/History.tsx @@ -14,9 +14,7 @@ export const History: React.FC = (props: IHistoryProps) => { const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => { const reversedIndex = (props.history.length - 1) - index; const step = props.history[reversedIndex]; - const desc = reversedIndex > 0 - ? `${reversedIndex}: ${step.LastAction}` - : 'Go to the beginning'; + const desc = step.LastAction; const selectedClass = reversedIndex === props.historyCurrentStep ? 'bg-blue-500 hover:bg-blue-600' diff --git a/src/utils/default.ts b/src/utils/default.ts index 2bd22dc..027c540 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -39,3 +39,5 @@ export const DEFAULT_MAINCONTAINER_PROPS: IProperties = { }; export const NOTCHES_LENGTH = 4; + +export const MAX_HISTORY = 200; diff --git a/src/workers/worker.js b/src/workers/worker.js new file mode 100644 index 0000000..c11fa7d --- /dev/null +++ b/src/workers/worker.js @@ -0,0 +1,25 @@ +onmessage = (e) => { + const data = JSON.stringify(e.data.editorState, getCircularReplacer(), e.data.spaces); + postMessage(data); +}; + +const getCircularReplacer = () => { + const seen = new WeakSet(); + return (key, value) => { + if (key === 'parent') { + return; + } + + if (key === 'SelectedContainer') { + return; + } + + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + return value; + }; +}; diff --git a/tsconfig.json b/tsconfig.json index 034ee0e..2fe4d5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": ["src"], + "include": ["src", "src/workers"], "exclude": ["test-server"], "references": [{ "path": "./tsconfig.node.json" }] }