private appendSideConnectionBond()

in packages/ketcher-core/src/application/render/renderers/PolymerBondRenderer/SnakeModePolymerBondRenderer.ts [236:438]


  private appendSideConnectionBond(rootElement, cells: Cell[]) {
    const firstCell = cells[0];
    const firstCellConnection = firstCell.connections.find(
      (connection: Connection): boolean => {
        return connection.polymerBond === this.polymerBond;
      },
    ) as Connection;
    const isVerticalConnection = firstCellConnection.isVertical;
    const isStraightVerticalConnection =
      (cells.length === 2 ||
        cells.reduce(
          (isStraight: boolean, cell: Cell, index: number): boolean => {
            if (!isStraight || index === 0 || index === cells.length - 1) {
              return isStraight;
            }
            return cell.x === firstCell.x && !cell.monomer;
          },
          true,
        )) &&
      isVerticalConnection;
    const isFirstMonomerOfBondInFirstCell = firstCell.node?.monomers.includes(
      this.polymerBond.firstMonomer,
    );
    const isTwoNeighborRowsConnection = cells.every(
      (cell) => cell.y === firstCell.y || cell.y === firstCell.y + 1,
    );
    const startPosition = isFirstMonomerOfBondInFirstCell
      ? this.scaledPosition.startPosition
      : this.scaledPosition.endPosition;
    const endPosition = isFirstMonomerOfBondInFirstCell
      ? this.scaledPosition.endPosition
      : this.scaledPosition.startPosition;
    const xDirection =
      startPosition.x >= (this.sideConnectionBondTurnPoint || endPosition.x)
        ? 180
        : 0;
    let dAttributeForPath = `M ${startPosition.x},${startPosition.y} `;

    const cos = Math.cos((xDirection * Math.PI) / 180);

    let previousConnection: Connection;
    let previousCell: Cell;

    const horizontalPartIntersectionsOffset = firstCellConnection.xOffset;

    const areCellsOnSameRow = cells.every((cell) => {
      return cell.y === firstCell.y;
    });
    const isSecondCellEmpty = cells[1].node === null;

    if (areCellsOnSameRow) {
      dAttributeForPath += `L ${startPosition.x},${
        startPosition.y -
        BOND_END_LENGTH -
        horizontalPartIntersectionsOffset * 3
      } `;
      dAttributeForPath += generateBend(0, -1, cos, -1);
    } else {
      dAttributeForPath += `L ${startPosition.x},${
        startPosition.y +
        BOND_END_LENGTH +
        horizontalPartIntersectionsOffset * 3
      } `;
      if (
        !isStraightVerticalConnection &&
        !isSecondCellEmpty &&
        !isTwoNeighborRowsConnection
      ) {
        dAttributeForPath += generateBend(0, 1, cos, 1);
      }
    }

    if (isVerticalConnection && !isStraightVerticalConnection) {
      dAttributeForPath += this.drawPartOfSideConnection(
        true,
        firstCellConnection,
        firstCell,
        this.sideConnectionBondTurnPoint &&
          startPosition.x < this.sideConnectionBondTurnPoint
          ? 0
          : 180,
      );
    }

    let maxHorizontalOffset = 0;

    cells.forEach((cell: Cell, cellIndex: number): void => {
      const cellConnection = cell.connections.find(
        (connection: Connection): boolean => {
          return connection.polymerBond === this.polymerBond;
        },
      ) as Connection;
      const isLastCell = cellIndex === cells.length - 1;
      const _xDirection = this.sideConnectionBondTurnPoint
        ? endPosition.x < this.sideConnectionBondTurnPoint
          ? 180
          : 0
        : xDirection;
      const maxXOffset = cell.connections.reduce(
        (max: number, connection: Connection): number => {
          return connection.isVertical || max > connection.xOffset
            ? max
            : connection.xOffset;
        },
        0,
      );

      maxHorizontalOffset =
        maxHorizontalOffset > maxXOffset ? maxHorizontalOffset : maxXOffset;

      if (isLastCell) {
        if (isStraightVerticalConnection) {
          return;
        }

        const directionObject =
          cellConnection.direction as ConnectionDirectionOfLastCell;
        const yDirection = isVerticalConnection ? 90 : directionObject.y;
        const sin = Math.sin((yDirection * Math.PI) / 180);
        const cos = Math.cos((_xDirection * Math.PI) / 180);

        if (!areCellsOnSameRow) {
          dAttributeForPath += `V ${
            endPosition.y -
            CELL_HEIGHT / 2 -
            SMOOTH_CORNER_SIZE -
            sin * (cellConnection.yOffset || 0) * 3 -
            (isTwoNeighborRowsConnection
              ? maxHorizontalOffset - cellConnection.xOffset
              : cellConnection.xOffset) *
              3
          } `;
          dAttributeForPath += generateBend(0, sin, cos, 1);
        }
        dAttributeForPath += `H ${endPosition.x - SMOOTH_CORNER_SIZE * cos} `;
        dAttributeForPath += generateBend(cos, 0, cos, 1);
        return;
      }
      // empty cells
      if (cell.node === null) {
        return;
      }

      // other cells
      if (
        previousConnection &&
        previousConnection.direction !== cellConnection.direction
      ) {
        const isHorizontal =
          previousConnection.direction === 0 ||
          previousConnection.direction === 180;

        dAttributeForPath += this.drawPartOfSideConnection(
          isHorizontal,
          previousConnection,
          previousCell,
          // FIXME: Check. Is it correct to use `as ConnectionDirectionInDegrees` here?
          isHorizontal
            ? xDirection
            : (previousConnection.direction as ConnectionDirectionInDegrees),
        );
      }
      previousCell = cell;
      previousConnection = cellConnection;
    });

    dAttributeForPath += `L ${endPosition.x},${endPosition.y} `;

    this.bodyElement = rootElement
      .append('path')
      .attr('class', `${SIDE_CONNECTION_BODY_ELEMENT_CLASS}`)
      .attr('stroke', this.isHydrogenBond ? '#333333' : '#43B5C0')
      .attr('stroke-width', 1)
      .attr('d', dAttributeForPath)
      .attr('fill', 'none')
      .attr('stroke-dasharray', this.isHydrogenBond ? '2' : '0')
      .attr('pointer-events', 'all')
      .attr('data-testid', 'bond')
      .attr('data-bondtype', this.isHydrogenBond ? 'hydrogen' : 'covalent')
      .attr('data-bondid', this.polymerBond.id)
      .attr('data-frommonomerid', this.polymerBond.firstMonomer.id)
      .attr('data-tomonomerid', this.polymerBond.secondMonomer?.id);

    if (!this.isHydrogenBond && this.bodyElement) {
      this.bodyElement
        .attr(
          'data-fromconnectionpoint',
          this.polymerBond.firstMonomer.getAttachmentPointByBond(
            this.polymerBond,
          ) || '',
        )
        .attr(
          'data-toconnectionpoint',
          this.polymerBond.secondMonomer?.getAttachmentPointByBond(
            this.polymerBond,
          ) || '',
        );
    }

    this.path = dAttributeForPath;

    return this.bodyElement;
  }