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.

- 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
  • Loading branch information
rrodionov91 committed Apr 18, 2024
1 parent b0f02b8 commit 7238d24
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 70 deletions.
41 changes: 33 additions & 8 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,7 @@ 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';

class PolymerBond implements BaseTool {
private bondRenderer?: PolymerBondRenderer;
Expand All @@ -40,7 +41,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 @@ -62,7 +63,10 @@ class PolymerBond implements BaseTool {

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 +154,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 +191,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 +213,7 @@ class PolymerBond implements BaseTool {
renderer.monomer,
this.bondRenderer?.polymerBond,
);

this.editor.renderersContainer.markForRecalculateBegin();
this.editor.renderersContainer.update(modelChanges);
}
Expand All @@ -202,11 +223,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 +239,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
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

0 comments on commit 7238d24

Please sign in to comment.