diff --git a/api/charts.api.md b/api/charts.api.md index ae3330e87f..d2773353e0 100644 --- a/api/charts.api.md +++ b/api/charts.api.md @@ -2005,6 +2005,7 @@ export type TooltipProps = TooltipPortalSettings<'chart'> & { headerFormatter?: TooltipValueFormatter; unit?: string; customTooltip?: CustomTooltip; + stickTo?: Position; }; // @public diff --git a/src/chart_types/xy_chart/crosshair/crosshair_utils.ts b/src/chart_types/xy_chart/crosshair/crosshair_utils.ts index b3a5c1eee0..dcec27b46f 100644 --- a/src/chart_types/xy_chart/crosshair/crosshair_utils.ts +++ b/src/chart_types/xy_chart/crosshair/crosshair_utils.ts @@ -21,7 +21,8 @@ import { TooltipAnchorPosition } from '../../../components/tooltip/types'; import { Line, Rect } from '../../../geoms/types'; import { Scale } from '../../../scales'; import { isContinuousScale } from '../../../scales/types'; -import { Rotation } from '../../../utils/common'; +import { TooltipProps } from '../../../specs/settings'; +import { Position, Rotation } from '../../../utils/common'; import { Dimensions } from '../../../utils/dimensions'; import { Point } from '../../../utils/point'; import { isHorizontalRotation, isVerticalRotation } from '../state/utils/common'; @@ -177,10 +178,25 @@ export function getTooltipAnchorPosition( cursorBandPosition: Line | Rect, cursorPosition: { x: number; y: number }, panel: Dimensions, + stickTo?: TooltipProps['stickTo'], ): TooltipAnchorPosition { const isRotated = isVerticalRotation(chartRotation); - const hPosition = getHorizontalTooltipPosition(cursorPosition.x, cursorBandPosition, panel, offset.left, isRotated); - const vPosition = getVerticalTooltipPosition(cursorPosition.y, cursorBandPosition, panel, offset.top, isRotated); + const hPosition = getHorizontalTooltipPosition( + cursorPosition.x, + cursorBandPosition, + panel, + offset.left, + isRotated, + stickTo, + ); + const vPosition = getVerticalTooltipPosition( + cursorPosition.y, + cursorBandPosition, + panel, + offset.top, + isRotated, + stickTo, + ); return { isRotated, ...vPosition, @@ -194,6 +210,7 @@ function getHorizontalTooltipPosition( panel: Dimensions, globalOffset: number, isRotated: boolean, + stickTo?: TooltipProps['stickTo'], ): { x0?: number; x1: number } { if (!isRotated) { const left = 'x1' in cursorBandPosition ? cursorBandPosition.x1 : cursorBandPosition.x; @@ -203,10 +220,11 @@ function getHorizontalTooltipPosition( x1: left + width + globalOffset, }; } + const x = stickTo === Position.Left ? 0 : stickTo === Position.Right ? panel.width : cursorXPosition; return { // NOTE: x0 set to zero blocks tooltip placement on left when rotated 90 deg // Delete this comment before merging and verifying this doesn't break anything. - x1: panel.left + cursorXPosition + globalOffset, + x1: panel.left + x + globalOffset, }; } @@ -216,15 +234,17 @@ function getVerticalTooltipPosition( panel: Dimensions, globalOffset: number, isRotated: boolean, + stickTo?: TooltipProps['stickTo'], ): { y0: number; y1: number; } { + const y = stickTo === Position.Top ? 0 : stickTo === Position.Bottom ? panel.height : cursorYPosition; if (!isRotated) { - const y = cursorYPosition + panel.top + globalOffset; + const yPos = y + panel.top + globalOffset; return { - y0: y, - y1: y, + y0: yPos, + y1: yPos, }; } const top = 'y1' in cursorBandPosition ? cursorBandPosition.y1 : cursorBandPosition.y; diff --git a/src/chart_types/xy_chart/state/selectors/get_tooltip_position.ts b/src/chart_types/xy_chart/state/selectors/get_tooltip_position.ts index 1a6faaaa5b..4995fedf76 100644 --- a/src/chart_types/xy_chart/state/selectors/get_tooltip_position.ts +++ b/src/chart_types/xy_chart/state/selectors/get_tooltip_position.ts @@ -20,6 +20,7 @@ import createCachedSelector from 're-reselect'; import { TooltipAnchorPosition } from '../../../../components/tooltip/types'; +import { isTooltipType } from '../../../../specs/settings'; import { getChartIdSelector } from '../../../../state/selectors/get_chart_id'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { getTooltipAnchorPosition } from '../../crosshair/crosshair_utils'; @@ -64,6 +65,7 @@ export const getTooltipAnchorPositionSelector = createCachedSelector( cursorBandPosition, projectedPointerPosition, panel, + isTooltipType(settings.tooltip) ? undefined : settings.tooltip.stickTo, ); }, )(getChartIdSelector); diff --git a/src/components/portal/types.ts b/src/components/portal/types.ts index eb6532e4b2..845ecd2465 100644 --- a/src/components/portal/types.ts +++ b/src/components/portal/types.ts @@ -104,7 +104,7 @@ export interface TooltipPortalSettings { boundary?: HTMLElement | B; /** * Boundary element padding. - * Used to reduce extents of boundary placement when magins or paddings are used on boundary + * Used to reduce extents of boundary placement when margins or paddings are used on boundary * * @defaultValue 0 */ diff --git a/src/specs/settings.tsx b/src/specs/settings.tsx index 44ac0599e7..227d6f704b 100644 --- a/src/specs/settings.tsx +++ b/src/specs/settings.tsx @@ -269,6 +269,10 @@ export type TooltipProps = TooltipPortalSettings<'chart'> & { * Render custom tooltip given header and values */ customTooltip?: CustomTooltip; + /** + * Stick the tooltip to a specific position within the current cursor + */ + stickTo?: Position; }; /** diff --git a/stories/area/2_with_time.tsx b/stories/area/2_with_time.tsx index 3f08b82219..a1f2d7b905 100644 --- a/stories/area/2_with_time.tsx +++ b/stories/area/2_with_time.tsx @@ -19,7 +19,7 @@ import React from 'react'; -import { AreaSeries, Axis, Chart, Position, ScaleType, timeFormatter } from '../../src'; +import { AreaSeries, Axis, Chart, Placement, Position, ScaleType, Settings, timeFormatter } from '../../src'; import { KIBANA_METRICS } from '../../src/utils/data_samples/test_dataset_kibana'; import { SB_SOURCE_PANEL } from '../utils/storybook'; @@ -27,6 +27,7 @@ const dateFormatter = timeFormatter('HH:mm'); export const Example = () => ( +