Skip to content

Commit

Permalink
fix: possibility of moving blocks in visualiser (#516)
Browse files Browse the repository at this point in the history
  • Loading branch information
magicmatatjahu authored Nov 30, 2022
1 parent 462c86e commit 1710744
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/components/Visualiser/Controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const Controls: FunctionComponent<ControlsProps> = () => {
}, [animateNodes]);

const reloadInterface = () => {
setNodes([...calculateNodesForDynamicLayout(nodes)]);
setNodes(calculateNodesForDynamicLayout(nodes));
fitView();
};

Expand Down
62 changes: 21 additions & 41 deletions src/components/Visualiser/FlowDiagram.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,44 @@
import { useState, useEffect, useCallback } from 'react';
import ReactFlow, { Controls as FlowControls, Background, BackgroundVariant, useReactFlow, useStore, useNodesState, useEdgesState, useNodes, useEdges } from 'reactflow';
import { useEffect } from 'react';
import ReactFlow, { Controls as FlowControls, Background, BackgroundVariant, useReactFlow, useStore, useNodesState, useEdgesState, useNodes } from 'reactflow';

import { Controls } from './Controls';
import NodeTypes from './Nodes';
import { Controls } from './Controls';
import { getElementsFromAsyncAPISpec } from './utils/node-factory';
import { calculateNodesForDynamicLayout } from './utils/node-calculator';

import type { OldAsyncAPIDocument as AsyncAPIDocument } from '@asyncapi/parser/cjs';
import type { FunctionComponent, PropsWithChildren } from 'react';
import type { ReactFlowInstance } from 'reactflow';
import type { FunctionComponent } from 'react';

interface FlowDiagramProps {
parsedSpec: AsyncAPIDocument;
}

interface AutoLayoutProps extends PropsWithChildren {
elementsToRenderNumber: number;
}
interface AutoLayoutProps {}

const AutoLayout: FunctionComponent<AutoLayoutProps> = ({ elementsToRenderNumber }) => {
const AutoLayout: FunctionComponent<AutoLayoutProps> = () => {
const { fitView } = useReactFlow();
const nodes = useNodes();
const edges = useEdges();
const setNodes = useStore(state => state.setNodes);

const rerender = () => {
const calculatedNodes = calculateNodesForDynamicLayout(nodes);
setNodes(calculatedNodes);
fitView();
};

useEffect(() => {
if (elementsToRenderNumber === (nodes.length + edges.length)) {
// stop overlap no nodes when re-render, recalculate where they should go
const nodesWithOrginalPosition = nodes.filter(node => node.position.x === 0 && node.position.y === 0);
if (nodesWithOrginalPosition.length > 1) {
setTimeout(() => {
rerender();
}, 1);
}
if (nodes.length === 0 || !nodes[0].width) {
return;
}

const nodesWithOrginalPosition = nodes.filter(node => node.position.x === 0 && node.position.y === 0);
if (nodesWithOrginalPosition.length > 1) {
const calculatedNodes = calculateNodesForDynamicLayout(nodes);
setNodes(calculatedNodes);
fitView();
}
}, [nodes]);

return null;
};

export const FlowDiagram: FunctionComponent<FlowDiagramProps> = ({ parsedSpec }) => {
const [loaded, setLoaded] = useState(false);

const elements = getElementsFromAsyncAPISpec(parsedSpec);
const _nodes = elements.map(el => el.node).filter(Boolean);
const _edges = elements.map(el => el.edge).filter(Boolean);

const [nodes, setNodes, onNodesChange] = useNodesState(_nodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(_edges);

const onInit = useCallback((instance: ReactFlowInstance) => {
setLoaded(true);
instance.fitView();
}, []);
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);

useEffect(() => {
const elements = getElementsFromAsyncAPISpec(parsedSpec);
Expand All @@ -76,15 +56,15 @@ export const FlowDiagram: FunctionComponent<FlowDiagramProps> = ({ parsedSpec })
nodes={nodes}
edges={edges}
minZoom={0.1}
onInit={onInit}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView={true}
>
<Background color="#d1d1d3" variant={BackgroundVariant.Dots} gap={20} size={1} className="bg-gray-200" />
{loaded && <AutoLayout elementsToRenderNumber={nodes.length + edges.length} />}
<Background variant={BackgroundVariant.Dots} gap={20} size={1} className="bg-gray-200" />
<AutoLayout />
<Controls />
<div className="-mt-20">
<FlowControls style={{ bottom: '105px' }} />
<FlowControls style={{ bottom: '95px' }} className='bg-white' />
</div>
</ReactFlow>
<div className="m-4 px-2 text-lg absolute text-gray-800 top-0 left-0 bg-white space-x-2 py-2 border border-gray-100 inline-block">
Expand Down
13 changes: 5 additions & 8 deletions src/components/Visualiser/utils/node-calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const calculateNodesForDynamicLayout = (elements: Node[]) => {
const elementsGroupedByColumn = groupNodesByColumn(elements);

const newElements: { nodes: Node[], currentXPosition: number } = Object.keys(elementsGroupedByColumn).reduce(
(data: any, group: string) => {
(data: { nodes: Node[], currentXPosition: number }, group: string) => {
const groupNodes = elementsGroupedByColumn[String(group)];

// eslint-disable-next-line
Expand All @@ -35,24 +35,21 @@ export const calculateNodesForDynamicLayout = (elements: Node[]) => {

// For each group (column), render the nodes based on height they require (with some padding)
const { positionedNodes } = groupNodes.reduce(
(groupedNodes: any, currentNode: Node) => {
(groupedNodes: { positionedNodes: Node[], currentYPosition: number }, currentNode: Node) => {
const verticalPadding = 40;

currentNode.position = {
x: data.currentXPosition,
y: groupedNodes.currentYPosition,
};
currentNode.position.x = data.currentXPosition;
currentNode.position.y = groupedNodes.currentYPosition;

return {
positionedNodes: groupedNodes.positionedNodes.concat([currentNode]),
currentYPosition: groupedNodes.currentYPosition + currentNode.height + verticalPadding,
currentYPosition: groupedNodes.currentYPosition + (currentNode.height || 0) + verticalPadding,
};
},
{ positionedNodes: [], currentYPosition: 0 }
);

return {
...data,
nodes: [...data.nodes, ...positionedNodes],
currentXPosition: data.currentXPosition + maxWidthOfColumn + 100,
};
Expand Down

0 comments on commit 1710744

Please sign in to comment.