From 991683fd7edcb8ab3b125e4e5d82cebdae2b7dbe Mon Sep 17 00:00:00 2001 From: Siklos Date: Mon, 15 Aug 2022 16:56:32 +0200 Subject: [PATCH] Add Web Worker for the save to json function --- src/Components/Editor/Save.ts | 41 ++++++++++++++++++++++++----------- src/workers/worker.js | 25 +++++++++++++++++++++ tsconfig.json | 2 +- 3 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/workers/worker.js 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/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" }] }