Add save/load functionality from file (#146)

Fixes #143
This commit is contained in:
Lucas Azzola 2020-01-05 15:20:09 +11:00 committed by Christopher Chedeau
parent 30ccaf0152
commit 7c321b49ab

View File

@ -460,6 +460,47 @@ function renderScene(
} }
} }
function saveAsJSON() {
const serialized = JSON.stringify({
version: 1,
source: window.location.origin,
elements
});
saveFile(
"excalidraw.json",
"data:text/plain;charset=utf-8," + encodeURIComponent(serialized)
);
}
function loadFromJSON() {
const input = document.createElement("input");
const reader = new FileReader();
input.type = "file";
input.accept = ".json";
input.onchange = () => {
if (!input.files!.length) {
alert("A file was not selected.");
return;
}
reader.readAsText(input.files![0], "utf8");
};
input.click();
return new Promise(resolve => {
reader.onloadend = () => {
if (reader.readyState === FileReader.DONE) {
const data = JSON.parse(reader.result as string);
restore(data.elements, null);
resolve();
}
};
});
}
function exportAsPNG({ function exportAsPNG({
exportBackground, exportBackground,
exportPadding = 10, exportPadding = 10,
@ -513,17 +554,23 @@ function exportAsPNG({
} }
); );
// create a temporary <a> elem which we'll use to download the image saveFile("excalidraw.png", tempCanvas.toDataURL("image/png"));
const link = document.createElement("a");
link.setAttribute("download", "excalidraw.png");
link.setAttribute("href", tempCanvas.toDataURL("image/png"));
link.click();
// clean up the DOM // clean up the DOM
link.remove();
if (tempCanvas !== canvas) tempCanvas.remove(); if (tempCanvas !== canvas) tempCanvas.remove();
} }
function saveFile(name: string, data: string) {
// create a temporary <a> elem which we'll use to download the image
const link = document.createElement("a");
link.setAttribute("download", name);
link.setAttribute("href", data);
link.click();
// clean up
link.remove();
}
function rotate(x1: number, y1: number, x2: number, y2: number, angle: number) { function rotate(x1: number, y1: number, x2: number, y2: number, angle: number) {
// 𝑎𝑥=(𝑎𝑥𝑐𝑥)cos𝜃(𝑎𝑦𝑐𝑦)sin𝜃+𝑐𝑥 // 𝑎𝑥=(𝑎𝑥𝑐𝑥)cos𝜃(𝑎𝑦𝑐𝑦)sin𝜃+𝑐𝑥
// 𝑎𝑦=(𝑎𝑥𝑐𝑥)sin𝜃+(𝑎𝑦𝑐𝑦)cos𝜃+𝑐𝑦. // 𝑎𝑦=(𝑎𝑥𝑐𝑥)sin𝜃+(𝑎𝑦𝑐𝑦)cos𝜃+𝑐𝑦.
@ -709,13 +756,26 @@ function save(state: AppState) {
localStorage.setItem(LOCAL_STORAGE_KEY_STATE, JSON.stringify(state)); localStorage.setItem(LOCAL_STORAGE_KEY_STATE, JSON.stringify(state));
} }
function restore() { function restoreFromLocalStorage() {
try {
const savedElements = localStorage.getItem(LOCAL_STORAGE_KEY); const savedElements = localStorage.getItem(LOCAL_STORAGE_KEY);
const savedState = localStorage.getItem(LOCAL_STORAGE_KEY_STATE); const savedState = localStorage.getItem(LOCAL_STORAGE_KEY_STATE);
return restore(savedElements, savedState);
}
function restore(
savedElements: string | ExcalidrawElement[] | null,
savedState: string | null
) {
try {
if (savedElements) { if (savedElements) {
elements.splice(0, elements.length, ...JSON.parse(savedElements)); elements.splice(
0,
elements.length,
...(typeof savedElements === "string"
? JSON.parse(savedElements)
: savedElements)
);
elements.forEach((element: ExcalidrawElement) => generateDraw(element)); elements.forEach((element: ExcalidrawElement) => generateDraw(element));
} }
@ -843,7 +903,7 @@ class App extends React.Component<{}, AppState> {
document.addEventListener("keydown", this.onKeyDown, false); document.addEventListener("keydown", this.onKeyDown, false);
window.addEventListener("resize", this.onResize, false); window.addEventListener("resize", this.onResize, false);
const savedState = restore(); const savedState = restoreFromLocalStorage();
if (savedState) { if (savedState) {
this.setState(savedState); this.setState(savedState);
} }
@ -1117,6 +1177,23 @@ class App extends React.Component<{}, AppState> {
background background
</label> </label>
</div> </div>
<h4>Save/Load</h4>
<div className="panelColumn">
<button
onClick={() => {
saveAsJSON();
}}
>
Save as...
</button>
<button
onClick={() => {
loadFromJSON().then(() => this.forceUpdate());
}}
>
Load file...
</button>
</div>
{someElementIsSelected() && ( {someElementIsSelected() && (
<> <>
<h4>Shape options</h4> <h4>Shape options</h4>