Browse Source

Merge pull request #230 from VladCuciureanu/feature/188

Added a 'Collapse/Expand Graph' button
Aykut Saraç 2 years ago
parent
commit
679fc707b0
2 changed files with 71 additions and 6 deletions
  1. 31 6
      src/components/Sidebar/index.tsx
  2. 40 0
      src/hooks/store/useGraph.tsx

+ 31 - 6
src/components/Sidebar/index.tsx

@@ -11,7 +11,12 @@ import {
   AiOutlineLink,
   AiOutlineEdit,
 } from "react-icons/ai";
-import { CgArrowsMergeAltH, CgArrowsShrinkH } from "react-icons/cg";
+import {
+  CgArrowsMergeAltH,
+  CgArrowsMergeAltV,
+  CgArrowsShrinkH,
+  CgArrowsShrinkV,
+} from "react-icons/cg";
 import { FiDownload } from "react-icons/fi";
 import { HiHeart } from "react-icons/hi";
 import { MdCenterFocusWeak } from "react-icons/md";
@@ -22,6 +27,7 @@ import { DownloadModal } from "src/containers/Modals/DownloadModal";
 import { ImportModal } from "src/containers/Modals/ImportModal";
 import { ShareModal } from "src/containers/Modals/ShareModal";
 import useConfig from "src/hooks/store/useConfig";
+import useGraph from "src/hooks/store/useGraph";
 import { getNextLayout } from "src/utils/getNextLayout";
 import styled from "styled-components";
 import shallow from "zustand/shallow";
@@ -154,6 +160,8 @@ export const Sidebar: React.FC = () => {
     shallow
   );
 
+  const { collapseGraph, expandGraph, graphCollapsed } = useGraph();
+
   const handleSave = () => {
     const a = document.createElement("a");
     const file = new Blob([getJson()], { type: "text/plain" });
@@ -163,9 +171,9 @@ export const Sidebar: React.FC = () => {
     a.click();
   };
 
-  const toggleExpandCollapse = () => {
+  const toggleExpandShrink = () => {
     setConfig("expand", !expand);
-    toast(`${expand ? "Collapsed" : "Expanded"} nodes.`);
+    toast(`${expand ? "Shrunk" : "Expanded"} nodes.`);
   };
 
   const toggleLayout = () => {
@@ -173,6 +181,15 @@ export const Sidebar: React.FC = () => {
     setConfig("layout", nextLayout);
   };
 
+  const toggleExpandCollapseGraph = () => {
+    if (graphCollapsed) {
+      expandGraph();
+    } else {
+      collapseGraph();
+    }
+    toast(`${graphCollapsed ? "Expanded" : "Collapsed"} graph.`);
+  };
+
   return (
     <StyledSidebar>
       <StyledTopWrapper>
@@ -205,12 +222,20 @@ export const Sidebar: React.FC = () => {
         <Tooltip
           className="desktop"
           title={expand ? "Shrink Nodes" : "Expand Nodes"}
+        >
+          <StyledElement title="Toggle Expand/Shrink" onClick={toggleExpandShrink}>
+            {expand ? <CgArrowsMergeAltH /> : <CgArrowsShrinkH />}
+          </StyledElement>
+        </Tooltip>
+        <Tooltip
+          className="desktop"
+          title={graphCollapsed ? "Expand Graph" : "Collapse Graph"}
         >
           <StyledElement
-            title="Toggle Expand/Collapse"
-            onClick={toggleExpandCollapse}
+            title="Expand/Collapse Graph"
+            onClick={toggleExpandCollapseGraph}
           >
-            {expand ? <CgArrowsMergeAltH /> : <CgArrowsShrinkH />}
+            {graphCollapsed ? <CgArrowsShrinkV /> : <CgArrowsMergeAltV />}
           </StyledElement>
         </Tooltip>
         <Tooltip className="desktop" title="Save JSON">

+ 40 - 0
src/hooks/store/useGraph.tsx

@@ -5,6 +5,7 @@ import create from "zustand";
 
 const initialStates = {
   loading: false,
+  graphCollapsed: false,
   nodes: [] as NodeData[],
   edges: [] as EdgeData[],
   collapsedNodes: [] as string[],
@@ -18,6 +19,8 @@ interface GraphActions {
   setGraphValue: (key: keyof Graph, value: any) => void;
   expandNodes: (nodeId: string) => void;
   collapseNodes: (nodeId: string) => void;
+  collapseGraph: () => void;
+  expandGraph: () => void;
 }
 
 const useGraph = create<Graph & GraphActions>((set, get) => ({
@@ -53,6 +56,7 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       collapsedParents,
       collapsedNodes,
       collapsedEdges,
+      graphCollapsed: false,
     });
   },
   collapseNodes: nodeId => {
@@ -68,6 +72,42 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       collapsedEdges: get().collapsedEdges.concat(edgeIds),
     });
   },
+  collapseGraph: () => {
+    const edges = get().edges;
+    const tos = edges.map(edge => edge.to);
+    const froms = edges.map(edge => edge.from);
+    const parentNodesIds = froms.filter(id => !tos.includes(id));
+    const secondDegreeNodesIds = edges
+      .filter(edge => parentNodesIds.includes(edge.from))
+      .map(edge => edge.to);
+
+    set({
+      collapsedParents: get()
+        .nodes.filter(
+          node => !parentNodesIds.includes(node.id) && node.data.isParent
+        )
+        .map(node => node.id),
+      collapsedNodes: get()
+        .nodes.filter(
+          node =>
+            !parentNodesIds.includes(node.id) &&
+            !secondDegreeNodesIds.includes(node.id)
+        )
+        .map(node => node.id),
+      collapsedEdges: get()
+        .edges.filter(edge => !parentNodesIds.includes(edge.from))
+        .map(edge => edge.id),
+      graphCollapsed: true,
+    });
+  },
+  expandGraph: () => {
+    set({
+      collapsedNodes: [],
+      collapsedEdges: [],
+      collapsedParents: [],
+      graphCollapsed: false,
+    });
+  },
 }));
 
 export default useGraph;