-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#2216 S-Group pop-up tool tip is positioned so that it overlaps struc…
…ture (#2289) * Change Calculation of the position for InfoPanel component. For template structure calculation do not change at all. For now it calculates according to the green rectangle that appears when user hovering over the element. Function calculateMiddleCoordsForRect calculate middle coord for each side of the rect. After that panel appears relativly to the middle point of side. - created WrapperPositionedRelativeToRectangle component. - moved calculateScrollOffsetX , calculateScrollOffsetY into helpers.ts to reduce code duplication - created calculateMiddleCoordsForRect accepts array of arrays [[1,2], [3,4], [3,4]] => [{ x: 2, y: 3 }, { x: 3, y: 4}] - added wrapperRef on div to get dinamically changed width / height of the element * - fixed issue with selection tool * - fixed eslint error * - fixed comments --------- Co-authored-by: Konstantin Zharich <kostantin_zharich@epam.com>
- Loading branch information
1 parent
a2c8470
commit 3e78f98
Showing
3 changed files
with
169 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
packages/ketcher-react/src/script/ui/views/components/StructEditor/SGroupDataRender.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { useEffect, useRef, useState, FC } from 'react' | ||
import { Vec2, Render, SGroup, Struct } from 'ketcher-core' | ||
import clsx from 'clsx' | ||
import classes from './InfoPanel.module.less' | ||
import { | ||
calculateMiddleCoordsForRect, | ||
calculateScrollOffsetX, | ||
calculateScrollOffsetY | ||
} from './helpers' | ||
|
||
const BAR_PANEL_SIZE = 32 | ||
const LEFT_PADDING_MULTIPLIER = 3 | ||
|
||
function getPanelPositionRelativeToRect( | ||
clientX: number, | ||
clientY: number, | ||
sGroup: SGroup, | ||
render: Render, | ||
width: number, | ||
height: number | ||
): Vec2 | null { | ||
const viewportLeftLimit = BAR_PANEL_SIZE * LEFT_PADDING_MULTIPLIER + width | ||
const viewportBottomLimit = | ||
render?.clientArea?.clientHeight - BAR_PANEL_SIZE - height | ||
const viewportRightLimit = | ||
render?.clientArea?.clientWidth - BAR_PANEL_SIZE - width | ||
|
||
// [['M', 23, 43], ['L', 23, 24]] we should remove first elements => [[23,43], [23,24]] | ||
const rectCoords: Array<Array<number>> = sGroup.hovering.attrs?.path?.map( | ||
(line) => line.slice(1) | ||
) | ||
|
||
const [middleLeftSide, middleBottomSide, middleRightSide, middleTopSide] = | ||
calculateMiddleCoordsForRect(rectCoords) | ||
|
||
if ( | ||
!middleBottomSide?.x || | ||
!middleBottomSide?.y || | ||
!middleTopSide?.y || | ||
!middleLeftSide?.x || | ||
!middleLeftSide?.y || | ||
!middleRightSide?.x || | ||
!middleRightSide?.y | ||
) { | ||
return null | ||
} | ||
|
||
// Default position for panel is in the bottom; | ||
let x = middleBottomSide.x - width / 2 | ||
let y = middleBottomSide.y | ||
|
||
if (clientY > viewportBottomLimit) { | ||
y = middleTopSide.y - height | ||
} | ||
|
||
if (clientX > viewportRightLimit) { | ||
x = middleLeftSide.x - width | ||
y = middleLeftSide.y - height / 2 | ||
} | ||
|
||
if (clientX < viewportLeftLimit) { | ||
x = middleRightSide.x | ||
y = middleRightSide.y - height / 2 | ||
} | ||
|
||
x += calculateScrollOffsetX(render) | ||
y += calculateScrollOffsetY(render) | ||
|
||
return new Vec2(x, y) | ||
} | ||
|
||
interface SGroupDataRenderProps { | ||
clientX: number | ||
clientY: number | ||
render: Render | ||
groupStruct: Struct | ||
sGroup: SGroup | ||
sGroupData: string | null | ||
className?: string | ||
} | ||
|
||
const SGroupDataRender: FC<SGroupDataRenderProps> = (props) => { | ||
const { clientX, clientY, render, className, sGroup, sGroupData } = props | ||
const [wrapperHeight, setWrapperHeight] = useState(0) | ||
const [wrapperWidth, setWrapperWidth] = useState(0) | ||
const wrapperRef = useRef<HTMLDivElement>(null) | ||
|
||
useEffect(() => { | ||
if (wrapperRef.current) { | ||
setWrapperHeight(wrapperRef.current.clientHeight) | ||
setWrapperWidth(wrapperRef.current.clientWidth) | ||
} | ||
}) | ||
|
||
const panelCoordinate = getPanelPositionRelativeToRect( | ||
clientX, | ||
clientY, | ||
sGroup, | ||
render, | ||
wrapperWidth, | ||
wrapperHeight | ||
) | ||
|
||
return panelCoordinate ? ( | ||
<div | ||
ref={wrapperRef} | ||
style={{ left: panelCoordinate.x + 'px', top: panelCoordinate.y + 'px' }} | ||
className={clsx(classes.infoPanel, className)} | ||
> | ||
{sGroupData} | ||
</div> | ||
) : null | ||
} | ||
|
||
export default SGroupDataRender |
41 changes: 41 additions & 0 deletions
41
packages/ketcher-react/src/script/ui/views/components/StructEditor/helpers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Render, Point } from 'ketcher-core' | ||
|
||
const X_COORD_INDEX = 0 | ||
const Y_COORD_INDEX = 1 | ||
|
||
export const calculateMiddleCoordsForRect = ( | ||
rectCoords: Array<Array<number>> | ||
): Array<Point> | [] => { | ||
if (!rectCoords) { | ||
return [] | ||
} | ||
|
||
const middleCoordForRectangleSides: Array<Point> = [] | ||
|
||
const previousPoint: Point = { | ||
x: rectCoords[0][X_COORD_INDEX], | ||
y: rectCoords[0][Y_COORD_INDEX] | ||
} | ||
|
||
for (let i = 1; i < rectCoords.length; i++) { | ||
if (!previousPoint.x || !previousPoint.y) { | ||
return [] | ||
} | ||
|
||
const middleX = (previousPoint.x + rectCoords[i][X_COORD_INDEX]) / 2 | ||
const middleY = (previousPoint.y + rectCoords[i][Y_COORD_INDEX]) / 2 | ||
middleCoordForRectangleSides.push({ x: middleX, y: middleY }) | ||
previousPoint.x = rectCoords[i][X_COORD_INDEX] | ||
previousPoint.y = rectCoords[i][Y_COORD_INDEX] | ||
} | ||
|
||
return middleCoordForRectangleSides | ||
} | ||
|
||
export const calculateScrollOffsetX = (render: Render) => { | ||
return render?.options.offset?.x - render?.clientArea?.scrollLeft | ||
} | ||
|
||
export const calculateScrollOffsetY = (render: Render) => { | ||
return render?.options?.offset?.y - render?.clientArea?.scrollTop | ||
} |