fix performance

This commit is contained in:
AykutSarac 2022-08-13 19:15:20 +03:00
parent 129096f25b
commit 440f0f78ff
2 changed files with 96 additions and 69 deletions

View File

@ -19,15 +19,13 @@ import useConfig from "src/hooks/store/useConfig";
import styled from "styled-components"; import styled from "styled-components";
import shallow from "zustand/shallow"; import shallow from "zustand/shallow";
interface GraphProps { interface LayoutProps {
json: string; json: string;
isWidget?: boolean; isWidget: boolean;
openModal: () => void;
setSelectedNode: (node: object) => void;
} }
const wheelOptions = {
step: 0.05,
};
const StyledEditorWrapper = styled.div<{ isWidget: boolean }>` const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -43,23 +41,12 @@ const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
} }
`; `;
export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({ const MemoizedGraph = React.memo(function Layout({
json, json,
isWidget = false, isWidget,
...props openModal,
}) => { setSelectedNode,
const [isModalVisible, setModalVisible] = React.useState(false); }: LayoutProps) {
const updateSetting = useConfig((state) => state.updateSetting);
const [expand, layout] = useConfig(
(state) => [state.settings.expand, state.settings.layout],
shallow
);
const onInit = (ref: ReactZoomPanPinchRef) => {
updateSetting("zoomPanPinch", ref);
};
const [selectedNode, setSelectedNode] = React.useState<NodeData | null>(null);
const [nodes, setNodes] = React.useState<NodeData[]>([]); const [nodes, setNodes] = React.useState<NodeData[]>([]);
const [edges, setEdges] = React.useState<EdgeData[]>([]); const [edges, setEdges] = React.useState<EdgeData[]>([]);
const [size, setSize] = React.useState({ const [size, setSize] = React.useState({
@ -67,6 +54,12 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
height: 2000, height: 2000,
}); });
const updateSetting = useConfig((state) => state.updateSetting);
const [expand, layout] = useConfig(
(state) => [state.settings.expand, state.settings.layout],
shallow
);
React.useEffect(() => { React.useEffect(() => {
const { nodes, edges } = getEdgeNodes(json, expand); const { nodes, edges } = getEdgeNodes(json, expand);
@ -74,6 +67,10 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
setEdges(edges); setEdges(edges);
}, [json, expand]); }, [json, expand]);
const onInit = (ref: ReactZoomPanPinchRef) => {
updateSetting("zoomPanPinch", ref);
};
const onCanvasClick = () => { const onCanvasClick = () => {
const input = document.querySelector("input:focus") as HTMLInputElement; const input = document.querySelector("input:focus") as HTMLInputElement;
if (input) input.blur(); if (input) input.blur();
@ -88,54 +85,74 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
e: React.MouseEvent<SVGElement>, e: React.MouseEvent<SVGElement>,
props: NodeProps props: NodeProps
) => { ) => {
setSelectedNode(props.properties); setSelectedNode(props.properties.text);
setModalVisible(true); openModal();
}; };
return ( return (
<> <StyledEditorWrapper isWidget={isWidget}>
<StyledEditorWrapper isWidget={isWidget}> <TransformWrapper
<TransformWrapper onInit={onInit}
maxScale={1.8} maxScale={1.8}
minScale={0.4} minScale={0.4}
initialScale={0.7} initialScale={0.7}
wheel={wheelOptions} wheel={{
onInit={onInit} step: 0.05,
}}
>
<TransformComponent
wrapperStyle={{
width: "100%",
height: "100%",
overflow: "hidden",
}}
> >
<TransformComponent <Canvas
wrapperStyle={{ nodes={nodes}
width: "100%", edges={edges}
height: "100%", maxWidth={size.width + 100}
overflow: "hidden", maxHeight={size.height + 100}
}} direction={layout}
> key={layout}
<Canvas onCanvasClick={onCanvasClick}
nodes={nodes} onLayoutChange={onLayoutChange}
edges={edges} node={(props) => (
maxWidth={size.width + 100} <CustomNode
maxHeight={size.height + 100} onClick={(e) => handleNodeClick(e, props)}
direction={layout} {...props}
key={layout} />
onCanvasClick={onCanvasClick} )}
onLayoutChange={onLayoutChange} zoomable={false}
node={(props) => ( readonly
<CustomNode />
onClick={(e) => handleNodeClick(e, props)} </TransformComponent>
{...props} </TransformWrapper>
/> </StyledEditorWrapper>
)} );
zoomable={false} });
readonly
{...props} export const Graph: React.FC<{ json: string; isWidget?: boolean }> = ({
/> json,
</TransformComponent> isWidget = false,
</TransformWrapper> }) => {
</StyledEditorWrapper> const [isModalVisible, setModalVisible] = React.useState(false);
{!isWidget && selectedNode && ( const [selectedNode, setSelectedNode] = React.useState<object>({});
const openModal = React.useCallback(() => setModalVisible(true), []);
return (
<>
<MemoizedGraph
json={json}
openModal={openModal}
setSelectedNode={setSelectedNode}
isWidget={isWidget}
/>
{!isWidget && (
<NodeModal <NodeModal
selectedNode={selectedNode.text} selectedNode={selectedNode}
visible={isModalVisible} visible={isModalVisible}
setVisible={setModalVisible} closeModal={() => setModalVisible(false)}
/> />
)} )}
</> </>

View File

@ -1,10 +1,17 @@
import React from "react"; import React from "react";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { FiCopy } from "react-icons/fi"; import { FiCopy } from "react-icons/fi";
import { NodeData } from "reaflow";
import { Button } from "src/components/Button"; import { Button } from "src/components/Button";
import { Modal } from "src/components/Modal"; import { Modal } from "src/components/Modal";
import styled from "styled-components"; import styled from "styled-components";
interface NodeModalProps {
selectedNode: object;
visible: boolean;
closeModal: () => void;
}
const StyledTextarea = styled.textarea` const StyledTextarea = styled.textarea`
resize: none; resize: none;
width: 100%; width: 100%;
@ -19,16 +26,19 @@ const StyledTextarea = styled.textarea`
border: none; border: none;
`; `;
export const NodeModal = ({ selectedNode, visible = true, setVisible }) => { export const NodeModal = ({
selectedNode,
visible,
closeModal,
}: NodeModalProps) => {
const handleClipboard = () => { const handleClipboard = () => {
toast("Content copied to clipboard!"); toast("Content copied to clipboard!");
navigator.clipboard.writeText(JSON.stringify(selectedNode)); navigator.clipboard.writeText(JSON.stringify(selectedNode));
setVisible(false); closeModal();
}; };
return ( return (
<Modal visible={visible} setVisible={setVisible}> <Modal visible={visible} setVisible={closeModal}>
<Modal.Header>Node Content</Modal.Header> <Modal.Header>Node Content</Modal.Header>
<Modal.Content> <Modal.Content>
<StyledTextarea <StyledTextarea
@ -42,7 +52,7 @@ export const NodeModal = ({ selectedNode, visible = true, setVisible }) => {
)} )}
/> />
</Modal.Content> </Modal.Content>
<Modal.Controls setVisible={setVisible}> <Modal.Controls setVisible={closeModal}>
<Button status="SECONDARY" onClick={handleClipboard}> <Button status="SECONDARY" onClick={handleClipboard}>
<FiCopy size={18} /> Clipboard <FiCopy size={18} /> Clipboard
</Button> </Button>