in packages/ketcher-core/src/application/render/renderers/BondRenderer.ts [244:376]
getSelectionPoints() {
// please refer to: ketcher-core/docs/data/hover_selection_1.png
const editor = CoreEditor.provideEditorInstance();
const viewModel = editor.viewModel;
const halfEdges = viewModel.bondsToHalfEdges.get(this.bond);
const firstHalfEdge = halfEdges?.[0];
const secondHalfEdge = halfEdges?.[1];
const bond: Bond = this.bond;
const bondSpacingInPx = 6;
const stereoBondWidth = 6;
const regularSelectionThikness = bondSpacingInPx + BOND_WIDTH;
if (!firstHalfEdge || !secondHalfEdge) {
KetcherLogger.warn(
'Failed to draw selection for bond. There is no no half edges.',
);
return [];
}
// get half-bond positions, this is where the actual bond
// image on the screen is drawn, it may be different e.g. if the
// bond is connected to an atom with a label as opposed
// to when it is connected to a Carbon atom w/o a label
// please refer to: ketcher-core/docs/data/hover_selection_2.png
let halfEdgeStart = Coordinates.modelToCanvas(firstHalfEdge.position);
let halfEdgeEnd = Coordinates.modelToCanvas(secondHalfEdge.position);
halfEdgeStart = this.shiftPositionIfAtomLabelVisible(
halfEdgeStart,
this.bond.firstAtom,
firstHalfEdge,
);
halfEdgeEnd = this.shiftPositionIfAtomLabelVisible(
halfEdgeEnd,
this.bond.secondAtom,
secondHalfEdge,
);
const isStereoBond = bond.stereo !== 0 && bond.stereo !== 3;
const addPadding = isStereoBond ? 0 : -2;
// find the points on the line where we will be drawing the curves
const contourStart = Vec2.getLinePoint(
halfEdgeEnd,
halfEdgeStart,
addPadding,
);
const contourEnd = Vec2.getLinePoint(
halfEdgeStart,
halfEdgeEnd,
addPadding,
);
const stereoBondStartHeightCoef = 0.5;
const bondPadding = 0.5;
const addStart = isStereoBond
? stereoBondWidth * stereoBondStartHeightCoef
: regularSelectionThikness + bondPadding;
const stereoBondEndHeightCoef = 1;
const addEnd = isStereoBond
? stereoBondWidth +
(regularSelectionThikness * stereoBondEndHeightCoef) / stereoBondWidth
: regularSelectionThikness + bondPadding;
const contourPaddedStart = Vec2.getLinePoint(
contourStart,
contourEnd,
addEnd,
);
const contourPaddedEnd = Vec2.getLinePoint(
contourEnd,
contourStart,
addStart,
);
// we need four points for each bezier curve
// and two for each line that together form the selection contour
// the padded values are for the curve points and the rest of
// the values are for drawing the lines
// please refer to: ketcher-core/docs/data/hover_selection_3.png
const startPoint = contourStart.add(new Vec2(addEnd, 0));
const endPoint = contourEnd.add(new Vec2(addStart, 0));
const padStartPoint = contourPaddedStart.add(new Vec2(addEnd, 0));
const padEndPoint = contourPaddedEnd.add(new Vec2(addStart, 0));
const angle =
(Math.atan2(firstHalfEdge.direction.y, firstHalfEdge.direction.x) * 180) /
Math.PI;
// rotate the points +/-90 degrees to find the
// perpendicular points that will be used for actual drawing
// of selection contour on canvas
const startTop = startPoint.rotateAroundOrigin(
angle + 90,
new Vec2(contourStart.x, contourStart.y),
);
const startBottom = startPoint.rotateAroundOrigin(
angle - 90,
new Vec2(contourStart.x, contourStart.y),
);
const startPadTop = padStartPoint.rotateAroundOrigin(
angle + 90,
contourPaddedStart,
);
const startPadBottom = padStartPoint.rotateAroundOrigin(
angle - 90,
contourPaddedStart,
);
const endTop = endPoint.rotateAroundOrigin(angle + 90, contourEnd);
const endBottom = endPoint.rotateAroundOrigin(angle - 90, contourEnd);
const endPadTop = padEndPoint.rotateAroundOrigin(
angle + 90,
contourPaddedEnd,
);
const endPadBottom = padEndPoint.rotateAroundOrigin(
angle - 90,
contourPaddedEnd,
);
return [
startPadTop,
startTop,
endTop,
endPadTop,
endPadBottom,
endBottom,
startPadBottom,
startBottom,
];
}