chore(examples): add save restore
This commit is contained in:
Generated
+16423
-189
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@craco/craco": "^5.7.0",
|
"@craco/craco": "^5.7.0",
|
||||||
|
"localforage": "^1.9.0",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-flow-renderer": "file:..",
|
"react-flow-renderer": "file:..",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import React, { memo, useCallback, useState } from 'react';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import ReactFlow, { ReactFlowProvider, useZoomPanHelper, removeElements, addEdge } from 'react-flow-renderer';
|
||||||
|
|
||||||
|
import './save.css';
|
||||||
|
|
||||||
|
localforage.config({
|
||||||
|
name: 'react-flow',
|
||||||
|
storeName: 'flow',
|
||||||
|
});
|
||||||
|
|
||||||
|
const flowKey = 'save-restore-key';
|
||||||
|
|
||||||
|
const initialElements = [
|
||||||
|
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
|
||||||
|
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||||
|
{ id: 'e1-2', source: '1', target: '2' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const getNodeId = () => `randomnode_${+new Date()}`;
|
||||||
|
|
||||||
|
const Controls = memo(({ rfInstance, setElements }) => {
|
||||||
|
const { transform } = useZoomPanHelper();
|
||||||
|
|
||||||
|
const onSave = useCallback(() => {
|
||||||
|
const flow = rfInstance.toObject();
|
||||||
|
localforage.setItem(flowKey, flow);
|
||||||
|
}, [rfInstance]);
|
||||||
|
|
||||||
|
const onRestore = useCallback(() => {
|
||||||
|
const onRestoreFlow = async () => {
|
||||||
|
const flow = await localforage.getItem(flowKey);
|
||||||
|
|
||||||
|
if (flow) {
|
||||||
|
const [x = 0, y = 0] = flow.position;
|
||||||
|
setElements(flow.elements || []);
|
||||||
|
transform({ x, y, zoom: flow.zoom || 0 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onRestoreFlow();
|
||||||
|
}, [rfInstance, setElements, transform]);
|
||||||
|
|
||||||
|
const onAdd = useCallback(() => {
|
||||||
|
const newNode = {
|
||||||
|
id: `random_node-${getNodeId()}`,
|
||||||
|
data: { label: 'Added node' },
|
||||||
|
position: { x: Math.random() * window.innerWidth - 100, y: Math.random() * window.innerHeight },
|
||||||
|
};
|
||||||
|
setElements((els) => els.concat(newNode));
|
||||||
|
}, [setElements]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="save__controls">
|
||||||
|
<button onClick={onSave}>save</button>
|
||||||
|
<button onClick={onRestore}>restore</button>
|
||||||
|
<button onClick={onAdd}>add node</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const SaveRestore = () => {
|
||||||
|
const [rfInstance, setRfInstance] = useState(null);
|
||||||
|
const [elements, setElements] = useState(initialElements);
|
||||||
|
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
||||||
|
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<ReactFlow elements={elements} onElementsRemove={onElementsRemove} onConnect={onConnect} onLoad={setRfInstance}>
|
||||||
|
{rfInstance && <Controls rfInstance={rfInstance} setElements={setElements} />}
|
||||||
|
</ReactFlow>
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SaveRestore;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.save__controls {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 4;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save__controls button {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import CustomConnectionLine from './CustomConnectionLine';
|
|||||||
import NodeTypeChange from './NodeTypeChange';
|
import NodeTypeChange from './NodeTypeChange';
|
||||||
import UpdatableEdge from './UpdatableEdge';
|
import UpdatableEdge from './UpdatableEdge';
|
||||||
import UpdateNode from './UpdateNode';
|
import UpdateNode from './UpdateNode';
|
||||||
|
import SaveRestore from './SaveRestore';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -90,6 +91,11 @@ const routes = [
|
|||||||
component: UpdateNode,
|
component: UpdateNode,
|
||||||
label: 'Update Node',
|
label: 'Update Node',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/save-restore',
|
||||||
|
component: SaveRestore,
|
||||||
|
label: 'Save Restore',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const navLinks = routes.filter((route) => route.label);
|
const navLinks = routes.filter((route) => route.label);
|
||||||
|
|||||||
Reference in New Issue
Block a user