mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
fix performance
This commit is contained in:
parent
129096f25b
commit
440f0f78ff
@ -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)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user