diff --git a/packages/osd-charts/api/charts.api.md b/packages/osd-charts/api/charts.api.md index 93f031283913..be941bc314f6 100644 --- a/packages/osd-charts/api/charts.api.md +++ b/packages/osd-charts/api/charts.api.md @@ -138,7 +138,7 @@ export interface AxisSpec extends Spec { // (undocumented) specType: typeof SpecTypes.Axis; style?: RecursivePartial>; - tickFormat: TickFormatter; + tickFormat?: TickFormatter; ticks?: number; title?: string; } @@ -1262,6 +1262,7 @@ export interface SeriesSpec extends Spec { sortIndex?: number; // (undocumented) specType: typeof SpecTypes.Series; + tickFormat?: TickFormatter; useDefaultGroupDomain?: boolean; // Warning: (ae-forgotten-export) The symbol "AccessorFormat" needs to be exported by the entry point index.d.ts y0AccessorFormat?: AccessorFormat; diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-axes-different-tooltip-formatter-visually-looks-correct-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-axes-different-tooltip-formatter-visually-looks-correct-1-snap.png new file mode 100644 index 000000000000..9077e825b614 Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-axes-different-tooltip-formatter-visually-looks-correct-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-all-custom-tick-formatters-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-all-custom-tick-formatters-1-snap.png new file mode 100644 index 000000000000..0748b824220b Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-all-custom-tick-formatters-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-default-tick-formatter-with-no-axis-tick-formatter-nor-series-tick-formatter-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-default-tick-formatter-with-no-axis-tick-formatter-nor-series-tick-formatter-1-snap.png new file mode 100644 index 000000000000..d77d1b0cb659 Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-default-tick-formatter-with-no-axis-tick-formatter-nor-series-tick-formatter-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-1-snap.png new file mode 100644 index 000000000000..0748b824220b Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-missing-series-tick-formatter-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-missing-series-tick-formatter-1-snap.png new file mode 100644 index 000000000000..f96564b5a066 Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-should-use-series-tick-formatter-with-no-axis-tick-formatter-missing-series-tick-formatter-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-show-synced-tooltips-1-snap.png b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-show-synced-tooltips-1-snap.png new file mode 100644 index 000000000000..0748b824220b Binary files /dev/null and b/packages/osd-charts/integration/tests/__image_snapshots__/interactions-test-ts-interactions-tooltip-formatting-show-synced-tooltips-1-snap.png differ diff --git a/packages/osd-charts/integration/tests/interactions.test.ts b/packages/osd-charts/integration/tests/interactions.test.ts index b32e3b0986f9..fbc8368e2b76 100644 --- a/packages/osd-charts/integration/tests/interactions.test.ts +++ b/packages/osd-charts/integration/tests/interactions.test.ts @@ -228,4 +228,34 @@ describe('Interactions', () => { ); }); }); + + describe('Tooltip formatting', () => { + it('should use all custom tick formatters', async () => { + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/axes--different-tooltip-formatter&knob-Show%20legend=true&knob-Disable%20Y%20Axis%20tickFormat=&knob-Y%20Axis%20value%20format=0[.]0&knob-Y%20Axis%20unit=pets&knob-Disable%20dog%20line%20tickFormat=&knob-Dog%20line%20unit=dogs&knob-Disable%20cat%20line%20tickFormat=&knob-Cat%20line%20unit=cats', + { left: 280, top: 80 }, + ); + }); + + it('should use series tick formatter with no axis tick formatter', async () => { + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/axes--different-tooltip-formatter&knob-Show%20legend=true&knob-Disable%20Y%20Axis%20tickFormat=&knob-Y%20Axis%20value%20format=0[.]0&knob-Y%20Axis%20unit=pets&knob-Disable%20dog%20line%20tickFormat=&knob-Dog%20line%20unit=dogs&knob-Disable%20cat%20line%20tickFormat=&knob-Cat%20line%20unit=cats', + { left: 280, top: 80 }, + ); + }); + + it('should use series tick formatter with no axis tick formatter, missing series tick formatter', async () => { + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/axes--different-tooltip-formatter&knob-Show%20legend=true&knob-Disable%20Y%20Axis%20tickFormat=true&knob-Y%20Axis%20value%20format=0[.]0&knob-Y%20Axis%20unit=pets&knob-Disable%20dog%20line%20tickFormat=true&knob-Dog%20line%20unit=dogs&knob-Disable%20cat%20line%20tickFormat=&knob-Cat%20line%20unit=cats', + { left: 280, top: 80 }, + ); + }); + + it('should use default tick formatter with no axis tick formatter, nor series tick formatter', async () => { + await common.expectChartWithMouseAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/axes--different-tooltip-formatter&knob-Show%20legend=true&knob-Disable%20Y%20Axis%20tickFormat=true&knob-Y%20Axis%20value%20format=0[.]0&knob-Y%20Axis%20unit=pets&knob-Disable%20dog%20line%20tickFormat=true&knob-Dog%20line%20unit=dogs&knob-Disable%20cat%20line%20tickFormat=true&knob-Cat%20line%20unit=cats', + { left: 280, top: 80 }, + ); + }); + }); }); diff --git a/packages/osd-charts/src/chart_types/xy_chart/legend/legend.ts b/packages/osd-charts/src/chart_types/xy_chart/legend/legend.ts index 30a1b53942c1..d630edc48ea5 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/legend/legend.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/legend/legend.ts @@ -19,10 +19,11 @@ import { LegendItem } from '../../../commons/legend'; import { SeriesKey, SeriesIdentifier } from '../../../commons/series_id'; -import { identity, Color } from '../../../utils/commons'; +import { Color } from '../../../utils/commons'; import { BandedAccessorType } from '../../../utils/geometry'; import { getAxesSpecForSpecId, getSpecsById } from '../state/utils/spec'; import { Y0_ACCESSOR_POSTFIX, Y1_ACCESSOR_POSTFIX } from '../tooltip/tooltip'; +import { defaultTickFormatter } from '../utils/axis_utils'; import { SeriesCollectionValue, getSeriesIndex, @@ -66,6 +67,7 @@ export function computeLegend( ): LegendItem[] { const legendItems: LegendItem[] = []; const sortedCollection = getSortedDataSeriesColorsValuesMap(seriesCollection); + const fallbackTickFormatter = specs.find(({ tickFormat }) => tickFormat)?.tickFormat ?? defaultTickFormatter; sortedCollection.forEach((series, key) => { const { banded, lastValue, seriesIdentifier } = series; @@ -83,7 +85,7 @@ export function computeLegend( // Use this to get axis spec w/ tick formatter const { yAxis } = getAxesSpecForSpecId(axesSpecs, spec.groupId); - const formatter = yAxis ? yAxis.tickFormat : identity; + const formatter = yAxis?.tickFormat ?? fallbackTickFormatter; const { hideInLegend } = spec; legendItems.push({ diff --git a/packages/osd-charts/src/chart_types/xy_chart/specs/axis.tsx b/packages/osd-charts/src/chart_types/xy_chart/specs/axis.tsx index ee224dbca740..5ab2716c8d4f 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/specs/axis.tsx +++ b/packages/osd-charts/src/chart_types/xy_chart/specs/axis.tsx @@ -33,15 +33,13 @@ const defaultProps = { showOverlappingTicks: false, showOverlappingLabels: false, position: Position.Left, - tickFormat: (tick: any) => `${tick}`, }; type SpecRequired = Pick; type SpecOptionals = Partial>; export const Axis: React.FunctionComponent = getConnect()( - specComponentFactory< - AxisSpec, - 'groupId' | 'hide' | 'showOverlappingTicks' | 'showOverlappingLabels' | 'position' | 'tickFormat' - >(defaultProps), + specComponentFactory( + defaultProps, + ), ); diff --git a/packages/osd-charts/src/chart_types/xy_chart/state/chart_state.timescales.test.ts b/packages/osd-charts/src/chart_types/xy_chart/state/chart_state.timescales.test.ts index eca86a8c02fb..6143d6d9cea7 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/state/chart_state.timescales.test.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/state/chart_state.timescales.test.ts @@ -91,18 +91,18 @@ describe('Render chart', () => { store.dispatch(onPointerMove({ x: 15, y: 10 }, 0)); // check first valid tooltip let tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(day1); - expect(tooltip.values[0].value).toBe(10); + expect(tooltip.header?.value).toBe(`${day1}`); + expect(tooltip.values[0].value).toBe(`${10}`); store.dispatch(onPointerMove({ x: 35, y: 10 }, 1)); // check second valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(day2); - expect(tooltip.values[0].value).toBe(22); + expect(tooltip.header?.value).toBe(`${day2}`); + expect(tooltip.values[0].value).toBe(`${22}`); store.dispatch(onPointerMove({ x: 76, y: 10 }, 2)); // check third valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(day3); - expect(tooltip.values[0].value).toBe(6); + expect(tooltip.header?.value).toBe(`${day3}`); + expect(tooltip.values[0].value).toBe(`${6}`); }); }); describe('line, utc-time, 5m interval', () => { @@ -159,18 +159,18 @@ describe('Render chart', () => { store.dispatch(onPointerMove({ x: 15, y: 10 }, 0)); // check first valid tooltip let tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date1); - expect(tooltip.values[0].value).toBe(10); + expect(tooltip.header?.value).toBe(`${date1}`); + expect(tooltip.values[0].value).toBe(`${10}`); store.dispatch(onPointerMove({ x: 35, y: 10 }, 1)); // check second valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date2); - expect(tooltip.values[0].value).toBe(22); + expect(tooltip.header?.value).toBe(`${date2}`); + expect(tooltip.values[0].value).toBe(`${22}`); store.dispatch(onPointerMove({ x: 76, y: 10 }, 2)); // check third valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date3); - expect(tooltip.values[0].value).toBe(6); + expect(tooltip.header?.value).toBe(`${date3}`); + expect(tooltip.values[0].value).toBe(`${6}`); }); }); describe('line, non utc-time, 5m + 1s interval', () => { @@ -245,18 +245,18 @@ describe('Render chart', () => { store.dispatch(onPointerMove({ x: 15, y: 10 }, 0)); // check first valid tooltip let tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date1); - expect(tooltip.values[0].value).toBe(10); + expect(tooltip.header?.value).toBe(`${date1}`); + expect(tooltip.values[0].value).toBe(`${10}`); store.dispatch(onPointerMove({ x: 35, y: 10 }, 1)); // check second valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date2); - expect(tooltip.values[0].value).toBe(22); + expect(tooltip.header?.value).toBe(`${date2}`); + expect(tooltip.values[0].value).toBe(`${22}`); store.dispatch(onPointerMove({ x: 76, y: 10 }, 2)); // check third valid tooltip tooltip = getTooltipInfoSelector(store.getState()); expect(tooltip.values.length).toBe(1); - expect(tooltip.header?.value).toBe(date3); - expect(tooltip.values[0].value).toBe(6); + expect(tooltip.header?.value).toBe(`${date3}`); + expect(tooltip.values[0].value).toBe(`${6}`); }); }); }); diff --git a/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts b/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts index d901f82290f8..1a1b78302e4f 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_ticks_dimensions.ts @@ -24,11 +24,16 @@ import { getChartThemeSelector } from '../../../../state/selectors/get_chart_the import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { CanvasTextBBoxCalculator } from '../../../../utils/bbox/canvas_text_bbox_calculator'; import { AxisId } from '../../../../utils/ids'; -import { computeAxisTicksDimensions, AxisTicksDimensions, isDuplicateAxis } from '../../utils/axis_utils'; +import { + computeAxisTicksDimensions, + AxisTicksDimensions, + isDuplicateAxis, + defaultTickFormatter, +} from '../../utils/axis_utils'; import { computeSeriesDomainsSelector } from './compute_series_domains'; import { countBarsInClusterSelector } from './count_bars_in_cluster'; import { getBarPaddingsSelector } from './get_bar_paddings'; -import { getAxisSpecsSelector } from './get_specs'; +import { getAxisSpecsSelector, getSeriesSpecsSelector } from './get_specs'; import { isHistogramModeEnabledSelector } from './is_histogram_mode_enabled'; /** @internal */ @@ -41,6 +46,7 @@ export const computeAxisTicksDimensionsSelector = createCachedSelector( getSettingsSpecSelector, computeSeriesDomainsSelector, countBarsInClusterSelector, + getSeriesSpecsSelector, ], ( barsPadding, @@ -50,9 +56,10 @@ export const computeAxisTicksDimensionsSelector = createCachedSelector( settingsSpec, seriesDomainsAndData, totalBarsInCluster, + seriesSpecs, ): Map => { const { xDomain, yDomain } = seriesDomainsAndData; - + const fallBackTickFormatter = seriesSpecs.find(({ tickFormat }) => tickFormat)?.tickFormat ?? defaultTickFormatter; const bboxCalculator = new CanvasTextBBoxCalculator(); const axesTicksDimensions: Map = new Map(); axesSpecs.forEach((axisSpec) => { @@ -65,6 +72,7 @@ export const computeAxisTicksDimensionsSelector = createCachedSelector( bboxCalculator, settingsSpec.rotation, chartTheme.axes, + fallBackTickFormatter, barsPadding, isHistogramMode, ); diff --git a/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_visible_ticks.ts b/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_visible_ticks.ts index 0e4c6496e38a..8e764b03866b 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_visible_ticks.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/state/selectors/compute_axis_visible_ticks.ts @@ -24,14 +24,14 @@ import { getChartThemeSelector } from '../../../../state/selectors/get_chart_the import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { Dimensions } from '../../../../utils/dimensions'; import { AxisId } from '../../../../utils/ids'; -import { getAxisTicksPositions, AxisTick, AxisLinePosition } from '../../utils/axis_utils'; +import { getAxisTicksPositions, AxisTick, AxisLinePosition, defaultTickFormatter } from '../../utils/axis_utils'; import { computeAxisTicksDimensionsSelector } from './compute_axis_ticks_dimensions'; import { computeChartDimensionsSelector } from './compute_chart_dimensions'; import { computeSeriesDomainsSelector } from './compute_series_domains'; import { countBarsInClusterSelector } from './count_bars_in_cluster'; import { getAxesStylesSelector } from './get_axis_styles'; import { getBarPaddingsSelector } from './get_bar_paddings'; -import { getAxisSpecsSelector } from './get_specs'; +import { getAxisSpecsSelector, getSeriesSpecsSelector } from './get_specs'; import { isHistogramModeEnabledSelector } from './is_histogram_mode_enabled'; /** @internal */ @@ -54,6 +54,7 @@ export const computeAxisVisibleTicksSelector = createCachedSelector( countBarsInClusterSelector, isHistogramModeEnabledSelector, getBarPaddingsSelector, + getSeriesSpecsSelector, ], ( chartDimensions, @@ -66,7 +67,9 @@ export const computeAxisVisibleTicksSelector = createCachedSelector( totalBarsInCluster, isHistogramMode, barsPadding, + seriesSpecs, ): AxisVisibleTicks => { + const fallBackTickFormatter = seriesSpecs.find(({ tickFormat }) => tickFormat)?.tickFormat ?? defaultTickFormatter; const { xDomain, yDomain } = seriesDomainsAndData; return getAxisTicksPositions( chartDimensions, @@ -79,6 +82,7 @@ export const computeAxisVisibleTicksSelector = createCachedSelector( yDomain, totalBarsInCluster, isHistogramMode, + fallBackTickFormatter, barsPadding, ); }, diff --git a/packages/osd-charts/src/chart_types/xy_chart/state/utils/utils.ts b/packages/osd-charts/src/chart_types/xy_chart/state/utils/utils.ts index d31ce8a4b5b7..69ae6c137b8e 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/state/utils/utils.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/state/utils/utils.ts @@ -20,7 +20,7 @@ import { SeriesKey, SeriesIdentifier } from '../../../../commons/series_id'; import { Scale } from '../../../../scales'; import { ScaleType } from '../../../../scales/constants'; -import { identity, mergePartial, Rotation, Color, isUniqueArray } from '../../../../utils/commons'; +import { mergePartial, Rotation, Color, isUniqueArray } from '../../../../utils/commons'; import { CurveType } from '../../../../utils/curves'; import { Dimensions } from '../../../../utils/dimensions'; import { Domain } from '../../../../utils/domain'; @@ -31,6 +31,7 @@ import { XDomain, YDomain } from '../../domains/types'; import { mergeXDomain } from '../../domains/x_domain'; import { mergeYDomain } from '../../domains/y_domain'; import { renderArea, renderBars, renderLine, renderBubble, isDatumFilled } from '../../rendering/rendering'; +import { defaultTickFormatter } from '../../utils/axis_utils'; import { fillSeries } from '../../utils/fill_series'; import { IndexedGeometryMap } from '../../utils/indexed_geometry_map'; import { computeXScale, computeYScales, countBarsInCluster } from '../../utils/scales'; @@ -483,6 +484,7 @@ function renderGeometries( const bubbles: BubbleGeometry[] = []; const indexedGeometryMap = new IndexedGeometryMap(); const isMixedChart = isUniqueArray(seriesSpecs, ({ seriesType }) => seriesType) && seriesSpecs.length > 1; + const fallBackTickFormatter = seriesSpecs.find(({ tickFormat }) => tickFormat)?.tickFormat ?? defaultTickFormatter; const geometriesCounts: GeometriesCounts = { points: 0, bars: 0, @@ -510,7 +512,7 @@ function renderGeometries( }); const { yAxis } = getAxesSpecForSpecId(axesSpecs, spec.groupId); - const valueFormatter = yAxis && yAxis.tickFormat ? yAxis.tickFormat : identity; + const valueFormatter = yAxis?.tickFormat ?? fallBackTickFormatter; const displayValueSettings = spec.displayValueSettings ? { valueFormatter, ...spec.displayValueSettings } diff --git a/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.test.ts b/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.test.ts index c69e0ad81cde..26f6af854722 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.test.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.test.ts @@ -23,7 +23,7 @@ import { SpecTypes } from '../../../specs/constants'; import { Position, RecursivePartial } from '../../../utils/commons'; import { BarGeometry } from '../../../utils/geometry'; import { AxisStyle } from '../../../utils/themes/theme'; -import { AxisSpec, BarSeriesSpec, SeriesTypes } from '../utils/specs'; +import { AxisSpec, BarSeriesSpec, SeriesTypes, TickFormatter } from '../utils/specs'; import { formatTooltip } from './tooltip'; const style: RecursivePartial = { @@ -274,4 +274,59 @@ describe('Tooltip formatting', () => { tooltipValue = formatTooltip(geometry, SPEC_1, true, true, false, YAXIS_SPEC); expect(tooltipValue.isHighlighted).toBe(false); }); + + it('should format ticks with custom formatter from spec', () => { + const axisTickFormatter: TickFormatter = (v) => `${v} axis`; + const tickFormatter: TickFormatter = (v) => `${v} spec`; + const axisSpec: AxisSpec = { + ...YAXIS_SPEC, + tickFormat: axisTickFormatter, + }; + const spec: BarSeriesSpec = { + ...SPEC_1, + tickFormat: tickFormatter, + }; + const tooltipValue = formatTooltip(indexedGeometry, spec, false, false, false, axisSpec); + expect(tooltipValue.value).toBe('10 spec'); + }); + + it('should format ticks with custom formatter from axis', () => { + const axisTickFormatter: TickFormatter = (v) => `${v} axis`; + const axisSpec: AxisSpec = { + ...YAXIS_SPEC, + tickFormat: axisTickFormatter, + }; + const tooltipValue = formatTooltip(indexedGeometry, SPEC_1, false, false, false, axisSpec); + expect(tooltipValue.value).toBe('10 axis'); + }); + + it('should format ticks with default formatter', () => { + const tooltipValue = formatTooltip(indexedGeometry, SPEC_1, false, false, false, YAXIS_SPEC); + expect(tooltipValue.value).toBe('10'); + }); + + it('should format header with custom formatter from axis', () => { + const axisTickFormatter: TickFormatter = (v) => `${v} axis`; + const tickFormatter: TickFormatter = (v) => `${v} spec`; + const axisSpec: AxisSpec = { + ...YAXIS_SPEC, + tickFormat: axisTickFormatter, + }; + const spec: BarSeriesSpec = { + ...SPEC_1, + tickFormat: tickFormatter, + }; + const tooltipValue = formatTooltip(indexedGeometry, spec, true, false, false, axisSpec); + expect(tooltipValue.value).toBe('1 axis'); + }); + + it('should format header with default formatter from axis', () => { + const tickFormatter: TickFormatter = (v) => `${v} spec`; + const spec: BarSeriesSpec = { + ...SPEC_1, + tickFormat: tickFormatter, + }; + const tooltipValue = formatTooltip(indexedGeometry, spec, true, false, false, YAXIS_SPEC); + expect(tooltipValue.value).toBe('1'); + }); }); diff --git a/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.ts b/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.ts index ed22408756b1..c0c014e096bb 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/tooltip/tooltip.ts @@ -21,8 +21,8 @@ import { LegendItemExtraValues } from '../../../commons/legend'; import { SeriesKey } from '../../../commons/series_id'; import { TooltipValue } from '../../../specs'; import { getAccessorFormatLabel } from '../../../utils/accessor'; -import { identity } from '../../../utils/commons'; import { IndexedGeometry, BandedAccessorType } from '../../../utils/geometry'; +import { defaultTickFormatter } from '../utils/axis_utils'; import { getSeriesName } from '../utils/series'; import { AxisSpec, @@ -84,12 +84,14 @@ export function formatTooltip( const value = isHeader ? x : y; const tickFormatOptions: TickFormatterOptions | undefined = spec.timeZone ? { timeZone: spec.timeZone } : undefined; + const tickFormatter = + (isHeader ? axisSpec?.tickFormat : spec.tickFormat ?? axisSpec?.tickFormat) ?? defaultTickFormatter; return { seriesIdentifier, valueAccessor: accessor, label, - value: axisSpec ? axisSpec.tickFormat(value, tickFormatOptions) : identity(value), + value: tickFormatter(value, tickFormatOptions), markValue: isHeader || mark === null ? null : mark, color, isHighlighted: isHeader ? false : isHighlighted, diff --git a/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.test.ts b/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.test.ts index 431b134f987d..f4ff75f34e8b 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.test.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.test.ts @@ -53,6 +53,7 @@ import { getVisibleTicks, isYDomain, enableDuplicatedTicks, + defaultTickFormatter, } from './axis_utils'; import { computeXScale } from './scales'; import { AxisSpec, DomainRange, DEFAULT_GLOBAL_ID, TickFormatter } from './specs'; @@ -118,7 +119,6 @@ describe('Axis computational utils', () => { showOverlappingLabels: false, position: Position.Left, style, - tickFormat: (value: any) => `${value}`, showGridLines: true, integersOnly: false, }; @@ -133,7 +133,6 @@ describe('Axis computational utils', () => { showOverlappingLabels: false, position: Position.Top, style, - tickFormat: (value: any) => `${value}`, integersOnly: false, }; @@ -148,7 +147,6 @@ describe('Axis computational utils', () => { showOverlappingLabels: false, position: Position.Left, style, - tickFormat: (value: any) => `${value}`, showGridLines: true, integersOnly: false, }; @@ -202,7 +200,16 @@ describe('Axis computational utils', () => { test('should compute axis dimensions', () => { const bboxCalculator = new SvgTextBBoxCalculator(); - const axisDimensions = computeAxisTicksDimensions(verticalAxisSpec, xDomain, [yDomain], 1, bboxCalculator, 0, axes); + const axisDimensions = computeAxisTicksDimensions( + verticalAxisSpec, + xDomain, + [yDomain], + 1, + bboxCalculator, + 0, + axes, + (v) => `${v}`, + ); expect(axisDimensions).toEqual(axis1Dims); const ungroupedAxisSpec = { ...verticalAxisSpec, groupId: 'foo' }; @@ -214,6 +221,7 @@ describe('Axis computational utils', () => { bboxCalculator, 0, axes, + (v) => `${v}`, undefined, false, ); @@ -226,7 +234,16 @@ describe('Axis computational utils', () => { test('should not compute axis dimensions when spec is configured to hide', () => { const bboxCalculator = new CanvasTextBBoxCalculator(); verticalAxisSpec.hide = true; - const axisDimensions = computeAxisTicksDimensions(verticalAxisSpec, xDomain, [yDomain], 1, bboxCalculator, 0, axes); + const axisDimensions = computeAxisTicksDimensions( + verticalAxisSpec, + xDomain, + [yDomain], + 1, + bboxCalculator, + 0, + axes, + (v) => `${v}`, + ); expect(axisDimensions).toBe(null); }); @@ -240,7 +257,16 @@ describe('Axis computational utils', () => { minInterval: 0, timeZone: 'utc', }; - let axisDimensions = computeAxisTicksDimensions(xAxisWithTime, xDomain, [yDomain], 1, bboxCalculator, 0, axes); + let axisDimensions = computeAxisTicksDimensions( + xAxisWithTime, + xDomain, + [yDomain], + 1, + bboxCalculator, + 0, + axes, + (v) => `${v}`, + ); expect(axisDimensions).not.toBeNull(); expect(axisDimensions?.tickLabels[0]).toBe('11:00:00'); expect(axisDimensions?.tickLabels[11]).toBe('11:55:00'); @@ -256,6 +282,7 @@ describe('Axis computational utils', () => { bboxCalculator, 0, axes, + (v) => `${v}`, ); expect(axisDimensions).not.toBeNull(); expect(axisDimensions?.tickLabels[0]).toBe('14:00:00'); @@ -272,6 +299,7 @@ describe('Axis computational utils', () => { bboxCalculator, 0, axes, + (v) => `${v}`, ); expect(axisDimensions).not.toBeNull(); expect(axisDimensions?.tickLabels[0]).toBe('08:00:00'); @@ -329,7 +357,7 @@ describe('Axis computational utils', () => { test('should compute to end of domain when histogram mode not enabled', () => { const enableHistogramMode = false; const scale = getScaleForAxisSpec(verticalAxisSpec, xDomain, [yDomain], 0, 0, 100, 0); - const axisPositions = getAvailableTicks(verticalAxisSpec, scale!, 0, enableHistogramMode); + const axisPositions = getAvailableTicks(verticalAxisSpec, scale!, 0, enableHistogramMode, (v) => `${v}`); const expectedAxisPositions = [ { label: '0', position: 100, value: 0 }, { label: '0.1', position: 90, value: 0.1 }, @@ -356,7 +384,13 @@ describe('Axis computational utils', () => { minInterval: 10, }; const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0); - const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode); + const histogramAxisPositions = getAvailableTicks( + horizontalAxisSpec, + xScale!, + 1, + enableHistogramMode, + (v) => `${v}`, + ); const histogramTickLabels = histogramAxisPositions.map(({ label }: AxisTick) => label); expect(histogramTickLabels).toEqual(['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100', '110']); }); @@ -371,7 +405,13 @@ describe('Axis computational utils', () => { minInterval: 90000, }; const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0); - const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode); + const histogramAxisPositions = getAvailableTicks( + horizontalAxisSpec, + xScale!, + 1, + enableHistogramMode, + (v) => `${v}`, + ); const histogramTickValues = histogramAxisPositions.map(({ value }: AxisTick) => value); const expectedTickValues = [ @@ -403,7 +443,13 @@ describe('Axis computational utils', () => { minInterval: 90000, }; const xScale = getScaleForAxisSpec(horizontalAxisSpec, xBandDomain, [yDomain], 1, 0, 100, 0); - const histogramAxisPositions = getAvailableTicks(horizontalAxisSpec, xScale!, 1, enableHistogramMode); + const histogramAxisPositions = getAvailableTicks( + horizontalAxisSpec, + xScale!, + 1, + enableHistogramMode, + (v) => `${v}`, + ); const histogramTickValues = histogramAxisPositions.map(({ value }: AxisTick) => value); const expectedTickValues = [1560438420000, 1560438510000]; @@ -917,6 +963,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); expect(axisTicksPosition.axisPositions.get(verticalAxisSpecWTitle.id)).toEqual({ @@ -944,6 +991,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); expect(axisTicksPosition.axisPositions.get(verticalAxisSpecWTitle.id)).toEqual({ @@ -1143,6 +1191,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); expect(axisTicksPosition.axisPositions.size).toBe(0); expect(axisTicksPosition.axisTicks.size).toBe(0); @@ -1172,6 +1221,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); const expectedVerticalAxisGridLines = [ @@ -1204,6 +1254,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); const expectedPositionWithTopLegend = { @@ -1232,6 +1283,7 @@ describe('Axis computational utils', () => { [yDomain], 1, false, + (v) => `${v}`, ); }; @@ -1478,7 +1530,7 @@ describe('Axis computational utils', () => { const scale: Scale = computeXScale({ xDomain: xDomainTime, totalBarsInCluster: 0, range: [0, 603.5] }); const offset = 0; const tickFormatOption = { timeZone: 'utc+1' }; - expect(enableDuplicatedTicks(axisSpec, scale, offset, tickFormatOption)).toEqual([ + expect(enableDuplicatedTicks(axisSpec, scale, offset, (v) => `${v}`, tickFormatOption)).toEqual([ { value: 1547208000000, label: '2019-01-11', position: 25.145833333333332 }, { value: 1547251200000, label: '2019-01-12', position: 85.49583333333334 }, { value: 1547337600000, label: '2019-01-13', position: 206.19583333333333 }, @@ -1514,7 +1566,7 @@ describe('Axis computational utils', () => { const scale: Scale = computeXScale({ xDomain: xDomainTime, totalBarsInCluster: 0, range: [0, 603.5] }); const offset = 0; const tickFormatOption = { timeZone: xDomainTime.timeZone }; - const ticks = enableDuplicatedTicks(axisSpec, scale, offset, tickFormatOption); + const ticks = enableDuplicatedTicks(axisSpec, scale, offset, (v) => `${v}`, tickFormatOption); const tickLabels = ticks.map(({ label }) => ({ label })); expect(tickLabels).toEqual([ { label: '12:00' }, @@ -1558,7 +1610,7 @@ describe('Axis computational utils', () => { const scale: Scale = computeXScale({ xDomain: xDomainTime, totalBarsInCluster: 0, range: [0, 603.5] }); const offset = 0; const tickFormatOption = { timeZone: 'utc+1' }; - expect(enableDuplicatedTicks(axisSpec, scale, offset, tickFormatOption)).toEqual([ + expect(enableDuplicatedTicks(axisSpec, scale, offset, (v) => `${v}`, tickFormatOption)).toEqual([ { value: 1547208000000, label: '2019-01-11', position: 25.145833333333332 }, { value: 1547251200000, label: '2019-01-12', position: 85.49583333333334 }, { value: 1547294400000, label: '2019-01-12', position: 145.84583333333333 }, @@ -1571,6 +1623,142 @@ describe('Axis computational utils', () => { { value: 1547596800000, label: '2019-01-16', position: 568.2958333333333 }, ]); }); + test('should use custom tick formatter', () => { + const now = DateTime.fromISO('2019-01-11T00:00:00.000') + .setZone('utc+1') + .toMillis(); + const oneDay = moment.duration(1, 'day'); + const formatter = niceTimeFormatter([now, oneDay.add(now).asMilliseconds() * 31]); + const axisSpec: AxisSpec = { + id: 'bottom', + position: 'bottom', + showDuplicatedTicks: true, + chartType: 'xy_axis', + specType: 'axis', + groupId: DEFAULT_GLOBAL_ID, + hide: false, + showOverlappingLabels: false, + showOverlappingTicks: false, + style, + tickFormat: formatter, + }; + const xDomainTime: XDomain = { + type: 'xDomain', + isBandScale: false, + domain: [1547190000000, 1547622000000], + minInterval: 86400000, + scaleType: ScaleType.Time, + }; + const scale: Scale = computeXScale({ xDomain: xDomainTime, totalBarsInCluster: 0, range: [0, 603.5] }); + const offset = 0; + const tickFormatOption = { timeZone: 'utc+1' }; + expect(enableDuplicatedTicks(axisSpec, scale, offset, (v) => `${v}`, tickFormatOption)).toEqual([ + { value: 1547208000000, label: '2019-01-11', position: 25.145833333333332 }, + { value: 1547251200000, label: '2019-01-12', position: 85.49583333333334 }, + { value: 1547294400000, label: '2019-01-12', position: 145.84583333333333 }, + { value: 1547337600000, label: '2019-01-13', position: 206.19583333333333 }, + { value: 1547380800000, label: '2019-01-13', position: 266.54583333333335 }, + { value: 1547424000000, label: '2019-01-14', position: 326.8958333333333 }, + { value: 1547467200000, label: '2019-01-14', position: 387.24583333333334 }, + { value: 1547510400000, label: '2019-01-15', position: 447.59583333333336 }, + { value: 1547553600000, label: '2019-01-15', position: 507.9458333333333 }, + { value: 1547596800000, label: '2019-01-16', position: 568.2958333333333 }, + ]); + }); + + describe('Custom formatting', () => { + it('should get custom labels for y axis', () => { + const customFotmatter = (v: any) => `${v} custom`; + const axisSpecs = [verticalAxisSpec]; + const axesStyles = new Map(); + const axisDims = new Map(); + axisDims.set(verticalAxisSpec.id, axis1Dims); + + const axisTicksPosition = getAxisTicksPositions( + { + chartDimensions: chartDim, + leftMargin: 0, + }, + LIGHT_THEME, + 0, + axisSpecs, + axisDims, + axesStyles, + xDomain, + [yDomain], + 1, + false, + customFotmatter, + ); + + const expected = axis1Dims.tickValues + .slice() + .reverse() + .map(customFotmatter); + expect(axisTicksPosition.axisTicks.get(verticalAxisSpec.id)!.map(({ label }) => label)).toEqual(expected); + }); + + it('should not use custom formatter with x axis', () => { + const customFotmatter = (v: any) => `${v} custom`; + const axisSpecs = [horizontalAxisSpec]; + const axesStyles = new Map(); + const axisDims = new Map(); + axisDims.set(horizontalAxisSpec.id, axis1Dims); + + const axisTicksPosition = getAxisTicksPositions( + { + chartDimensions: chartDim, + leftMargin: 0, + }, + LIGHT_THEME, + 0, + axisSpecs, + axisDims, + axesStyles, + xDomain, + [yDomain], + 1, + false, + customFotmatter, + ); + + const expected = axis1Dims.tickValues.slice().map(defaultTickFormatter); + expect(axisTicksPosition.axisTicks.get(horizontalAxisSpec.id)!.map(({ label }) => label)).toEqual(expected); + }); + + it('should use custom axis tick formatter to get labels for x axis', () => { + const customFotmatter = (v: any) => `${v} custom`; + const customAxisFotmatter = (v: any) => `${v} custom`; + const spec: AxisSpec = { + ...horizontalAxisSpec, + tickFormat: customAxisFotmatter, + }; + const axisSpecs = [spec]; + const axesStyles = new Map(); + const axisDims = new Map(); + axisDims.set(spec.id, axis1Dims); + + const axisTicksPosition = getAxisTicksPositions( + { + chartDimensions: chartDim, + leftMargin: 0, + }, + LIGHT_THEME, + 0, + axisSpecs, + axisDims, + axesStyles, + xDomain, + [yDomain], + 1, + false, + customFotmatter, + ); + + const expected = axis1Dims.tickValues.slice().map(customAxisFotmatter); + expect(axisTicksPosition.axisTicks.get(spec.id)!.map(({ label }) => label)).toEqual(expected); + }); + }); }); it.todo('Test alignment calculations'); diff --git a/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.ts b/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.ts index 2cf210cbdd33..44b9ef88f3ce 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/utils/axis_utils.ts @@ -67,6 +67,8 @@ export interface TickLabelProps { verticalAlign: Extract; } +export const defaultTickFormatter = (tick: any) => `${tick}`; + /** * Compute the ticks values and identify max width and height of the labels * so we can compute the max space occupied by the axis component. @@ -86,6 +88,7 @@ export function computeAxisTicksDimensions( bboxCalculator: BBoxCalculator, chartRotation: Rotation, { gridLine, tickLabel }: AxisStyle, + fallBackTickFormatter: TickFormatter, barsPadding?: number, enableHistogramMode?: boolean, ): AxisTicksDimensions | null { @@ -113,7 +116,7 @@ export function computeAxisTicksDimensions( const dimensions = computeTickDimensions( scale, - axisSpec.labelFormat ?? axisSpec.tickFormat, + axisSpec.labelFormat ?? axisSpec.tickFormat ?? fallBackTickFormatter, bboxCalculator, tickLabel, { timeZone: xDomain.timeZone }, @@ -507,6 +510,7 @@ export function getAvailableTicks( scale: Scale, totalBarsInCluster: number, enableHistogramMode: boolean, + fallBackTickFormatter: TickFormatter, tickFormatOptions?: TickFormatterOptions, ): AxisTick[] { const ticks = scale.ticks(); @@ -531,25 +535,26 @@ export function getAvailableTicks( const band = scale.bandwidth / (1 - scale.barsPadding); const halfPadding = (band - scale.bandwidth) / 2; const offset = enableHistogramMode ? -halfPadding : (scale.bandwidth * shift) / 2; + const tickFormatter = axisSpec.tickFormat ?? fallBackTickFormatter; if (isSingleValueScale && hasAdditionalTicks) { - const firstTickValue = ticks[0]; + const [firstTickValue] = ticks; const firstTick = { value: firstTickValue, - label: axisSpec.tickFormat(firstTickValue, tickFormatOptions), + label: tickFormatter(firstTickValue, tickFormatOptions), position: (scale.scale(firstTickValue) ?? 0) + offset, }; const lastTickValue = firstTickValue + scale.minInterval; const lastTick = { value: lastTickValue, - label: axisSpec.tickFormat(lastTickValue, tickFormatOptions), + label: tickFormatter(lastTickValue, tickFormatOptions), position: scale.bandwidth + halfPadding * 2, }; return [firstTick, lastTick]; } - return enableDuplicatedTicks(axisSpec, scale, offset, tickFormatOptions); + return enableDuplicatedTicks(axisSpec, scale, offset, fallBackTickFormatter, tickFormatOptions); } /** @internal */ @@ -557,13 +562,14 @@ export function enableDuplicatedTicks( axisSpec: AxisSpec, scale: Scale, offset: number, + fallBackTickFormatter: TickFormatter, tickFormatOptions?: TickFormatterOptions, -) { +): AxisTick[] { const ticks = scale.ticks(); const allTicks: AxisTick[] = ticks.map((tick) => ({ value: tick, // TODO handle empty string tick formatting - label: axisSpec.tickFormat(tick, tickFormatOptions), + label: (axisSpec.tickFormat ?? fallBackTickFormatter)(tick, tickFormatOptions), position: (scale.scale(tick) ?? 0) + offset, })); @@ -685,6 +691,7 @@ export function getAxisTicksPositions( yDomain: YDomain[], totalGroupsCount: number, enableHistogramMode: boolean, + fallBackTickFormatter: TickFormatter, barsPadding?: number, ): { axisPositions: Map; @@ -731,9 +738,17 @@ export function getAxisTicksPositions( timeZone: xDomain.timeZone, }; const { axisTitle, tickLine, tickLabel, gridLine } = axesStyles.get(id) ?? sharedAxesStyle; - const allTicks = getAvailableTicks(axisSpec, scale, totalGroupsCount, enableHistogramMode, tickFormatOptions); - const visibleTicks = getVisibleTicks(allTicks, axisSpec, axisDim); const isVertical = isVerticalAxis(axisSpec.position); + const allTicks = getAvailableTicks( + axisSpec, + scale, + totalGroupsCount, + enableHistogramMode, + isVertical ? fallBackTickFormatter : defaultTickFormatter, + tickFormatOptions, + ); + + const visibleTicks = getVisibleTicks(allTicks, axisSpec, axisDim); const axisSpecConfig = axisSpec.gridLine; const gridLineThemeStyles = isVertical ? gridLine.vertical : gridLine.horizontal; const gridLineStyles = axisSpecConfig ? mergePartial(gridLineThemeStyles, axisSpecConfig) : gridLineThemeStyles; diff --git a/packages/osd-charts/src/chart_types/xy_chart/utils/specs.ts b/packages/osd-charts/src/chart_types/xy_chart/utils/specs.ts index 32d37ecfb56e..7d4625d57d7f 100644 --- a/packages/osd-charts/src/chart_types/xy_chart/utils/specs.ts +++ b/packages/osd-charts/src/chart_types/xy_chart/utils/specs.ts @@ -382,6 +382,11 @@ export interface SeriesSpec extends Spec { * Hide series in tooltip */ filterSeriesInTooltip?: FilterPredicate; + /** + * A function called to format every value label. + * Uses axis `tickFormat` when not provided. + */ + tickFormat?: TickFormatter; } export interface Postfixes { @@ -621,11 +626,14 @@ export interface AxisSpec extends Spec { /** Where the axis appear on the chart */ position: Position; /** - * A function called to format every single tick label (includes tooltip) + * A function called to format every tick value label. + * Uses first series spec `tickFormat` when not provided. + * + * used in tooltip when no `tickFormat` is provided from series spec */ - tickFormat: TickFormatter; + tickFormat?: TickFormatter; /** - * A function called to format every single label (excludes tooltip) + * A function called to format every label (excludes tooltip) * * overrides tickFormat for axis labels */ diff --git a/packages/osd-charts/stories/axes/6a_different_tooltip_formatter.tsx b/packages/osd-charts/stories/axes/6a_different_tooltip_formatter.tsx new file mode 100644 index 000000000000..62cdd2ac170b --- /dev/null +++ b/packages/osd-charts/stories/axes/6a_different_tooltip_formatter.tsx @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { text, boolean } from '@storybook/addon-knobs'; +import numeral from 'numeral'; +import React from 'react'; + +import { Axis, Chart, LineSeries, Position, ScaleType, Settings } from '../../src'; +import { SB_SOURCE_PANEL } from '../utils/storybook'; + +export const Example = () => { + const showLegend = boolean('Show legend', true); + const disableAxisFormat = boolean('Disable Y Axis tickFormat', false); + const axisFormat = text('Y Axis value format', '0[.]0'); + const axisUnit = text('Y Axis unit', 'pets'); + const disableDogLineFormat = boolean('Disable dog line tickFormat', false); + const dogLineFormat = text('Dog line unit', 'dogs'); + const disableCatLineFormat = boolean('Disable cat line tickFormat', false); + const catLineFormat = text('Cat line unit', 'cats'); + + return ( + + + + `${numeral(d).format(axisFormat)}${axisUnit ? ` ${axisUnit}` : ''}` + } + /> + `${Number(d).toFixed(2)} ${dogLineFormat}`} + data={[ + { x: 'USA', y: 8 }, + { x: 'Canada', y: 7 }, + { x: 'Mexico', y: 18 }, + ]} + /> + `${Number(d).toFixed(2)} ${catLineFormat}`} + data={[ + { x: 'USA', y: 14 }, + { x: 'Canada', y: 15 }, + { x: 'Mexico', y: 14 }, + ]} + /> + + ); +}; + +// storybook configuration +Example.story = { + parameters: { + options: { selectedPanel: SB_SOURCE_PANEL }, + info: { + text: 'Using a single axis with different unit types is discouraged. ', + }, + }, +}; diff --git a/packages/osd-charts/stories/axes/axes.stories.tsx b/packages/osd-charts/stories/axes/axes.stories.tsx index 183180515064..8b9f826468e7 100644 --- a/packages/osd-charts/stories/axes/axes.stories.tsx +++ b/packages/osd-charts/stories/axes/axes.stories.tsx @@ -32,6 +32,7 @@ export { Example as with4Axes } from './3_axis_4_axes'; export { Example as multiAxes } from './4_multi_axis'; export { Example as barsAndLines } from './5_multi_axis_bar_lines'; export { Example as differentTooltip } from './6_different_tooltip'; +export { Example as differentTooltipFormatter } from './6a_different_tooltip_formatter'; export { Example as manyTickLabels } from './7_many_tick_labels'; export { Example as customDomain } from './8_custom_domain'; export { Example as customMixed } from './9_custom_mixed_domain';