From 914cea1508b72709f1e737d2634e0152bab489dc Mon Sep 17 00:00:00 2001 From: afonso Date: Thu, 1 Aug 2024 18:32:15 +0100 Subject: [PATCH] CELE-32 feat: Connect join with new enhanced model --- .../components/viewers/TwoD/ContextMenu.tsx | 72 ++++++++++++------- .../src/helpers/twoD/graphRendering.ts | 2 +- .../frontend/src/helpers/twoD/twoDHelpers.ts | 4 +- .../visualizer/frontend/src/models/models.ts | 2 +- .../frontend/src/models/workspace.ts | 2 +- 5 files changed, 52 insertions(+), 30 deletions(-) diff --git a/applications/visualizer/frontend/src/components/viewers/TwoD/ContextMenu.tsx b/applications/visualizer/frontend/src/components/viewers/TwoD/ContextMenu.tsx index ada24604..deafc029 100644 --- a/applications/visualizer/frontend/src/components/viewers/TwoD/ContextMenu.tsx +++ b/applications/visualizer/frontend/src/components/viewers/TwoD/ContextMenu.tsx @@ -2,7 +2,7 @@ import type React from "react"; import {useMemo} from "react"; import {Menu, MenuItem} from "@mui/material"; import {type NeuronGroup, ViewerType} from "../../../models"; -import {calculateSplitPositions, isNeuronClass} from "../../../helpers/twoD/twoDHelpers.ts"; +import {calculateMeanPosition, calculateSplitPositions, isNeuronClass} from "../../../helpers/twoD/twoDHelpers.ts"; import {useSelectedWorkspace} from "../../../hooks/useSelectedWorkspace.ts"; import {Position} from "cytoscape"; @@ -108,7 +108,7 @@ const ContextMenu: React.FC = ({ }).map(neuron => neuron.name); // Calculate the positions for the individual neurons - const basePosition = workspace.availableNeurons[neuronId].viewerData[ViewerType.Graph]?.position || { + const basePosition = workspace.availableNeurons[neuronId].viewerData[ViewerType.Graph]?.defaultPosition || { x: 0, y: 0 }; @@ -117,7 +117,12 @@ const ContextMenu: React.FC = ({ // Update the selected neurons with individual neurons individualNeurons.forEach(neuronName => { newSelectedNeurons.add(neuronName); - positionUpdates[neuronName] = {position: positions[neuronName], visibility: true}; + // Only set the position if it doesn't exist yet + if (!workspace.availableNeurons[neuronName].viewerData[ViewerType.Graph]?.defaultPosition) { + positionUpdates[neuronName] = {position: positions[neuronName], visibility: true}; + } else { + positionUpdates[neuronName] = {visibility: true}; + } }); // Remove the corresponding class from the toJoin set @@ -131,20 +136,8 @@ const ContextMenu: React.FC = ({ } }); - workspace.customUpdate(draft => { - // Update the selected neurons - draft.selectedNeurons = newSelectedNeurons; - - // Update the positions and visibility for the individual neurons and class neuron - Object.entries(positionUpdates).forEach(([neuronName, update]) => { - if (draft.availableNeurons[neuronName]) { - if (update.position !== undefined) { - draft.availableNeurons[neuronName].viewerData[ViewerType.Graph].position = update.position; - } - draft.availableNeurons[neuronName].viewerData[ViewerType.Graph].visibility = update.visibility; - } - }); - }); + // Update the selected neurons in the workspace + updateWorkspace(newSelectedNeurons, positionUpdates) return {split: newSplit, join: newJoin}; }); @@ -157,16 +150,30 @@ const ContextMenu: React.FC = ({ const newSplit = new Set(prevState.split); const newSelectedNeurons = new Set(workspace.selectedNeurons); + const positionUpdates: Record = {}; + workspace.selectedNeurons.forEach(neuronId => { const neuronClass = workspace.availableNeurons[neuronId].nclass; + const individualNeurons = Object.values(workspace.availableNeurons).filter(neuron => neuron.nclass === neuronClass && neuron.name !== neuronClass); + const individualNeuronIds = individualNeurons.map(neuron => neuron.name); + + // Calculate and set the class position if not set already + const classPosition = calculateMeanPosition(individualNeuronIds, workspace); + + if (!workspace.availableNeurons[neuronClass].viewerData[ViewerType.Graph]?.defaultPosition) { + positionUpdates[neuronClass] = {position: classPosition, visibility: true}; + } else { + positionUpdates[neuronClass] = {...positionUpdates[neuronClass], visibility: true}; + } // Remove the individual neurons from the selected neurons and add the class neuron - Object.values(workspace.availableNeurons).forEach(neuron => { - if (neuron.nclass === neuronClass && neuron.name !== neuronClass) { - newSelectedNeurons.delete(neuron.name); - newJoin.add(neuron.name); - } + individualNeuronIds.forEach(neuronName => { + newSelectedNeurons.delete(neuronName); + newJoin.add(neuronName); + + // Set individual neurons' visibility to false + positionUpdates[neuronName] = {visibility: false}; }); newSelectedNeurons.add(neuronClass); @@ -179,15 +186,30 @@ const ContextMenu: React.FC = ({ }); // Update the selected neurons in the workspace - workspace.customUpdate(draft => { - draft.selectedNeurons = newSelectedNeurons; - }); + updateWorkspace(newSelectedNeurons, positionUpdates) return {split: newSplit, join: newJoin}; }); onClose(); }; + const updateWorkspace = (newSelectedNeurons, positionUpdates) => { + workspace.customUpdate(draft => { + // Update the selected neurons + draft.selectedNeurons = newSelectedNeurons; + + // Update the positions and visibility for the individual neurons and class neuron + Object.entries(positionUpdates).forEach(([neuronName, update]) => { + if (draft.availableNeurons[neuronName]) { + if (update.position !== undefined) { + draft.availableNeurons[neuronName].viewerData[ViewerType.Graph].defaultPosition = update.position; + } + draft.availableNeurons[neuronName].viewerData[ViewerType.Graph].visibility = update.visibility; + } + }); + }); + }; + const handleAddToWorkspace = () => { workspace.customUpdate((draft) => { workspace.selectedNeurons.forEach((neuronId) => { diff --git a/applications/visualizer/frontend/src/helpers/twoD/graphRendering.ts b/applications/visualizer/frontend/src/helpers/twoD/graphRendering.ts index 05df7e13..957d642d 100644 --- a/applications/visualizer/frontend/src/helpers/twoD/graphRendering.ts +++ b/applications/visualizer/frontend/src/helpers/twoD/graphRendering.ts @@ -109,7 +109,7 @@ export const computeGraphDifferences = ( } else { const neuron = workspace.availableNeurons[nodeId]; const attributes = extractNeuronAttributes(neuron); - const position = neuron.viewerData[ViewerType.Graph]?.position ?? null; + const position = neuron.viewerData[ViewerType.Graph]?.defaultPosition ?? null; nodesToAdd.push(createNode(nodeId, workspace.selectedNeurons.has(nodeId), attributes, position)); } } diff --git a/applications/visualizer/frontend/src/helpers/twoD/twoDHelpers.ts b/applications/visualizer/frontend/src/helpers/twoD/twoDHelpers.ts index c334c40e..b0239dfd 100644 --- a/applications/visualizer/frontend/src/helpers/twoD/twoDHelpers.ts +++ b/applications/visualizer/frontend/src/helpers/twoD/twoDHelpers.ts @@ -125,7 +125,7 @@ export const calculateMeanPosition = (nodeIds: string[], workspace: Workspace): nodeIds.forEach(nodeId => { const neuron = workspace.availableNeurons[nodeId]; - const position = neuron?.viewerData[ViewerType.Graph]?.position; + const position = neuron?.viewerData[ViewerType.Graph]?.defaultPosition; if (position) { totalX += position.x; totalY += position.y; @@ -193,7 +193,7 @@ export const updateWorkspaceNeurons2DViewerData = (workspace: Workspace, cy: Cor cy.nodes().forEach(node => { const neuronId = node.id(); if (draft.availableNeurons[neuronId]) { - draft.availableNeurons[neuronId].viewerData[ViewerType.Graph].position = { ...node.position() }; + draft.availableNeurons[neuronId].viewerData[ViewerType.Graph].defaultPosition = { ...node.position() }; draft.availableNeurons[neuronId].viewerData[ViewerType.Graph].visibility = true; } }); diff --git a/applications/visualizer/frontend/src/models/models.ts b/applications/visualizer/frontend/src/models/models.ts index 35ff014e..b0ce2a83 100644 --- a/applications/visualizer/frontend/src/models/models.ts +++ b/applications/visualizer/frontend/src/models/models.ts @@ -31,7 +31,7 @@ export interface EnhancedNeuron extends Neuron { } export interface GraphViewerData { - position: Position | null; + defaultPosition: Position | null; visibility: boolean; } diff --git a/applications/visualizer/frontend/src/models/workspace.ts b/applications/visualizer/frontend/src/models/workspace.ts index cc9e6554..917c7f80 100644 --- a/applications/visualizer/frontend/src/models/workspace.ts +++ b/applications/visualizer/frontend/src/models/workspace.ts @@ -186,7 +186,7 @@ export class Workspace { ...neuron, viewerData: { [ViewerType.Graph]: { - position: null, + defaultPosition: null, visibility: false, }, [ViewerType.ThreeD]: {},