Skip to content

Commit

Permalink
#3899 - Macro: Attachment points do not disappear when hover is remov…
Browse files Browse the repository at this point in the history
…ed from some monomers. (#4482)

- added AttachmentPoint instance binding to it's html elements
- added pointer-events: none by default for all elements of attachment point and explicitly pointer-events: auto to it's hover area
- fixed(reduced) size of attachment point hover area
- fixed case with switching tool by hotkeys

---------

Co-authored-by: Roman Rodionov <roman_rodionov@epam.com>
  • Loading branch information
rrodionov91 and rrodionov91 authored Apr 18, 2024
1 parent bf6d26c commit 06dd9f8
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 74 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 49 additions & 12 deletions packages/ketcher-core/src/application/editor/tools/Bond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { RNABase } from 'domain/entities/RNABase';
import { Phosphate } from 'domain/entities/Phosphate';
import { Coordinates } from '../shared/coordinates';
import { AttachmentPointName } from 'domain/types';
import { AttachmentPoint } from 'domain/AttachmentPoint';
import { Command } from 'domain/entities/Command';

class PolymerBond implements BaseTool {
private bondRenderer?: PolymerBondRenderer;
Expand All @@ -40,7 +42,7 @@ class PolymerBond implements BaseTool {
public mouseDownAttachmentPoint(event) {
const selectedRenderer = event.target.__data__;
if (
selectedRenderer instanceof BaseMonomerRenderer &&
selectedRenderer instanceof AttachmentPoint &&
!selectedRenderer.monomer.isAttachmentPointUsed(event.attachmentPointName)
) {
selectedRenderer.monomer.setChosenFirstAttachmentPoint(
Expand All @@ -49,20 +51,26 @@ class PolymerBond implements BaseTool {
}
}

private removeBond(): void {
private removeBond() {
if (this.bondRenderer) {
const modelChanges =
this.editor.drawingEntitiesManager.cancelPolymerBondCreation(
this.bondRenderer.polymerBond,
);
this.editor.renderersContainer.update(modelChanges);
this.bondRenderer = undefined;

return modelChanges;
} else {
return new Command();
}
}

public mousedown(event) {
const selectedRenderer = event.target.__data__;
if (selectedRenderer instanceof BaseMonomerRenderer) {
if (
selectedRenderer instanceof BaseMonomerRenderer ||
selectedRenderer instanceof AttachmentPoint
) {
const startAttachmentPoint =
selectedRenderer.monomer.startBondAttachmentPoint;

Expand Down Expand Up @@ -150,9 +158,13 @@ class PolymerBond implements BaseTool {
}

public mouseOverAttachmentPoint(event) {
const renderer: BaseMonomerRenderer = event.target.__data__;
const renderer: AttachmentPoint = event.target.__data__;
let modelChanges;

if (renderer.monomer.isAttachmentPointUsed(event.attachmentPointName)) {
return;
}

if (this.bondRenderer) {
// Don't need to do anything if we hover over the first monomer of the bond
if (this.bondRenderer?.polymerBond.firstMonomer === renderer.monomer) {
Expand Down Expand Up @@ -183,7 +195,19 @@ class PolymerBond implements BaseTool {
}

public mouseLeaveMonomer(event) {
const eventToElementData = event.toElement?.__data__;
const eventFromElementData = event.fromElement?.__data__;
if (
eventToElementData instanceof AttachmentPoint &&
eventToElementData.monomer === eventFromElementData.monomer
) {
eventToElementData.monomer.removePotentialBonds();

return;
}

const renderer: BaseMonomerRenderer = event.target.__data__;

if (
renderer !== this.bondRenderer?.polymerBond?.firstMonomer?.renderer &&
!this.isBondConnectionModalOpen
Expand All @@ -193,6 +217,7 @@ class PolymerBond implements BaseTool {
renderer.monomer,
this.bondRenderer?.polymerBond,
);

this.editor.renderersContainer.markForRecalculateBegin();
this.editor.renderersContainer.update(modelChanges);
}
Expand All @@ -202,11 +227,14 @@ class PolymerBond implements BaseTool {
if (this.isBondConnectionModalOpen) {
return;
}
const renderer: BaseMonomerRenderer = event.target.__data__;
if (renderer !== this.bondRenderer?.polymerBond?.firstMonomer?.renderer) {
const attachmentPointRenderer: AttachmentPoint = event.target.__data__;
if (
attachmentPointRenderer.monomer.renderer !==
this.bondRenderer?.polymerBond?.firstMonomer?.renderer
) {
const modelChanges =
this.editor.drawingEntitiesManager.cancelIntentionToFinishBondCreation(
renderer.monomer,
attachmentPointRenderer.monomer,
this.bondRenderer?.polymerBond,
);
this.editor.renderersContainer.markForRecalculateBegin();
Expand All @@ -215,9 +243,10 @@ class PolymerBond implements BaseTool {
}

public mouseUpAttachmentPoint(event) {
const renderer = event.target.__data__;
const renderer = event.target.__data__ as AttachmentPoint;
const isFirstMonomerHovered =
renderer === this.bondRenderer?.polymerBond?.firstMonomer?.renderer;
renderer.monomer.renderer ===
this.bondRenderer?.polymerBond?.firstMonomer?.renderer;

if (this.bondRenderer && !isFirstMonomerHovered) {
const firstMonomer = this.bondRenderer?.polymerBond?.firstMonomer;
Expand Down Expand Up @@ -306,7 +335,10 @@ class PolymerBond implements BaseTool {
if (this.isBondConnectionModalOpen) {
return;
}
this.removeBond();

const modelChanges = this.removeBond();

this.editor.renderersContainer.update(modelChanges);
}

public mouseUpMonomer(event) {
Expand Down Expand Up @@ -414,7 +446,12 @@ class PolymerBond implements BaseTool {
};

public destroy() {
this.removeBond();
const modelChanges = this.removeBond();
modelChanges.merge(
this.editor.drawingEntitiesManager.removeHoverForAllMonomers(),
);

this.editor.renderersContainer.update(modelChanges);
}

private shouldInvokeModal(
Expand Down
114 changes: 56 additions & 58 deletions packages/ketcher-core/src/domain/AttachmentPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,20 @@ export class AttachmentPoint {
};

private rootElement: D3SvgElementSelection<SVGGElement, void>;
private attachmentPoint: D3SvgElementSelection<SVGGElement, void> | null;
private monomer: BaseMonomer;
private attachmentPoint: D3SvgElementSelection<SVGGElement, this> | null;
public monomer: BaseMonomer;
private bodyWidth: number;
private bodyHeight: number;
private attachmentPointName: string;
private attachmentPointName: AttachmentPointName;
private canvasOffset: Coordinates;
private centerOfMonomer: Coordinates;
private element: Selection<SVGGElement, void, HTMLElement, never> | undefined;
private element: Selection<SVGGElement, this, HTMLElement, never> | undefined;
private hoverableArea:
| Selection<SVGGElement, void, HTMLElement, never>
| Selection<SVGGElement, this, HTMLElement, never>
| undefined;

private initialAngle = 0;
private isUsed: boolean;
private fill: string;
private stroke: string;
private isSnake;
private editorEvents: typeof editorEvents;

Expand All @@ -69,25 +67,35 @@ export class AttachmentPoint {
this.editorEvents = editorEvents;
this.attachmentPoint = null;

if (constructorParams.isPotentiallyUsed) {
this.fill = AttachmentPoint.colors.fillPotentially;
this.stroke = AttachmentPoint.colors.strokePotentially;
} else if (constructorParams.isUsed) {
this.fill = AttachmentPoint.colors.fillUsed;
this.stroke = AttachmentPoint.colors.strokeUsed;
this.appendAttachmentPoint();
}

private get fill() {
if (
this.monomer.isAttachmentPointPotentiallyUsed(this.attachmentPointName)
) {
return AttachmentPoint.colors.fillPotentially;
} else if (this.monomer.isAttachmentPointUsed(this.attachmentPointName)) {
return AttachmentPoint.colors.fillUsed;
} else {
this.fill = AttachmentPoint.colors.fill;
this.stroke = AttachmentPoint.colors.stroke;
return AttachmentPoint.colors.fill;
}
}

this.appendAttachmentPoint();
private get stroke() {
if (
this.monomer.isAttachmentPointPotentiallyUsed(this.attachmentPointName)
) {
return AttachmentPoint.colors.strokePotentially;
} else if (this.monomer.isAttachmentPointUsed(this.attachmentPointName)) {
return AttachmentPoint.colors.strokeUsed;
} else {
return AttachmentPoint.colors.stroke;
}
}

public removeAttachmentPoint() {
const remove = () => {
this.element?.remove();
};
setTimeout(remove, 1);
this.element?.remove();
}

private renderAttachmentPointByCoordinates(
Expand All @@ -98,7 +106,10 @@ export class AttachmentPoint {
const fill = this.fill;
const stroke = this.stroke;

this.attachmentPoint = this.rootElement.insert('g', ':first-child');
this.attachmentPoint = this.rootElement
.insert('g', ':first-child')
.data([this])
.style('pointer-events', 'none');

const attachmentPointElement = this.attachmentPoint.append('g');

Expand Down Expand Up @@ -144,16 +155,16 @@ export class AttachmentPoint {
}

const rotation = angleDegrees + 90;
const halfWidth = 20;
const halfWidth = 8;

const areaHeight = Math.sqrt(
(monomerCenter.x - attachmentPointCenter.x) ** 2 +
(monomerCenter.y - attachmentPointCenter.y) ** 2,
);

const points: Coordinates[] = [
{ x: -AttachmentPoint.radius, y: AttachmentPoint.radius },
{ x: AttachmentPoint.radius, y: AttachmentPoint.radius },
{ x: -AttachmentPoint.radius, y: AttachmentPoint.radius + 2 },
{ x: AttachmentPoint.radius, y: AttachmentPoint.radius + 2 },
{
x: halfWidth,
y: -areaHeight + 10,
Expand All @@ -162,7 +173,7 @@ export class AttachmentPoint {
x: -halfWidth,
y: -areaHeight + 10,
},
{ x: -AttachmentPoint.radius, y: AttachmentPoint.radius },
{ x: -AttachmentPoint.radius, y: AttachmentPoint.radius + 2 },
];

const lineFunction = line<Coordinates>()
Expand All @@ -178,6 +189,7 @@ export class AttachmentPoint {
.attr('stroke-width', '1px')
.attr('fill', '#0097A8')
.style('opacity', '0')
.style('pointer-events', 'auto')
.attr(
'transform',
`translate(${attachmentPointCenter.x},${attachmentPointCenter.y})rotate(${rotation})`,
Expand Down Expand Up @@ -206,26 +218,20 @@ export class AttachmentPoint {
public appendAttachmentPoint() {
let angleDegrees;
let angleRadians: number;
const flip =
this.monomer.id ===
this.monomer.attachmentPointsToBonds[this.attachmentPointName]
?.firstMonomer?.id;
const polymerBond =
this.monomer.attachmentPointsToBonds[this.attachmentPointName];
const flip = this.monomer.id === polymerBond?.firstMonomer?.id;
const isAttachmentpointR1 = this.attachmentPointName === 'R1';
if (!this.isUsed) {
if (!polymerBond) {
angleDegrees = this.initialAngle;
} else if (
this.isSnake &&
!this.monomer.attachmentPointsToBonds[
this.attachmentPointName
]?.renderer.isMonomersOnSameHorizontalLine()
!polymerBond?.renderer?.isMonomersOnSameHorizontalLine()
) {
angleRadians = isAttachmentpointR1 ? 0 : Math.PI;
angleDegrees = Vec2.radiansToDegrees(angleRadians);
} else {
angleRadians = this.rotateToAngle(
this.monomer.attachmentPointsToBonds[this.attachmentPointName],
flip,
);
angleRadians = this.rotateToAngle(polymerBond, flip);

angleDegrees = Vec2.radiansToDegrees(angleRadians);
}
Expand Down Expand Up @@ -263,18 +269,11 @@ export class AttachmentPoint {
}

public updateAttachmentPointStyleForHover() {
const isAttachmentPointUsed = this.monomer.isAttachmentPointUsed(
this.attachmentPointName as AttachmentPointName,
);
if (isAttachmentPointUsed) {
this.attachmentPoint
?.select('line')
.style('stroke', AttachmentPoint.colors.fillUsed);
this.attachmentPoint
?.select('circle')
.style('fill', AttachmentPoint.colors.fillUsed)
.attr('stroke', 'white');
}
this.attachmentPoint?.select('line').style('stroke', this.stroke);
this.attachmentPoint
?.select('circle')
.style('fill', this.fill)
.attr('stroke', this.fill === 'white' ? '#0097A8' : 'white');
}

public rotateToAngle(polymerBond: PolymerBond, flip = false) {
Expand Down Expand Up @@ -327,15 +326,14 @@ export class AttachmentPoint {
}

public updateCoords() {
const flip =
this.monomer.id ===
this.monomer.attachmentPointsToBonds[this.attachmentPointName]
?.firstMonomer?.id;

const angleRadians = this.rotateToAngle(
this.monomer.attachmentPointsToBonds[this.attachmentPointName],
flip,
);
const polymerBond =
this.monomer.attachmentPointsToBonds[this.attachmentPointName];

assert(polymerBond);

const flip = this.monomer.id === polymerBond?.firstMonomer?.id;

const angleRadians = this.rotateToAngle(polymerBond, flip);
const angleDegrees = Vec2.radiansToDegrees(angleRadians);

const [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -750,14 +750,11 @@ export class DrawingEntitiesManager {
monomer.turnOnHover();
monomer.turnOnAttachmentPointsVisibility();

if (
monomer.isAttachmentPointUsed(attachmentPointName as AttachmentPointName)
) {
if (monomer.isAttachmentPointUsed(attachmentPointName)) {
const operation = new MonomerHoverOperation(monomer, true);
command.addOperation(operation);
return command;
}

if (attachmentPointName) {
monomer.setPotentialSecondAttachmentPoint(attachmentPointName);
monomer.setPotentialBond(attachmentPointName, bond);
Expand Down Expand Up @@ -1777,6 +1774,22 @@ export class DrawingEntitiesManager {

return command;
}

public removeHoverForAllMonomers() {
const command = new Command();
this.monomers.forEach((monomer) => {
if (!monomer.hovered) {
return;
}

monomer.turnOffHover();
monomer.turnOffAttachmentPointsVisibility();

command.addOperation(new MonomerHoverOperation(monomer, true));
});

return command;
}
}
function getFirstPosition(height: number, lastPosition: Vec2) {
return new Vec2(MONOMER_START_X_POSITION, lastPosition.y + height);
Expand Down

0 comments on commit 06dd9f8

Please sign in to comment.