Skip to content

Commit

Permalink
feat: resize floating molecule
Browse files Browse the repository at this point in the history
- refactor floating molecules and move it out of the svg and use 'react-rnd'
- include the floating molecules when generating the SVG

close #1929
  • Loading branch information
hamed-musallam committed Jan 30, 2023
1 parent 7f61114 commit 52d16e6
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 86 deletions.
Expand Up @@ -5,7 +5,10 @@ import Button from '../../../elements/Button';

export default function ActionsButton({ onFloatBtnClick }) {
return (
<div data-no-export="true" style={{ display: 'flex', zIndex: 0 }}>
<div
className="float-molecule-actions"
style={{ display: 'flex', zIndex: 0 }}
>
<Button.Action
style={{ fontSize: '14px' }}
fill="clear"
Expand Down
@@ -1,19 +1,19 @@
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import OCL from 'openchemlib/full';
import { useCallback } from 'react';
import { ResponsiveChart } from 'react-d3-utils';
import OCLnmr from 'react-ocl-nmr';
import { Rnd } from 'react-rnd';

import {
MoleculeBoundingRect,
MoleculeView,
StateMoleculeExtended,
} from '../../../../data/molecules/Molecule';
import { Ranges } from '../../../../data/types/data1d/index';
import { Zones } from '../../../../data/types/data2d/index';
import { useDispatch } from '../../../context/DispatchContext';
import { useGlobal } from '../../../context/GlobalContext';
import SVGDraggable from '../../../elements/draggable/SVGDraggable';
import { Position } from '../../../elements/draggable/useDraggable';
import { useMoleculeEditor } from '../../../modal/MoleculeStructureEditorModal';
import useAtomAssignment from '../../../panels/MoleculesPanel/useAtomAssignment';
import { DISPLAYER_MODE } from '../../../reducer/core/Constants';
Expand Down Expand Up @@ -41,6 +41,11 @@ const style = css`
visibility: hidden;
}
.content {
width: 100%;
height: 100%;
}
&:hover {
border: 1px solid #ebecf1;
background-color: white;
Expand All @@ -49,7 +54,7 @@ const style = css`
}
}
`;
export const DRAGGABLE_STRUCTURE_INITIAL_POSITION = { x: 100, y: 50 };

export function DraggableStructure(props: DraggableStructureProps) {
const {
zones,
Expand All @@ -63,80 +68,98 @@ export function DraggableStructure(props: DraggableStructureProps) {
const { viewerRef } = useGlobal();
const dispatch = useDispatch();
const openMoleculeEditor = useMoleculeEditor();

const {
currentDiaIDsToHighlight,
handleOnAtomHover,
handleOnClickAtom,
assignedDiaIDsMerged,
} = useAtomAssignment({ zones, ranges, activeTab, displayerMode });

const floatMoleculeHandler = useCallback(() => {
function floatMoleculeHandler() {
dispatch({
type: FLOAT_MOLECULE_OVER_SPECTRUM,
payload: { id: molecule.id },
});
}, [dispatch, molecule]);
const dragFloatMoleculeHandler = useCallback(
(position: Position) => {
dispatch({
type: CHANGE_FLOAT_MOLECULE_POSITION,
payload: { id: molecule.id, position },
});
},
[dispatch, molecule],
);
}

function dragFloatMoleculeHandler(bounding: Partial<MoleculeBoundingRect>) {
if (
typeof bounding?.width === 'number' &&
typeof bounding?.height === 'number'
) {
const { width, height } = moleculeView.floating.bounding;
bounding.width += width;
bounding.height += height;
}
dispatch({
type: CHANGE_FLOAT_MOLECULE_POSITION,
payload: { id: molecule.id, bounding },
});
}

if (!viewerRef) return null;

return (
<SVGDraggable
key={molecule.id}
width={150}
height={100}
initialPosition={moleculeView.floating.position}
<Rnd
default={moleculeView.floating.bounding}
minWidth={100}
minHeight={100}
dragHandleClassName="handle"
parentElement={viewerRef}
onEnd={dragFloatMoleculeHandler}
enableUserSelectHack={false}
bounds={viewerRef}
style={{ zIndex: 1 }}
className="draggable-molecule"
onResizeStop={(e, dir, eRef, { width, height }) =>
dragFloatMoleculeHandler({ width, height })
}
onDragStop={(e, { x, y }) => {
dragFloatMoleculeHandler({ x, y });
}}
resizeHandleWrapperStyle={{ backgroundColor: 'white' }}
css={style}
>
{(width, height) => (
<foreignObject
width={width}
height={height + 30}
data-replace-float-structure="true"
css={style}
onDoubleClick={() => openMoleculeEditor(molecule)}
>
<ActionsButton onFloatBtnClick={floatMoleculeHandler} />
<OCLnmr
OCL={OCL}
autoCrop
id={`molSVG${index || ''}`}
width={width - 20}
height={height}
molfile={molecule.molfile}
setSelectedAtom={handleOnClickAtom}
atomHighlightColor={
currentDiaIDsToHighlight?.length > 0 ? 'red' : '#FFD700'
}
atomHighlightOpacity={0.35}
highlights={
currentDiaIDsToHighlight?.length > 0
? currentDiaIDsToHighlight
: assignedDiaIDsMerged
}
setHoverAtom={handleOnAtomHover}
setMolfile={(molfile) => {
dispatch({
type: SET_MOLECULE,
payload: {
molfile,
id: molecule.id,
label: molecule.label,
},
});
}}
showAtomNumber={moleculeView.showAtomNumber}
/>
</foreignObject>
)}
</SVGDraggable>
<div
className="content"
onDoubleClick={() => openMoleculeEditor(molecule)}
>
<ActionsButton onFloatBtnClick={floatMoleculeHandler} />
<ResponsiveChart>
{({ width, height }) => {
return (
<OCLnmr
OCL={OCL}
autoCrop
id={`molSVG${index || ''}`}
width={width}
height={height}
molfile={molecule.molfile}
setSelectedAtom={handleOnClickAtom}
atomHighlightColor={
currentDiaIDsToHighlight?.length > 0 ? 'red' : '#FFD700'
}
atomHighlightOpacity={0.35}
highlights={
currentDiaIDsToHighlight?.length > 0
? currentDiaIDsToHighlight
: assignedDiaIDsMerged
}
setHoverAtom={handleOnAtomHover}
setMolfile={(molfile) => {
dispatch({
type: SET_MOLECULE,
payload: {
molfile,
id: molecule.id,
label: molecule.label,
},
});
}}
showAtomNumber={moleculeView.showAtomNumber}
/>
);
}}
</ResponsiveChart>
</div>
</Rnd>
);
}
Expand Up @@ -34,10 +34,10 @@ export function FloatMoleculeStructuresInner(
if (floatingMolecules.length === 0) return null;

return (
<g>
<>
{floatingMolecules
.filter(([, view]) => view.floating.visible)
.map(([id, moleculeView]) => {
.map(([id, moleculeView], index) => {
const molecule = molecules.find((m) => m.id === id);
assert(molecule !== undefined, 'molecule should be defined');
return (
Expand All @@ -50,11 +50,12 @@ export function FloatMoleculeStructuresInner(
displayerMode,
moleculeView,
molecule,
index,
}}
/>
);
})}
</g>
</>
);
}

Expand Down
2 changes: 0 additions & 2 deletions src/component/1d/Chart1D.tsx
@@ -1,4 +1,3 @@
import FloatMoleculeStructures from '../1d-2d/components/FloatMoleculeStructures/index';
import SpectrumInfoBlock from '../1d-2d/components/SpectrumInfoBlock';

import ApodizationLine from './ApodizationLine';
Expand Down Expand Up @@ -49,7 +48,6 @@ function Chart1D({ mode, width, height, margin, displayerKey }) {
<g className="container" style={{ pointerEvents: 'none' }}>
<XAxis showGrid mode={mode} />
</g>
<FloatMoleculeStructures />
</svg>
);
}
Expand Down
2 changes: 0 additions & 2 deletions src/component/2d/Chart2D.tsx
@@ -1,7 +1,6 @@
import { memo } from 'react';

import { Datum1D } from '../../data/types/data1d';
import FloatMoleculeStructures from '../1d-2d/components/FloatMoleculeStructures/index';
import SpectrumInfoBlock from '../1d-2d/components/SpectrumInfoBlock';
import { useChartData } from '../context/ChartContext';
import { Margin } from '../reducer/Reducer';
Expand Down Expand Up @@ -67,7 +66,6 @@ function chart2DInner({
<XAxis />
<YAxis />
</g>
<FloatMoleculeStructures />
</svg>
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/component/NMRium.tsx
Expand Up @@ -28,6 +28,7 @@ import checkModifierKeyActivated from '../data/utilities/checkModifierKeyActivat
import { NMRiumDataReturn } from '../types/NMRiumDataReturn';

import Viewer1D from './1d/Viewer1D';
import FloatMoleculeStructures from './1d-2d/components/FloatMoleculeStructures';
import Viewer2D from './2d/Viewer2D';
import ErrorOverlay from './ErrorOverlay';
import KeysListenerTracker from './EventsTrackers/KeysListenerTracker';
Expand Down Expand Up @@ -355,13 +356,16 @@ function InnerNMRium({
<div css={viewerContainerStyle}>
<KeysListenerTracker />
<div
id="nmrium-viewer"
data-test-id="viewer"
ref={viewerRef}
style={{
width: '100%',
height: '100%',
position: 'relative',
}}
>
<FloatMoleculeStructures />
{displayerMode ===
DISPLAYER_MODE.DM_1D ? (
<Viewer1D emptyText={emptyText} />
Expand All @@ -380,7 +384,7 @@ function InnerNMRium({
style={{
position: 'absolute',
pointerEvents: 'none',
zIndex: 0,
zIndex: 2,
left: 0,
right: 0,
top: 0,
Expand Down
8 changes: 4 additions & 4 deletions src/component/reducer/actions/MoleculeActions.ts
Expand Up @@ -2,9 +2,9 @@ import { Draft } from 'immer';

import { generateSpectra } from '../../../data/PredictionManager';
import { changeSpectraRelativeSum } from '../../../data/data1d/Spectrum1D/SumManager';
import { DRAGGABLE_STRUCTURE_INITIAL_BOUNDING_REACT } from '../../../data/molecules/Molecule';
import * as MoleculeManager from '../../../data/molecules/MoleculeManager';
import { generateColor } from '../../../data/utilities/generateColor';
import { DRAGGABLE_STRUCTURE_INITIAL_POSITION } from '../../1d-2d/components/FloatMoleculeStructures/DraggableStructure';
import nucleusToString from '../../utility/nucleusToString';
import { State } from '../Reducer';
import { DISPLAYER_MODE } from '../core/Constants';
Expand Down Expand Up @@ -107,7 +107,7 @@ function initMoleculeViewProperties(id: string, draft: Draft<State>) {
draft.view.molecules[id] = {
floating: {
visible: false,
position: DRAGGABLE_STRUCTURE_INITIAL_POSITION,
bounding: DRAGGABLE_STRUCTURE_INITIAL_BOUNDING_REACT,
},
showAtomNumber: false,
};
Expand Down Expand Up @@ -137,10 +137,10 @@ function toggleMoleculeAtomsNumbers(draft: Draft<State>, action) {
}
}
function changeFloatMoleculePosition(draft: Draft<State>, action) {
const { id, position } = action.payload;
const { id, bounding } = action.payload;
const molecule = getMoleculeViewObject(id, draft);
if (molecule) {
molecule.floating.position = position;
molecule.floating.bounding = { ...molecule.floating.bounding, ...bounding };
} else {
throw new Error(`Molecule ${id} does not exist`);
}
Expand Down

0 comments on commit 52d16e6

Please sign in to comment.