-
Notifications
You must be signed in to change notification settings - Fork 1
20 Visualization Frontend
JP Barbosa edited this page Apr 15, 2023
·
2 revisions
npm install react-graph-vis
code ./vite.config.ts
...
export default defineConfig({
...
define: {
global: {},
},
});
code ./packages/web/src/react-graph-vis.d.ts
declare module 'react-graph-vis' {
import { Network, NetworkEvents, Options, Node, Edge, DataSet } from 'vis';
import { Component } from 'react';
export { Network, NetworkEvents, Options, Node, Edge, DataSet } from 'vis';
export interface graphEvents {
[event: NetworkEvents]: (params?: any) => void;
}
//Doesn't appear that this module supports passing in a vis.DataSet directly. Once it does graph can just use the Data object from vis.
export interface GraphVisData {
nodes: Node[];
edges: Edge[];
}
export interface NetworkGraphProps {
graph: GraphVisData;
options?: Options;
events?: graphEvents;
getNetwork?: (network: Network) => void;
identifier?: string;
style?: React.CSSProperties;
getNodes?: (nodes: DataSet) => void;
getEdges?: (edges: DataSet) => void;
}
export interface NetworkGraphState {
identifier: string;
}
export default class NetworkGraph extends Component<
NetworkGraphProps,
NetworkGraphState
> {
render();
}
}
code ./packages/web/src/api/visualization.ts
import axios from 'axios';
import { GraphVisData } from 'react-graph-vis';
const url = `${import.meta.env.VITE_API_URL}/visualization`;
export const visualization = {
get: (search: string) =>
axios.get<GraphVisData>(`${url}?search=${search}`).then((res) => res.data),
};
code ./packages/web/src/api/index.ts
...
export * from './visualization';
code ./packages/web/src/pages/visualization/index.tsx
import { useState } from 'react';
import { Content } from './Content';
export const Visualization: React.FC = () => {
const [search, setSearch] = useState<string>('');
return (
<div className="page">
<div className="actions-bar">
<h2>Graph Visualization</h2>
<div className="filter">
<input
type="text"
value={search}
placeholder="Search by movie title or actor name..."
onChange={(e) => setSearch(e.target.value)}
/>
</div>
</div>
<Content search={search} />
</div>
);
};
code ./packages/web/src/pages/visualization/Content.tsx
import { useQuery } from 'react-query';
import { GraphVisData } from 'react-graph-vis';
import { AxiosCustomError } from '@neo4j-crud/shared';
import * as api from '../../api';
import { AlertCombo, GraphVis } from '../../components';
import { useDebounce } from '../../hooks/useDebounce';
type ContentProps = {
search: string;
};
export const Content: React.FC<ContentProps> = ({ search }) => {
const debouncedSearch = useDebounce(search, 500);
const { data, error, isLoading } = useQuery<GraphVisData, AxiosCustomError>(
['visualization', debouncedSearch],
() => api.visualization.get(search)
);
const noData = !data || data.nodes.length === 0;
if (error || isLoading || noData) {
return <AlertCombo error={error} isLoading={isLoading} noData={noData} />;
}
return (
<div
style={{
height: '100%',
}}
>
<GraphVis graph={data} />
</div>
);
};
code ./packages/web/src/components/GraphVis.tsx
import ReactGraphVis, { GraphVisData } from 'react-graph-vis';
type GraphVisProps = {
graph: GraphVisData;
};
export const GraphVis: React.FC<GraphVisProps> = ({ graph }) => {
return (
<ReactGraphVis
graph={graph}
options={{
//autoResize: true,
height: '100%',
nodes: {
shape: 'dot',
font: {
strokeWidth: 4,
},
},
edges: {
width: 1,
color: 'darkorange',
length: 200,
font: {
size: 10,
strokeWidth: 3,
// align: 'middle', // Performance issue.
},
},
physics: {
// Even though it's disabled the options still apply to network.stabilize().
enabled: true,
solver: 'repulsion',
repulsion: {
nodeDistance: 200, // Put more distance between the nodes.
},
stabilization: {
iterations: 200,
//fit: true,
},
},
}}
getNetwork={(network) => {
network.fit({
animation: {
duration: 1000,
easingFunction: 'easeInOutQuad',
},
nodes: graph.nodes.map((n) => String(n.id)),
});
}}
/>
);
};
code ./packages/web/src/components/index.ts
...
export * from './GraphVis';
code ./packages/web/src/pages/index.ts
...
export * from './visualization';
code ./packages/web/src/app/app.tsx
...
import { ..., Visualization } from './pages';
export function App() {
return (
<>
<Header />
<Routes>
...
<Route path="/visualization/*" element={<Visualization />} />
</Routes>
</>
);
}
export default App;
code ./packages/web/src/components/Header.tsx
...
export const Header: React.FC = () => {
const navItems: NavItem[] = [
...
{ path: '/visualization', label: 'Graph Visualization' },
];
return ...;
};
open http://localhost:4200/visualization
Graph | Search |
git add .
git commit -m "Visualization Frontend"