From d4f4c2bd320bd889bedd2989e5378b76a4791a16 Mon Sep 17 00:00:00 2001 From: Jane Harrison Date: Fri, 29 Sep 2023 18:58:07 +0000 Subject: [PATCH] Tooltip position adjust for scroll on StackedAreaChart --- .../src/components/StackedAreaChart/Chart.tsx | 2 + .../stories/ExternalTooltip.stories.tsx | 40 ++++++++++ .../getAlteredStackedAreaChartPosition.ts | 54 +++++++++++++ ...getAlteredStackedAreaChartPosition.test.ts | 80 +++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx create mode 100644 packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts create mode 100644 packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts diff --git a/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx b/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx index 0cf69b7dd..d40e801dd 100644 --- a/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx +++ b/packages/polaris-viz/src/components/StackedAreaChart/Chart.tsx @@ -62,6 +62,7 @@ import {useStackedData} from './hooks'; import {StackedAreas, Points} from './components'; import {useStackedChartTooltipContent} from './hooks/useStackedChartTooltipContent'; import {yAxisMinMax} from './utilities/yAxisMinMax'; +import {getAlteredStackedAreaChartPosition} from './utilities/getAlteredStackedAreaChartPosition'; import styles from './Chart.scss'; const TOOLTIP_POSITION: TooltipPositionOffset = { @@ -382,6 +383,7 @@ export function Chart({ focusElementDataType={DataType.Point} getMarkup={getTooltipMarkup} getPosition={getTooltipPosition} + getAlteredPosition={getAlteredStackedAreaChartPosition} id={tooltipId} margin={ChartMargin} onIndexChange={(index) => setActivePointIndex(index)} diff --git a/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx b/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx new file mode 100644 index 000000000..9f421a225 --- /dev/null +++ b/packages/polaris-viz/src/components/StackedAreaChart/stories/ExternalTooltip.stories.tsx @@ -0,0 +1,40 @@ +import type {Story} from '@storybook/react'; + +export {META as default} from './meta'; + +import {StackedAreaChart, type StackedAreaChartProps} from '../../../components'; + +import {DEFAULT_DATA, DEFAULT_PROPS} from './data'; + +function Card(args: StackedAreaChartProps) { + return ( +
+ +
+ ); +} + +const Template: Story = (args: StackedAreaChartProps) => { + return ( +
+ +
+
+ ); +} + + + +export const ExternalTooltip: Story = Template.bind({}); + +ExternalTooltip.args = { + ...DEFAULT_PROPS, + data: DEFAULT_DATA, +}; diff --git a/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts b/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts new file mode 100644 index 000000000..b01023770 --- /dev/null +++ b/packages/polaris-viz/src/components/StackedAreaChart/utilities/getAlteredStackedAreaChartPosition.ts @@ -0,0 +1,54 @@ +import type {Dimensions} from '@shopify/polaris-viz-core'; + +import type {TooltipPositionOffset} from '../../TooltipWrapper'; +import type {Margin} from '../../../types'; + +// The space between the cursor and the tooltip +const TOOLTIP_MARGIN = 20; + +export interface AlteredPositionProps { + bandwidth: number; + chartBounds: {x: number; y: number; width: number; height: number}; + currentX: number; + currentY: number; + isPerformanceImpacted: boolean; + margin: Margin; + position: TooltipPositionOffset; + tooltipDimensions: Dimensions; +} + +export interface AlteredPositionReturn { + x: number; + y: number; +} + +export type AlteredPosition = ( + props: AlteredPositionProps, +) => AlteredPositionReturn; + +export function getAlteredStackedAreaChartPosition({ + currentX, + currentY, + chartBounds, + margin, + tooltipDimensions, +}: AlteredPositionProps): AlteredPositionReturn { + const x = Math.min( + Math.max(currentX, TOOLTIP_MARGIN), + chartBounds.width - tooltipDimensions.width - TOOLTIP_MARGIN, + ); + + // Y POSITIONING + // If y is below the chart, adjust the tooltip position to the bottom of the chart + // + + const y = + currentY >= chartBounds.y + chartBounds.height + ? chartBounds.height - + tooltipDimensions.height - + TOOLTIP_MARGIN - + margin.Bottom + : currentY; + + return {x, y}; +} diff --git a/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts b/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts new file mode 100644 index 000000000..c01005e5b --- /dev/null +++ b/packages/polaris-viz/src/components/StackedAreaChart/utilities/tests/getAlteredStackedAreaChartPosition.test.ts @@ -0,0 +1,80 @@ +import type {AlteredPositionProps} from '../../../TooltipWrapper'; +import { + TooltipVerticalOffset, + TooltipHorizontalOffset, +} from '../../../TooltipWrapper'; +import {getAlteredStackedAreaChartPosition} from '../getAlteredStackedAreaChartPosition'; + +const MARGIN = {Top: 0, Left: 0, Right: 0, Bottom: 0}; +const TOOLTIP_MARGIN = 20; + +const BASE_PROPS: AlteredPositionProps = { + isPerformanceImpacted: false, + chartBounds: {height: 100, width: 200, x: 0, y: 100}, + tooltipDimensions: {height: 40, width: 60}, + margin: MARGIN, + bandwidth: 40, + currentX: 20, + currentY: 0, + position: { + horizontal: TooltipHorizontalOffset.Left, + vertical: TooltipVerticalOffset.Center, + }, +}; + +describe('getAlteredStackedAreaChartPosition', () => { + it('returns the original position of y when currentY is within the chart bounds', () => { + const props = { + ...BASE_PROPS, + currentX: 50, + currentY: 50, + }; + + const result = getAlteredStackedAreaChartPosition(props); + + expect(result.x).toBe(50); + expect(result.y).toBe(50); + }); + + it('returns the adjusted position when currentY is greater than chartBounds.y + chartBounds.height', () => { + const props = { + ...BASE_PROPS, + currentY: 300, + }; + + const chartBounds = props.chartBounds; + const tooltipDimensions = props.tooltipDimensions; + const margin = props.margin; + const result = getAlteredStackedAreaChartPosition(props); + + expect(result.x).toBe(20); + + expect(result.y).toBe( + chartBounds.height - + tooltipDimensions.height - + TOOLTIP_MARGIN - + margin.Bottom, + ); + }); + + it('returns the adjusted position when currentY is equal to chartBounds.y + chartBounds.height', () => { + const props = { + ...BASE_PROPS, + currentY: 200, + }; + + const chartBounds = props.chartBounds; + const tooltipDimensions = props.tooltipDimensions; + const margin = props.margin; + const result = getAlteredStackedAreaChartPosition(props); + + expect(result.x).toBe(20); + + expect(result.y).toBe( + chartBounds.height - + tooltipDimensions.height - + TOOLTIP_MARGIN - + margin.Bottom, + ); + }); +});