diff --git a/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx b/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx
deleted file mode 100644
index 337ed3728..000000000
--- a/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { BsArrowsMove } from 'react-icons/bs';
-import { FaTimes } from 'react-icons/fa';
-
-import Button from '../../../elements/Button.js';
-
-export default function ActionsButton({ onFloatBtnClick }) {
- return (
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx b/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx
index 9c53c134c..9d79fa333 100644
--- a/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx
+++ b/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx
@@ -1,7 +1,10 @@
import styled from '@emotion/styled';
import type { Ranges, Zones } from 'nmr-processing';
import OCL from 'openchemlib/full';
+import { useEffect, useState } from 'react';
import { ResponsiveChart } from 'react-d3-utils';
+import { BsArrowsMove } from 'react-icons/bs';
+import { FaTimes } from 'react-icons/fa';
import OCLnmr from 'react-ocl-nmr';
import { Rnd } from 'react-rnd';
@@ -12,14 +15,15 @@ import type {
} from '../../../../data/molecules/Molecule.js';
import { useDispatch } from '../../../context/DispatchContext.js';
import { useGlobal } from '../../../context/GlobalContext.js';
+import { ActionsButtonsPopover } from '../../../elements/ActionsButtonsPopover.js';
+import type { ActionsButtonsPopoverProps } from '../../../elements/ActionsButtonsPopover.js';
import { useHighlightColor } from '../../../hooks/useHighlightColor.js';
+import { useSVGUnitConverter } from '../../../hooks/useSVGUnitConverter.js';
import { useCheckExportStatus } from '../../../hooks/useViewportSize.js';
import { useMoleculeEditor } from '../../../modal/MoleculeStructureEditorModal.js';
import useAtomAssignment from '../../../panels/MoleculesPanel/useAtomAssignment.js';
import type { DisplayerMode } from '../../../reducer/Reducer.js';
-import ActionsButton from './ActionsButton.js';
-
interface DraggableMoleculeProps extends DraggableStructureProps {
width: number;
height: number;
@@ -35,15 +39,9 @@ interface DraggableStructureProps {
molecule: StateMoleculeExtended;
}
-const AUTO_CROP_MARGIN = 30;
-
const ReactRnd = styled(Rnd)`
border: 1px solid transparent;
- button {
- visibility: hidden;
- }
-
.content {
width: 100%;
height: 100%;
@@ -52,10 +50,6 @@ const ReactRnd = styled(Rnd)`
&:hover {
border: 1px solid #ebecf1;
background-color: white;
-
- button {
- visibility: visible;
- }
}
`;
@@ -65,6 +59,15 @@ export function DraggableStructure(props: DraggableStructureProps) {
const isExportProcessStart = useCheckExportStatus();
const dispatch = useDispatch();
const { modal, openMoleculeEditor } = useMoleculeEditor();
+ const { percentToPixel, pixelToPercent } = useSVGUnitConverter();
+ const [bounding, setBounding] = useState(
+ moleculeView.floating.bounding,
+ );
+ const [isMoveActive, setIsMoveActive] = useState(false);
+
+ useEffect(() => {
+ setBounding({ ...moleculeView.floating.bounding });
+ }, [moleculeView.floating.bounding]);
function floatMoleculeHandler() {
dispatch({
@@ -88,42 +91,102 @@ export function DraggableStructure(props: DraggableStructureProps) {
});
}
+ function handleDrag(internalBounding: Pick) {
+ setBounding((prevBounding) => ({
+ ...prevBounding,
+ ...convertPositionToPercent(internalBounding),
+ }));
+ }
+
+ function convertPositionToPercent({
+ x,
+ y,
+ }: Pick) {
+ return { x: pixelToPercent(x, 'x'), y: pixelToPercent(y, 'y') };
+ }
+
if (!viewerRef) return null;
+ const actionsButtons: ActionsButtonsPopoverProps['buttons'] = [
+ {
+ icon: ,
+ intent: 'none',
+ title: 'Move molecule',
+ style: { cursor: 'move' },
+ className: 'handle',
+ },
+ {
+ icon: ,
+ intent: 'danger',
+ title: 'Hide molecule',
+ onClick: floatMoleculeHandler,
+ },
+ ];
+
+ const { x: xInPercent, y: yInPercent, width, height } = bounding;
+
+ const x = percentToPixel(xInPercent, 'x');
+ const y = percentToPixel(yInPercent, 'y');
+
if (isExportProcessStart) {
- const { width, height } = moleculeView.floating.bounding;
- return ;
+ return (
+
+
+
+ );
}
return (
setIsMoveActive(true)}
onResizeStop={(e, dir, eRef, { width, height }) =>
dragFloatMoleculeHandler({ width, height })
}
+ onDrag={(e, { x, y }) => {
+ handleDrag({ x, y });
+ }}
onDragStop={(e, { x, y }) => {
- dragFloatMoleculeHandler({ x, y });
+ dragFloatMoleculeHandler(convertPositionToPercent({ x, y }));
+ setIsMoveActive(false);
}}
resizeHandleWrapperStyle={{ backgroundColor: 'white' }}
>
- openMoleculeEditor(molecule)}
+
-
-
- {({ width, height }) => {
- return ;
- }}
-
-
+ openMoleculeEditor(molecule)}
+ >
+
+ {({ width, height }) => {
+ return ;
+ }}
+
+
+
+
{modal}
);
@@ -154,10 +217,8 @@ function DraggableMolecule(props: DraggableMoleculeProps) {
>`
padding: 5px;
}
`;
-
+interface ActionButtonProps
+ extends Pick<
+ ButtonProps,
+ | 'icon'
+ | 'onClick'
+ | 'intent'
+ | 'disabled'
+ | 'onPointerDown'
+ | 'style'
+ | 'className'
+ > {
+ title?: string;
+ visible?: boolean;
+ css?: Interpolation;
+}
export interface ActionsButtonsPopoverProps
extends Omit {
- buttons: Array<
- Pick<
- ButtonProps,
- 'icon' | 'onClick' | 'intent' | 'disabled' | 'onPointerDown' | 'style'
- > & {
- title?: string;
- visible?: boolean;
- css?: Interpolation;
- }
- >;
+ buttons: ActionButtonProps[];
contentStyle?: CSSProperties;
direction?: 'column' | 'row';
space?: number;
}
+function ActionButton(props: ButtonProps) {
+ return ;
+}
+
export function ActionsButtonsPopover(props: ActionsButtonsPopoverProps) {
const {
buttons,
@@ -60,7 +69,7 @@ export function ActionsButtonsPopover(props: ActionsButtonsPopoverProps) {
{buttons
.filter((button) => button?.visible !== false)
.map(({ title, visible, ...otherProps }, index) => (
-