Implement webworker for save operation + Limit the history size #29
6 changed files with 64 additions and 18 deletions
|
@ -10,6 +10,7 @@ import { onKeyDown } from './Shortcuts';
|
||||||
import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations';
|
import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations';
|
||||||
import EditorEvents from '../../Events/EditorEvents';
|
import EditorEvents from '../../Events/EditorEvents';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
|
import { MAX_HISTORY } from '../../utils/default';
|
||||||
|
|
||||||
interface IEditorProps {
|
interface IEditorProps {
|
||||||
configuration: IConfiguration
|
configuration: IConfiguration
|
||||||
|
@ -17,7 +18,12 @@ interface IEditorProps {
|
||||||
historyCurrentStep: number
|
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];
|
export const getCurrentHistoryState = (history: IHistoryState[], historyCurrentStep: number): IHistoryState => history[historyCurrentStep];
|
||||||
|
|
||||||
const Editor: React.FunctionComponent<IEditorProps> = (props) => {
|
const Editor: React.FunctionComponent<IEditorProps> = (props) => {
|
||||||
|
|
|
@ -3,27 +3,38 @@ import { IConfiguration } from '../../Interfaces/IConfiguration';
|
||||||
import { getCircularReplacer } from '../../utils/saveload';
|
import { getCircularReplacer } from '../../utils/saveload';
|
||||||
import { ID } from '../SVG/SVG';
|
import { ID } from '../SVG/SVG';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
|
import Worker from '../../workers/worker?worker';
|
||||||
|
|
||||||
export function SaveEditorAsJSON(
|
export function SaveEditorAsJSON(
|
||||||
history: IHistoryState[],
|
history: IHistoryState[],
|
||||||
historyCurrentStep: number,
|
historyCurrentStep: number,
|
||||||
configuration: IConfiguration
|
configuration: IConfiguration
|
||||||
): void {
|
): void {
|
||||||
const exportName = 'state';
|
const exportName = 'state.json';
|
||||||
const spaces = import.meta.env.DEV ? 4 : 0;
|
const spaces = import.meta.env.DEV ? 4 : 0;
|
||||||
const editorState: IEditorState = {
|
const editorState: IEditorState = {
|
||||||
history,
|
history,
|
||||||
historyCurrentStep,
|
historyCurrentStep,
|
||||||
configuration
|
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 data = JSON.stringify(editorState, getCircularReplacer(), spaces);
|
||||||
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`;
|
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`;
|
||||||
const downloadAnchorNode = document.createElement('a');
|
createDownloadNode(exportName, dataStr);
|
||||||
downloadAnchorNode.setAttribute('href', dataStr);
|
|
||||||
downloadAnchorNode.setAttribute('download', `${exportName}.json`);
|
|
||||||
document.body.appendChild(downloadAnchorNode); // required for firefox
|
|
||||||
downloadAnchorNode.click();
|
|
||||||
downloadAnchorNode.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SaveEditorAsSVG(): void {
|
export function SaveEditorAsSVG(): void {
|
||||||
|
@ -32,10 +43,14 @@ export function SaveEditorAsSVG(): void {
|
||||||
const preface = '<?xml version="1.0" standalone="no"?>\r\n';
|
const preface = '<?xml version="1.0" standalone="no"?>\r\n';
|
||||||
const svgBlob = new Blob([preface, svg.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
|
const svgBlob = new Blob([preface, svg.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
|
||||||
const svgUrl = URL.createObjectURL(svgBlob);
|
const svgUrl = URL.createObjectURL(svgBlob);
|
||||||
const downloadLink = document.createElement('a');
|
createDownloadNode('state.svg', svgUrl);
|
||||||
downloadLink.href = svgUrl;
|
}
|
||||||
downloadLink.download = 'newesttree.svg';
|
|
||||||
document.body.appendChild(downloadLink);
|
function createDownloadNode(filename: string, datastring: string) {
|
||||||
downloadLink.click();
|
const downloadAnchorNode = document.createElement('a');
|
||||||
document.body.removeChild(downloadLink);
|
downloadAnchorNode.href = datastring;
|
||||||
|
downloadAnchorNode.download = filename;
|
||||||
|
document.body.appendChild(downloadAnchorNode); // required for firefox
|
||||||
|
downloadAnchorNode.click();
|
||||||
|
downloadAnchorNode.remove();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,7 @@ export const History: React.FC<IHistoryProps> = (props: IHistoryProps) => {
|
||||||
const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => {
|
const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => {
|
||||||
const reversedIndex = (props.history.length - 1) - index;
|
const reversedIndex = (props.history.length - 1) - index;
|
||||||
const step = props.history[reversedIndex];
|
const step = props.history[reversedIndex];
|
||||||
const desc = reversedIndex > 0
|
const desc = step.LastAction;
|
||||||
? `${reversedIndex}: ${step.LastAction}`
|
|
||||||
: 'Go to the beginning';
|
|
||||||
|
|
||||||
const selectedClass = reversedIndex === props.historyCurrentStep
|
const selectedClass = reversedIndex === props.historyCurrentStep
|
||||||
? 'bg-blue-500 hover:bg-blue-600'
|
? 'bg-blue-500 hover:bg-blue-600'
|
||||||
|
|
|
@ -39,3 +39,5 @@ export const DEFAULT_MAINCONTAINER_PROPS: IProperties = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NOTCHES_LENGTH = 4;
|
export const NOTCHES_LENGTH = 4;
|
||||||
|
|
||||||
|
export const MAX_HISTORY = 200;
|
||||||
|
|
25
src/workers/worker.js
Normal file
25
src/workers/worker.js
Normal file
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -16,7 +16,7 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src", "src/workers"],
|
||||||
"exclude": ["test-server"],
|
"exclude": ["test-server"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue