Skip to content

Commit

Permalink
Move handle layout to nodeChange
Browse files Browse the repository at this point in the history
  • Loading branch information
mcharfadi committed Nov 14, 2023
1 parent e61b81b commit 8ca080e
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ import {
GQLRectangularNodeStyle,
GQLViewModifier,
} from '../graphql/subscription/nodeFragment.types';
import { BorderNodePositon, ConnectionHandle, Diagram, Label, NodeData } from '../renderer/DiagramRenderer.types';
import {
BorderNodePositon,
ConnectionHandle,
Diagram,
EdgeData,
Label,
NodeData,
} from '../renderer/DiagramRenderer.types';
import { MultiLabelEdgeData } from '../renderer/edge/MultiLabelEdge.types';
import { IconLabelNodeData } from '../renderer/node/IconsLabelNode.types';
import { ImageNodeData } from '../renderer/node/ImageNode.types';
Expand Down Expand Up @@ -53,23 +60,55 @@ const toRectangularNode = (
} = gqlNode;

const connectionHandles: ConnectionHandle[] = [];
const numberSourceHandles = (handles: ConnectionHandle[]): string => {
return handles.filter((handle) => handle.type === 'source').length.toString();
};
const numberTargetHandles = (handles: ConnectionHandle[]): string => {
return handles.filter((handle) => handle.type === 'target').length.toString();
};
console.log(insideLabel?.text);
gqlEdges.forEach((edge) => {
if (edge.sourceId === gqlNode.id)
if (edge.sourceId === gqlNode.id) {
console.log(numberSourceHandles(connectionHandles));
console.log(`handle--source--${gqlNode.id}--${numberSourceHandles(connectionHandles)}`);
connectionHandles.push({
id: `handle--source--${edge.id}`,
id: `handle--source--${gqlNode.id}--${numberSourceHandles(connectionHandles)}`,
edgeId: edge.id,
nodeId: gqlNode.id,
position: Position.Right,
type: 'source',
});
if (edge.targetId === gqlNode.id)
}

if (edge.targetId === gqlNode.id) {
console.log(numberTargetHandles(connectionHandles));
console.log(`handle--target--${gqlNode.id}--${numberTargetHandles(connectionHandles)}`);
connectionHandles.push({
id: `handle--target--${edge.id}`,
id: `handle--target--${gqlNode.id}--${numberTargetHandles(connectionHandles)}`,
edgeId: edge.id,
nodeId: gqlNode.id,
position: Position.Left,
type: 'target',
});
}
});
console.log(numberSourceHandles(connectionHandles));
console.log(`Extra handle--source--${gqlNode.id}--${numberSourceHandles(connectionHandles)}`);
connectionHandles.push({
id: `handle--source--${gqlNode.id}--${numberSourceHandles(connectionHandles)}`,
edgeId: '',
nodeId: gqlNode.id,
position: Position.Right,
type: 'source',
});
console.log(numberTargetHandles(connectionHandles));
console.log(`Extra handle--target--${gqlNode.id}--${numberTargetHandles(connectionHandles)}`);
connectionHandles.push({
id: `handle--target--${gqlNode.id}--${numberTargetHandles(connectionHandles)}`,
edgeId: '',
nodeId: gqlNode.id,
position: Position.Left,
type: 'target',
});
const data: RectangularNodeData = {
targetObjectId,
Expand Down Expand Up @@ -530,10 +569,10 @@ export const convertDiagram = (gqlDiagram: GQLDiagram): Diagram => {
const nodeId2Depth = new Map<string, number>();
nodes.forEach((node) => nodeId2Depth.set(node.id, nodeDepth(nodeId2node, node.id)));

const edges: Edge[] = gqlDiagram.edges.map((gqlEdge) => {
const sourceNode = nodeId2node.get(gqlEdge.sourceId);
const targetNode = nodeId2node.get(gqlEdge.targetId);

let usedHandles: string[] = [];
const edges: Edge<EdgeData>[] = gqlDiagram.edges.map((gqlEdge) => {
const sourceNode: Node<NodeData> | undefined = nodeId2node.get(gqlEdge.sourceId);
const targetNode: Node<NodeData> | undefined = nodeId2node.get(gqlEdge.targetId);
const data: MultiLabelEdgeData = {
targetObjectId: gqlEdge.targetObjectId,
targetObjectKind: gqlEdge.targetObjectKind,
Expand All @@ -552,6 +591,17 @@ export const convertDiagram = (gqlDiagram: GQLDiagram): Diagram => {
data.endLabel = convertEdgeLabel(gqlEdge.endLabel);
}

const sourceHandle = sourceNode?.data.connectionHandles
.filter((handle) => handle.type === 'source')
.find((handle) => !usedHandles.find((usedHandles) => usedHandles === handle.id));

const targetHandle = targetNode?.data.connectionHandles
.filter((handle) => handle.type === 'target')
.find((handle) => !usedHandles.find((usedHandles) => usedHandles === handle.id));
if (sourceHandle?.id && targetHandle?.id) {
usedHandles.push(sourceHandle?.id, targetHandle.id);
}

return {
id: gqlEdge.id,
type: 'multiLabelEdge',
Expand All @@ -566,14 +616,14 @@ export const convertDiagram = (gqlDiagram: GQLDiagram): Diagram => {
},
data,
hidden: gqlEdge.state === GQLViewModifier.Hidden,
sourceHandle: `handle--source--${gqlEdge.id}`,
targetHandle: `handle--target--${gqlEdge.id}`,
sourceHandle: sourceHandle?.id,
targetHandle: targetHandle?.id,
sourceNode: sourceNode,
targetNode: targetNode,
interactionWidth: 0.25,
};
});

//id: `handle--target--${gqlNode.id}--${index}`,
return {
metadata: {
id: gqlDiagram.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,37 @@ import {
NodeSelectionChange,
OnEdgesChange,
OnNodesChange,
Position,
ReactFlow,
getConnectedEdges,
useEdgesState,
useNodesState,
useReactFlow,
useStoreApi,
} from 'reactflow';

import 'reactflow/dist/style.css';
import { convertDiagram } from '../converter/convertDiagram';
import { Diagram, DiagramRendererProps, DiagramRendererState, EdgeData, NodeData } from './DiagramRenderer.types';
import {
ConnectionHandle,
Diagram,
DiagramRendererProps,
DiagramRendererState,
EdgeData,
NodeData,
} from './DiagramRenderer.types';
import { useBorderChange } from './border/useBorderChange';
import { ConnectorContextualMenu } from './connector/ConnectorContextualMenu';
import { useConnector } from './connector/useConnector';
import { useDiagramDelete } from './delete/useDiagramDelete';
import { useDiagramDirectEdit } from './direct-edit/useDiagramDirectEdit';
import { useDrop } from './drop/useDrop';
import { useDropNode } from './dropNode/useDropNode';
import { getNodeCenter } from './edge/EdgeLayout';
import { edgeTypes } from './edge/EdgeTypes';
import { MultiLabelEdgeData } from './edge/MultiLabelEdge.types';
import { useLayout } from './layout/useLayout';
import { NodeContext } from './node/NodeContext';
import { NodeContextValue } from './node/NodeContext.types';
import { nodeTypes } from './node/NodeTypes';
import { DiagramNodeType } from './node/NodeTypes.types';
import { DiagramPalette } from './palette/DiagramPalette';
Expand All @@ -53,10 +64,6 @@ import { useDiagramPalette } from './palette/useDiagramPalette';
import { DiagramPanel } from './panel/DiagramPanel';
import { useReconnectEdge } from './reconnect-edge/useReconnectEdge';

import 'reactflow/dist/style.css';
import { NodeContext } from './node/NodeContext';
import { NodeContextValue } from './node/NodeContext.types';

const GRID_STEP: number = 10;

const isNodeSelectChange = (change: NodeChange): change is NodeSelectionChange => change.type === 'select';
Expand Down Expand Up @@ -155,6 +162,86 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload, selection, setSe
const handleNodesChange: OnNodesChange = (changes: NodeChange[]) => {
onNodesChange(onBorderChange(changes));

changes.map((change) => {
if (change.type === 'position' && change.positionAbsolute) {
const movedNode = reactFlowInstance.getNodes().find((node) => change.id === node.id);

if (movedNode) {
const connectedEdges = getConnectedEdges([movedNode], edges);
connectedEdges.forEach((edge) => {
const { sourceNode, targetNode, id } = edge;
if (sourceNode?.id === movedNode.id && targetNode) {
const nodeCenterSourceNode = {
x: change.positionAbsolute?.x ?? 0 + (movedNode.width ?? 0) / 2,
y: change.positionAbsolute?.y ?? 0 + (movedNode.height ?? 0) / 2,
};
const nodeCenterTargetNode = getNodeCenter(targetNode, nodes);
const horizontallDifference = Math.abs(nodeCenterTargetNode.x - nodeCenterSourceNode.x);
const verticalDifference = Math.abs(nodeCenterTargetNode.y - nodeCenterSourceNode.y);

let newPositionSource: Position;
if (horizontallDifference > verticalDifference) {
newPositionSource = nodeCenterTargetNode.x > nodeCenterSourceNode.x ? Position.Right : Position.Left;
} else {
newPositionSource = nodeCenterTargetNode.y > nodeCenterSourceNode.y ? Position.Bottom : Position.Top;
}

let newPositionTarget: Position;
if (horizontallDifference > verticalDifference) {
newPositionTarget = nodeCenterTargetNode.x > nodeCenterSourceNode.x ? Position.Left : Position.Right;
} else {
newPositionTarget = nodeCenterTargetNode.y > nodeCenterSourceNode.y ? Position.Top : Position.Bottom;
}

const nodeSourceConnectionHandles: ConnectionHandle[] = sourceNode.data.connectionHandles;
const nodeTargetConnectionHandles: ConnectionHandle[] = targetNode.data.connectionHandles;
const nodeSourceConnectionHandle: ConnectionHandle | undefined = nodeSourceConnectionHandles.find(
(connectionHandle) => connectionHandle.edgeId === id
);
const nodeTargetConnectionHandle: ConnectionHandle | undefined = nodeTargetConnectionHandles.find(
(connectionHandle) => connectionHandle.edgeId === id
);

if (
nodeSourceConnectionHandle?.position !== newPositionSource &&
nodeTargetConnectionHandle?.position !== newPositionTarget
) {
nodeSourceConnectionHandles.map((nodeConnectionHandle: ConnectionHandle) => {
if (nodeConnectionHandle.edgeId === id && nodeConnectionHandle.type === 'source') {
nodeConnectionHandle.position = newPositionSource;
//nodeConnectionHandle.id = `handle--source--${id}`;
}
return nodeConnectionHandle;
});

nodeTargetConnectionHandles.map((nodeConnectionHandle: ConnectionHandle) => {
if (nodeConnectionHandle.edgeId === id && nodeConnectionHandle.type === 'target') {
nodeConnectionHandle.position = newPositionTarget;
//nodeConnectionHandle.id = `handle--target--${id}`;
}
return nodeConnectionHandle;
});

reactFlowInstance.setNodes((nodes: Node<NodeData>[]) =>
nodes.map((node) => {
//console.log('reactFlowInstance.setNodes');
if (sourceNode.id === node.id) {
node.data = { ...node.data, connectionHandles: nodeSourceConnectionHandles };
}
if (targetNode.id === node.id) {
node.data = { ...node.data, connectionHandles: nodeTargetConnectionHandles };
}
return node;
})
);
}
}
});
}
}
return change;
});

const selectionEntries: SelectionEntry[] = changes
.filter(isNodeSelectChange)
.filter((change) => change.selected)
Expand Down Expand Up @@ -246,6 +333,14 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload, selection, setSe

const { backgroundColor, smallGridColor, largeGridColor } = dropFeedbackStyleProvider.getDiagramBackgroundStyle();

const handleOnNodeDrag = (
event: React.MouseEvent<Element, MouseEvent>,
node: Node<any, string | undefined>,
nodes: Node<any, string | undefined>[]
) => {
onNodeDrag(event, node, nodes);
};

return (
<ReactFlow
nodes={nodes}
Expand All @@ -265,7 +360,7 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload, selection, setSe
onMove={() => hideDiagramPalette()}
onDrop={onDrop}
onDragOver={onDragOver}
onNodeDrag={onNodeDrag}
onNodeDrag={handleOnNodeDrag}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop((node: Node) => {
const resetPosition: NodePositionChange = {
Expand All @@ -284,7 +379,7 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload, selection, setSe
minZoom={0.1}
snapToGrid={state.snapToGrid}
snapGrid={[GRID_STEP, GRID_STEP]}
connectionMode={ConnectionMode.Loose}
connectionMode={ConnectionMode.Strict}
zoomOnDoubleClick={false}
ref={ref}>
{state.snapToGrid ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ import { ServerContext, ServerContextValue, useMultiToast } from '@eclipse-siriu
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import { useContext, useEffect } from 'react';
import { DiagramContext } from '../../contexts/DiagramContext';
import { DiagramContextValue } from '../../contexts/DiagramContext.types';
import {
ConnectorContextualMenuProps,
GetConnectorToolsData,
GetConnectorToolsVariables,
GQLDiagramDescription,
GQLErrorPayload,
GQLInvokeSingleClickOnTwoDiagramElementsToolData,
GQLInvokeSingleClickOnTwoDiagramElementsToolInput,
GQLInvokeSingleClickOnTwoDiagramElementsToolVariables,
GQLRepresentationDescription,
GQLTool,
GetConnectorToolsData,
GetConnectorToolsVariables,
} from './ConnectorContextualMenu.types';
import { useConnector } from './useConnector';

Expand Down Expand Up @@ -116,16 +116,12 @@ export const ConnectorContextualMenu = ({}: ConnectorContextualMenuProps) => {

const { addMessages, addErrorMessage } = useMultiToast();

const connectionSource: HTMLElement | null = connection
? document.querySelector(`[data-id="${connection.source}"]`)
: null;

const connectionTarget: HTMLElement | null = connection
? document.querySelector(`[data-id="${connection.target}"]`)
: null;

const sourceDiagramElementId = connectionSource?.dataset.id ?? '';
const targetDiagramElementId = connectionTarget?.dataset.id ?? '';
const sourceDiagramElementId = connection?.source ?? '';
const targetDiagramElementId = connection?.target ?? '';

const variables: GetConnectorToolsVariables = {
editingContextId,
Expand All @@ -135,7 +131,7 @@ export const ConnectorContextualMenu = ({}: ConnectorContextualMenuProps) => {
};
const { data, error } = useQuery<GetConnectorToolsData, GetConnectorToolsVariables>(getConnectorToolsQuery, {
variables,
skip: !connectionSource || !connectionTarget,
skip: !sourceDiagramElementId || !targetDiagramElementId,
});

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const getParameters: GetParameters = (nodeA, nodeB, edgeId, visiblesNodes) => {
};
};

const getNodeCenter: GetNodeCenter = (node, visiblesNodes) => {
export const getNodeCenter: GetNodeCenter = (node, visiblesNodes) => {
if (node.positionAbsolute?.x && node.positionAbsolute?.y) {
return {
x: node.positionAbsolute?.x ?? 0 + (node.width ?? 0) / 2,
Expand Down
Loading

0 comments on commit 8ca080e

Please sign in to comment.