Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/component/1d/peaks/PeakAnnotationsSpreadMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ function PeakAnnotationsSpreadMode(props: PeakAnnotationsSpreadModeProps) {
<ActionsButtonsPopover
targetTagName="g"
buttons={actionsButtons}
positioningStrategy="fixed"
position="top"
direction="row"
{...(isDragActive && { isOpen: true })}
y={y}
offsetY={-20}
offsetXMode="cursor"
autoFlip={false}
>
<g className="peaks">
<g
Expand Down
35 changes: 15 additions & 20 deletions src/component/2d/zones/Signal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { useHighlight, useHighlightData } from '../../highlight/index.js';
import { useActiveSpectrumZonesViewState } from '../../hooks/useActiveSpectrumZonesViewState.js';
import { useScale2DX, useScale2DY } from '../utilities/scale.js';

import SignalCrosshair from './SignalCrosshair.js';

interface SignalProps {
signal: Signal2D;
}
Expand Down Expand Up @@ -52,24 +50,21 @@ function Signal({ signal }: SignalProps) {
return (
<g className="zone-signal">
{showSignals && (
<g>
<SignalCrosshair signal={signal} />
<circle
onMouseEnter={() => {
assignment?.highlight();
highlight.show();
}}
onMouseLeave={() => {
assignment?.clearHighlight();
highlight.hide();
}}
key={signal.id}
cx={scaleX(signal.x.delta || 0)}
cy={scaleY(signal.y.delta || 0)}
r={isHighlighted ? 6 : 4}
fill={isHighlighted ? 'green' : 'darkgreen'}
/>
</g>
<circle
onMouseEnter={() => {
assignment?.highlight();
highlight.show();
}}
onMouseLeave={() => {
assignment?.clearHighlight();
highlight.hide();
}}
key={signal.id}
cx={scaleX(signal.x.delta || 0)}
cy={scaleY(signal.y.delta || 0)}
r={isHighlighted ? 6 : 4}
fill={isHighlighted ? 'green' : 'darkgreen'}
/>
)}
<g className="zone-signal-peak" style={{ pointerEvents: 'none' }}>
{showPeaks &&
Expand Down
4 changes: 1 addition & 3 deletions src/component/2d/zones/SignalCrosshair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface SignalCrosshairProps {
signal: Signal2D;
}

function SignalCrosshair({ signal }: SignalCrosshairProps) {
export function SignalCrosshair({ signal }: SignalCrosshairProps) {
const highlightIDsX = useMemo(() => {
return [buildID(signal.id, 'Crosshair'), buildID(signal.id, 'Crosshair_X')];
}, [signal.id]);
Expand Down Expand Up @@ -39,5 +39,3 @@ function SignalCrosshair({ signal }: SignalCrosshairProps) {
</g>
);
}

export default SignalCrosshair;
37 changes: 21 additions & 16 deletions src/component/2d/zones/Zone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useActiveSpectrumZonesViewState } from '../../hooks/useActiveSpectrumZo
import { useScale2DX, useScale2DY } from '../utilities/scale.js';

import Signal from './Signal.js';
import { SignalCrosshair } from './SignalCrosshair.tsx';

interface ZoneProps {
zoneData: ZoneType;
Expand Down Expand Up @@ -54,21 +55,25 @@ function Zone({ zoneData }: ZoneProps) {
];

return (
<ActionsButtonsPopover
buttons={actionButtons}
targetTagName="g"
{...(assignment && { isOpen: false })}
<g
key={id}
onMouseEnter={() => {
assignmentZone.highlight();
highlightZone.show();
}}
onMouseLeave={() => {
assignmentZone.clearHighlight();
highlightZone.hide();
}}
>
<g
key={id}
onMouseEnter={() => {
assignmentZone.highlight();
highlightZone.show();
}}
onMouseLeave={() => {
assignmentZone.clearHighlight();
highlightZone.hide();
}}
{signals.map((signal) => (
<SignalCrosshair key={signal.id} signal={signal} />
))}

<ActionsButtonsPopover
buttons={actionButtons}
targetTagName="g"
{...(assignment && { isOpen: false })}
>
{showZones && (
<g transform={`translate(${scaleX(x2)},${scaleY(y1)})`}>
Expand All @@ -87,8 +92,8 @@ function Zone({ zoneData }: ZoneProps) {
// eslint-disable-next-line react/no-array-index-key
<Signal key={id + i} signal={_signal} />
))}
</g>
</ActionsButtonsPopover>
</ActionsButtonsPopover>
</g>
);
}

Expand Down
27 changes: 19 additions & 8 deletions src/component/elements/ActionsButtonsPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ export interface ActionsButtonsPopoverProps
offsetX?: number;
offsetY?: number;
offsetYMode?: 'fixed' | 'cursor';
offsetXMode?: 'fixed' | 'cursor';
x?: number;
y?: number;
autoFlip?: boolean;
}

function ActionButton(props: ButtonProps) {
Expand All @@ -80,30 +82,37 @@ export function ActionsButtonsPopover(props: ActionsButtonsPopoverProps) {
space,
direction = 'column',
contentStyle = {},
offsetX = 0,
offsetX: externalOffsetX = 0,
offsetY: externalOffsetY = 0,
x,
y,
offsetYMode = 'fixed',
offsetXMode = 'fixed',
autoFlip = true,
...otherProps
} = props;

const [cursorY, setCursorY] = useState(0);
const [cursor, setCursor] = useState({ x: 0, y: 0 });
const Wrapper = targetTagName as any;

const visibleButtons = buttons.filter(
(button) => isSeparator(button) || button?.visible !== false,
);

const offsetY = offsetYMode === 'fixed' ? externalOffsetY : cursorY;
const offsetY = offsetYMode === 'fixed' ? externalOffsetY : cursor.y;
const offsetX = offsetXMode === 'fixed' ? externalOffsetX : cursor.x;

function handleMouseEnter(event) {
const { clientY, target } = event;
if (!target || offsetYMode !== 'cursor') return;
const targetElementRect = (target as HTMLElement)?.getBoundingClientRect();
const y = clientY - targetElementRect.y;
setCursorY(y);
const { clientX, clientY, currentTarget } = event;
if (!(currentTarget instanceof Element)) return;
const rect = currentTarget.getBoundingClientRect();

setCursor((prev) => ({
x: offsetXMode === 'cursor' ? clientX - rect.left : prev.x,
y: offsetYMode === 'cursor' ? clientY - rect.top : prev.y,
}));
}

return (
<Popover
minimal
Expand Down Expand Up @@ -133,6 +142,8 @@ export function ActionsButtonsPopover(props: ActionsButtonsPopoverProps) {
direction === 'column' ? [offsetY, offsetX] : [offsetX, offsetY],
},
},

flip: { enabled: autoFlip },
}}
content={
<Container style={contentStyle} flexDirection={direction} gap={space}>
Expand Down
Loading