Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2869 - Preview of monomer structures on canvas #3401

Merged
merged 20 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,20 @@ test.describe('Erase Tool', () => {
await bondTwoMonomers(page, peptide3, peptide2);
await bondTwoMonomers(page, peptide3, peptide4);

// Get rid of flakiness because of preview
const coords = [100, 100];
await page.mouse.move(coords[0], coords[1]);

await takeEditorScreenshot(page);

await selectEraseTool(page);

// Delete peptide linked with two other peptides by bonds
await peptide3.click();

// Get rid of flakiness because of preview
await page.mouse.move(coords[0], coords[1]);

await takeEditorScreenshot(page);
});
});
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { test } from '@playwright/test';
import {
clickInTheMiddleOfTheScreen,
moveMouseToTheMiddleOfTheScreen,
selectSingleBondTool,
takePageScreenshot,
waitForPageInit,
} from '@utils';
Expand All @@ -11,12 +13,29 @@ import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
Test case: #3063 - Add e2e tests for Macromolecule editor
*/

test('Select peptide and drag it to canvas', async ({ page }) => {
await waitForPageInit(page);
await turnOnMacromoleculesEditor(page);
test.describe('Peptide', () => {
test.beforeEach(async ({ page }) => {
await waitForPageInit(page);
await turnOnMacromoleculesEditor(page);
});

await page.click(ALANINE);
await clickInTheMiddleOfTheScreen(page);
test.afterEach(async ({ page }) => {
await takePageScreenshot(page);
});

await takePageScreenshot(page);
test('Select peptide and drag it to canvas', async ({ page }) => {
await page.click(ALANINE);
await clickInTheMiddleOfTheScreen(page);
});

test('Add monomer preview on canvas', async ({ page }) => {
/*
Test case: #2869 - Preview of monomer structures on canvas
Description: Add monomer preview on canvas
*/
await page.click(ALANINE);
await clickInTheMiddleOfTheScreen(page);
await selectSingleBondTool(page);
await moveMouseToTheMiddleOfTheScreen(page);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test.describe('Check attachment point rotation', () => {
await waitForPageInit(page);
await turnOnMacromoleculesEditor(page);
});

test('Select monomer and bonds and then hover monomer', async ({ page }) => {
/*
Test case: # - Rotate attachment point to bond
Expand Down Expand Up @@ -72,11 +73,17 @@ test.describe('Check attachment point rotation', () => {
// Hover 1th peptide
await peptide1.hover();

// Get rid of flakiness because of preview
await page.waitForSelector('.polymer-library-preview');

await takePageScreenshot(page);

// Hover 2nd peptide
await peptide2.hover();

// Get rid of flakiness because of preview
await page.waitForSelector('.polymer-library-preview');

await takeEditorScreenshot(page);
});

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@ test.describe('Polymer Bond Tool', () => {
// Select bond tool
await selectSingleBondTool(page);

await takePageScreenshot(page);

// Create bonds between peptides, taking screenshots in middle states
await peptide1.hover();
await page.mouse.down();

await takePageScreenshot(page);
await peptide2.hover();
await page.mouse.up();

// Get rid of preview
const coords = [100, 100];
await page.mouse.move(coords[0], coords[1]);

await takePageScreenshot(page);

await peptide2.hover();
await page.mouse.down();
await peptide3.hover();
await page.mouse.up();
Expand All @@ -60,6 +66,9 @@ test.describe('Polymer Bond Tool', () => {
await page.mouse.down();
await peptide3.hover();
await page.mouse.up();

// Get rid of preview
await page.mouse.move(coords[0], coords[1]);
});

test('Create bond between two chems', async ({ page }) => {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
BUTTON__ADD_TO_PRESETS,
} from '../../../constants/testIdConstants';
import { waitForPageInit } from '@utils/common';
import { takePageScreenshot } from '@utils';
import { moveMouseToTheMiddleOfTheScreen, takePageScreenshot } from '@utils';

/*
Test case: #3063 - Add e2e tests for Macromolecule editor
Expand Down Expand Up @@ -54,7 +54,7 @@ test.describe('Macromolecules custom presets', () => {
base: 'baA___N-benzyl-adenine',
phosphate: 'bP___Boranophosphate',
});

await moveMouseToTheMiddleOfTheScreen(page);
await page.getByTestId(BUTTON__ADD_TO_PRESETS).click();

await takePageScreenshot(page);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ test.describe('Rectangle Selection Tool', () => {
await bondTwoMonomers(page, peptide3, peptide2);
await bondTwoMonomers(page, peptide3, peptide4);

// Get rid of flakiness because of preview
const coords = [100, 100];
await page.mouse.move(coords[0], coords[1]);
await takePageScreenshot(page);

await selectRectangleSelectionTool(page);
Expand All @@ -82,11 +85,16 @@ test.describe('Rectangle Selection Tool', () => {

await selectRectangleArea(page, startX, startY, endX, endY);

// Get rid of flakiness because of preview
await page.mouse.move(coords[0], coords[1]);
await takePageScreenshot(page);

// Erase selected elements
await selectEraseTool(page);

// Get rid of flakiness because of preview
await page.mouse.move(coords[0], coords[1]);

await takePageScreenshot(page);
});

Expand Down Expand Up @@ -124,9 +132,7 @@ test.describe('Rectangle Selection Tool', () => {

// Move selected monomer
await selectRectangleSelectionTool(page);
await page.mouse.move(400, 400);
await dragMouseTo(500, 500, page);
await page.mouse.move(400, 400);
await page.mouse.click(400, 400);
await dragMouseTo(200, 400, page);

await takeEditorScreenshot(page);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/ketcher-core/src/application/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export class CoreEditor {
// this.lastEvent = event;
const conditions = [
eventHandlerName in editorTool,
this.canvas.contains(event.target) || editorTool.isSelectionRunning?.(),
this.canvas.contains(event?.target) || editorTool.isSelectionRunning?.(),
// isContextMenuClosed(editor.contextMenu),
];

Expand Down
2 changes: 2 additions & 0 deletions packages/ketcher-core/src/application/editor/editorEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const editorEvents = {
mouseOverPolymerBond: new Subscription(),
mouseLeavePolymerBond: new Subscription(),
mouseOverMonomer: new Subscription(),
mouseOnMoveMonomer: new Subscription(),
mouseLeaveMonomer: new Subscription(),
mouseOverDrawingEntity: new Subscription(),
mouseLeaveDrawingEntity: new Subscription(),
Expand All @@ -20,6 +21,7 @@ export const renderersEvents: ToolEventHandlerName[] = [
'mouseOverPolymerBond',
'mouseLeavePolymerBond',
'mouseOverMonomer',
'mouseOnMoveMonomer',
'mouseLeaveMonomer',
'mouseOverDrawingEntity',
'mouseLeaveDrawingEntity',
Expand Down
2 changes: 2 additions & 0 deletions packages/ketcher-core/src/application/editor/tools/Tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ interface ToolEventHandler {

mouseOverMonomer?(event: Event): void;

mouseOnMoveMonomer?(event: Event): void;

mouseLeaveMonomer?(event: Event): void;

mouseOverDrawingEntity?(event: Event): void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ export abstract class BaseMonomerRenderer extends BaseRenderer {
this.editorEvents.mouseOverDrawingEntity.dispatch(event);
this.editorEvents.mouseOverMonomer.dispatch(event);
})
.on('mousemove', (event) => {
this.editorEvents.mouseOnMoveMonomer.dispatch(event);
})
.on('mouseleave', (event) => {
this.editorEvents.mouseLeaveDrawingEntity.dispatch(event);
this.editorEvents.mouseLeaveMonomer.dispatch(event);
Expand Down Expand Up @@ -319,5 +322,6 @@ export abstract class BaseMonomerRenderer extends BaseRenderer {
this.rootElement?.remove();
this.rootElement = undefined;
this.removeSelection();
this.editorEvents.mouseLeaveMonomer.dispatch();
}
}
60 changes: 55 additions & 5 deletions packages/ketcher-polymer-editor-react/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
* limitations under the License.
***************************************************************************/
import { Provider } from 'react-redux';
import { useEffect, useRef } from 'react';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { Global, ThemeProvider } from '@emotion/react';
import { createTheme } from '@mui/material/styles';
import { merge } from 'lodash';
import { debounce, merge } from 'lodash';
import { SdfSerializer } from 'ketcher-core';
import monomersData from './data/monomers.sdf';

Expand All @@ -39,6 +39,7 @@ import {
selectEditorActiveTool,
selectEditorBondMode,
selectTool,
showPreview,
selectMode,
} from 'state/common';
import { loadMonomerLibrary } from 'state/library';
Expand Down Expand Up @@ -69,6 +70,8 @@ import {
PhosphateAvatar,
RNABaseAvatar,
} from 'components/shared/monomerOnCanvas';
import { calculatePreviewPosition } from 'helpers';
import StyledPreview from 'components/shared/MonomerPreview';

const muiTheme = createTheme(muiOverrides);

Expand Down Expand Up @@ -112,6 +115,7 @@ function Editor({ theme }: EditorProps) {
const canvasRef = useRef<SVGSVGElement>(null);
const errorTooltipText = useAppSelector(selectErrorTooltipText);
const editor = useAppSelector(selectEditor);
const activeTool = useAppSelector(selectEditorActiveTool);
useEffect(() => {
dispatch(createEditor({ theme, canvas: canvasRef.current }));
const serializer = new SdfSerializer();
Expand All @@ -123,6 +127,16 @@ function Editor({ theme }: EditorProps) {
};
}, [dispatch]);

const dispatchShowPreview = useCallback(
(payload) => dispatch(showPreview(payload)),
[dispatch],
);

const debouncedShowPreview = useMemo(
() => debounce((p) => dispatchShowPreview(p), 500),
[dispatchShowPreview],
);

useEffect(() => {
if (editor) {
editor.events.error.add((errorText) =>
Expand All @@ -133,6 +147,44 @@ function Editor({ theme }: EditorProps) {
}
}, [editor]);

useEffect(() => {
editor?.events.mouseOverMonomer.add((e) => {
handleOpenPreview(e);
});
editor?.events.mouseLeaveMonomer.add(() => {
handleClosePreview();
});
editor?.events.mouseOnMoveMonomer.add((e) => {
handleClosePreview();
handleOpenPreview(e);
});
}, [editor, activeTool]);

const handleOpenPreview = useCallback(
(e) => {
const tools = ['erase', 'select-rectangle', 'bond-single'];
if (!tools.includes(activeTool)) {
handleClosePreview();
return;
}
const monomer = e.target.__data__.monomer.monomerItem;

const cardCoordinates = e.target.getBoundingClientRect();
const top = calculatePreviewPosition(monomer, cardCoordinates);
const previewStyle = {
top,
left: `${cardCoordinates.left + cardCoordinates.width / 2}px`,
};
debouncedShowPreview({ monomer, style: previewStyle });
},
[activeTool],
);

const handleClosePreview = () => {
debouncedShowPreview.cancel();
dispatch(showPreview(undefined));
};

const handleCloseErrorTooltip = () => {
dispatch(closeErrorTooltip());
};
Expand Down Expand Up @@ -192,11 +244,9 @@ function Editor({ theme }: EditorProps) {
<MonomerLibrary />
</Layout.Right>
</Layout>

<FullscreenButton />

<StyledPreview className="polymer-library-preview" />
<ModalContainer />

<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={Boolean(errorTooltipText)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const MonomerLibraryContainer = styled.div(({ theme }) => ({
boxShadow: '0px 2px 5px rgba(103, 104, 132, 0.15)',
display: 'flex',
flexDirection: 'column',
position: 'relative',

'&.hidden': {
visibility: 'hidden',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ const MonomerGroup = ({
monomer: MonomerItemType,
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
) => {
handleItemMouseLeave();
if (preview.monomer || !e.currentTarget) {
return;
}
const cardCoordinates = e.currentTarget.getBoundingClientRect();
const previewStyle = calculatePreviewPosition(monomer, cardCoordinates);
debouncedShowPreview({ monomer, style: previewStyle });
const style = { top: previewStyle, right: '-88px' };
debouncedShowPreview({ monomer, style });
};

const selectMonomer = (monomer: MonomerItemType) => {
Expand Down
Loading
Loading