From 5437d8e985ecc8cfa32651ccc97fdf7b9da84b01 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Wed, 6 Apr 2022 10:35:29 -0500 Subject: [PATCH] feat(goal): auto generated linear ticks (#1637) BREAKING CHANGE: goal chart now requires domain min and max to be defined --- ...ar-ticks-visually-looks-correct-1-snap.png | Bin 0 -> 10024 bytes ...s-auto-ticks-goal-reverse-false-1-snap.png | Bin 0 -> 28599 bytes ...es-auto-ticks-goal-reverse-true-1-snap.png | Bin 0 -> 28445 bytes integration/tests/goal_stories.test.ts | 8 +++ packages/charts/api/charts.api.md | 13 ++-- .../layout/types/viewmodel_types.ts | 2 - .../goal_chart/layout/viewmodel/viewmodel.ts | 59 ++++++++++++---- .../src/chart_types/goal_chart/specs/index.ts | 26 ++++++- .../accessibility/accessibility.test.tsx | 2 + packages/charts/src/utils/common.test.ts | 20 ++++++ packages/charts/src/utils/common.ts | 27 ++++++++ .../stories/goal/10_band_in_band.story.tsx | 1 + storybook/stories/goal/11_gaps.story.tsx | 1 + storybook/stories/goal/12_range.story.tsx | 1 + .../goal/13_confidence_level.story.tsx | 1 + storybook/stories/goal/14_one_third.story.tsx | 1 + .../stories/goal/15_half_circle.story.tsx | 1 + .../stories/goal/16_two_thirds.story.tsx | 1 + .../stories/goal/17_three_quarters.story.tsx | 1 + .../stories/goal/17_total_circle.story.tsx | 1 + .../stories/goal/17_very_small_gap.story.tsx | 1 + .../stories/goal/18_side_gauge.story.tsx | 1 + ...de_gauge_inverted_angle_relation.story.tsx | 1 + .../goal/19_horizontal_negative.story.tsx | 1 + .../goal/20_vertical_negative.story.tsx | 1 + .../stories/goal/21_goal_negative.story.tsx | 1 + .../goal/22_horizontal_plusminus.story.tsx | 1 + .../goal/23_vertical_plusminus.story.tsx | 1 + .../stories/goal/24_goal_plusminus.story.tsx | 1 + .../stories/goal/25_goal_semantic.story.tsx | 2 +- .../goal/26_auto_linear_ticks.story.tsx | 65 ++++++++++++++++++ .../goal/2_gauge_with_target.story.tsx | 1 + .../goal/3_horizontal_bullet.story.tsx | 1 + .../stories/goal/4_vertical_bullet.story.tsx | 1 + storybook/stories/goal/5_minimal.story.tsx | 1 + .../goal/6_minimal_horizontal.story.tsx | 1 + .../stories/goal/7_horizontal_bar.story.tsx | 1 + .../stories/goal/8_irregular_ticks.story.tsx | 1 + .../stories/goal/9_minimal_band.story.tsx | 1 + storybook/stories/goal/goal.stories.tsx | 1 + .../interactions/17_png_export.story.tsx | 1 + 41 files changed, 231 insertions(+), 21 deletions(-) create mode 100644 integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-goal-alpha-auto-linear-ticks-visually-looks-correct-1-snap.png create mode 100644 integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-false-1-snap.png create mode 100644 integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-true-1-snap.png create mode 100644 storybook/stories/goal/26_auto_linear_ticks.story.tsx diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-goal-alpha-auto-linear-ticks-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-goal-alpha-auto-linear-ticks-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..4d4efc5f2a6fd25aa051e83aa29557ec9e5dd3fa GIT binary patch literal 10024 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 ZH6bILVp_r%VYm;1J+G^otNzn3{|j_SE35zj literal 0 HcmV?d00001 diff --git a/integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-false-1-snap.png b/integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-false-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..3028c84dd46925f81a2268b83cdbf61faa696256 GIT binary patch literal 28599 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 literal 0 HcmV?d00001 diff --git a/integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-true-1-snap.png b/integration/tests/__image_snapshots__/goal-stories-test-ts-goal-stories-auto-ticks-goal-reverse-true-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..626f9457d855b16f7208b60b750097d75bc5cbcd GIT binary patch literal 28445 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 NsC(*np(~RA{{rWiiQ)hN literal 0 HcmV?d00001 diff --git a/integration/tests/goal_stories.test.ts b/integration/tests/goal_stories.test.ts index 54341020e0..40bcce9625 100644 --- a/integration/tests/goal_stories.test.ts +++ b/integration/tests/goal_stories.test.ts @@ -83,6 +83,14 @@ describe('Goal stories', () => { ); }); + describe('auto ticks', () => { + it.each([true, false])('goal - reverse %p', async (reverse) => { + await common.expectChartAtUrlToMatchScreenshot( + `http://localhost:9001/?path=/story/goal-alpha--auto-linear-ticks&knob-subtype=goal&knob-reverse=${reverse}`, + ); + }); + }); + describe('sagitta shifted goal charts', () => { it.each<[title: string, startAngle: number, endAngle: number]>([ // top openings diff --git a/packages/charts/api/charts.api.md b/packages/charts/api/charts.api.md index 8b393be5f6..b4f106fcd6 100644 --- a/packages/charts/api/charts.api.md +++ b/packages/charts/api/charts.api.md @@ -958,6 +958,12 @@ export function getNodeName(node: ArrayNode): string; // @alpha export const Goal: (props: SFProps) => null; +// @alpha (undocumented) +export interface GoalDomainRange { + max: number; + min: number; +} + // @alpha (undocumented) export type GoalLabelAccessor = LabelAccessor; @@ -978,8 +984,7 @@ export interface GoalSpec extends Spec { bandFillColor: BandFillColorAccessor; // (undocumented) bandLabels: string[]; - // (undocumented) - bands: number[]; + bands?: number | number[]; // (undocumented) base: number; // (undocumented) @@ -988,6 +993,7 @@ export interface GoalSpec extends Spec { centralMinor: string | GoalLabelAccessor; // (undocumented) chartType: typeof ChartType.Goal; + domain: GoalDomainRange; // (undocumented) labelMajor: string | GoalLabelAccessor; // (undocumented) @@ -1000,8 +1006,7 @@ export interface GoalSpec extends Spec { subtype: GoalSubtype; // (undocumented) target?: number; - // (undocumented) - ticks: number[]; + ticks?: number | number[]; // (undocumented) tickValueFormatter: GoalLabelAccessor; // (undocumented) diff --git a/packages/charts/src/chart_types/goal_chart/layout/types/viewmodel_types.ts b/packages/charts/src/chart_types/goal_chart/layout/types/viewmodel_types.ts index 4180eb7dfb..bc9ecb2b6a 100644 --- a/packages/charts/src/chart_types/goal_chart/layout/types/viewmodel_types.ts +++ b/packages/charts/src/chart_types/goal_chart/layout/types/viewmodel_types.ts @@ -62,13 +62,11 @@ export type ShapeViewModel = { const commonDefaults = { base: 0, actual: 50, - ticks: [0, 25, 50, 75, 100], }; /** @internal */ export const defaultGoalSpec = { ...commonDefaults, - bands: [50, 75, 100], bandFillColor: ({ value, highestValue, lowestValue }: BandFillColorAccessorInput) => { return getGreensColorScale(0.5, [highestValue, lowestValue])(value); }, diff --git a/packages/charts/src/chart_types/goal_chart/layout/viewmodel/viewmodel.ts b/packages/charts/src/chart_types/goal_chart/layout/viewmodel/viewmodel.ts index 68ad0462f1..941f7c91ad 100644 --- a/packages/charts/src/chart_types/goal_chart/layout/viewmodel/viewmodel.ts +++ b/packages/charts/src/chart_types/goal_chart/layout/viewmodel/viewmodel.ts @@ -6,10 +6,14 @@ * Side Public License, v 1. */ +import { Radian } from '../../../../common/geometry'; +import { ScaleContinuous } from '../../../../scales'; import { Dimensions } from '../../../../utils/dimensions'; import { Theme } from '../../../../utils/themes/theme'; import { GoalSpec } from '../../specs'; +import { GoalSubtype } from '../../specs/constants'; import { BulletViewModel, PickFunction, ShapeViewModel } from '../types/viewmodel_types'; +import { clamp, clampAll, isBetween, isFiniteNumber, isNil } from './../../../../utils/common'; /** @internal */ export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Dimensions): ShapeViewModel { @@ -24,11 +28,9 @@ export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Di const { subtype, - base, - target, - actual, - bands, ticks, + bands, + domain, bandFillColor, tickValueFormatter, labelMajor, @@ -39,13 +41,40 @@ export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Di angleStart, angleEnd, } = spec; - const [lowestValue, highestValue] = [base, ...(target ? [target] : []), actual, ...bands, ...ticks].reduce( - ([min, max], value) => [Math.min(min, value), Math.max(max, value)], - [Infinity, -Infinity], - ); + const lowestValue = isFiniteNumber(domain.min) ? domain.min : 0; + const highestValue = isFiniteNumber(domain.max) ? domain.max : 1; + const base = clamp(spec.base, lowestValue, highestValue); + const target = + !isNil(spec.target) && spec.target <= highestValue && spec.target >= lowestValue ? spec.target : undefined; + const actual = clamp(spec.actual, lowestValue, highestValue); + const finalTicks = Array.isArray(ticks) + ? ticks.filter(isBetween(lowestValue, highestValue)) + : new ScaleContinuous( + { + type: 'linear', + domain: [lowestValue, highestValue], + range: [0, 1], + }, + { + desiredTickCount: ticks ?? getDesiredTicks(subtype, angleStart, angleEnd), + }, + ).ticks(); + + const finalBands = Array.isArray(bands) + ? bands.reduce(...clampAll(lowestValue, highestValue)) + : new ScaleContinuous( + { + type: 'linear', + domain: [lowestValue, highestValue], + range: [0, 1], + }, + { + desiredTickCount: bands ?? getDesiredTicks(subtype, angleStart, angleEnd), + }, + ).ticks(); - const aboveBaseCount = bands.filter((b: number) => b > base).length; - const belowBaseCount = bands.filter((b: number) => b <= base).length; + const aboveBaseCount = finalBands.filter((b: number) => b > base).length; + const belowBaseCount = finalBands.filter((b: number) => b <= base).length; const callbackArgs = { base, @@ -62,12 +91,12 @@ export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Di base, target, actual, - bands: bands.map((value: number, index: number) => ({ + bands: finalBands.map((value: number, index: number) => ({ value, fillColor: bandFillColor({ value, index, ...callbackArgs }), text: bandLabels, })), - ticks: ticks.map((value: number, index: number) => ({ + ticks: finalTicks.map((value: number, index: number) => ({ value, text: tickValueFormatter({ value, index, ...callbackArgs }), })), @@ -98,3 +127,9 @@ export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Di pickQuads, }; } + +function getDesiredTicks(subtype: GoalSubtype, angleStart: Radian, angleEnd: Radian) { + if (subtype !== GoalSubtype.Goal) return 5; + const arc = Math.abs(angleStart - angleEnd); + return Math.ceil(arc / (Math.PI / 4)); +} diff --git a/packages/charts/src/chart_types/goal_chart/specs/index.ts b/packages/charts/src/chart_types/goal_chart/specs/index.ts index 6febeb9af4..e131dc099c 100644 --- a/packages/charts/src/chart_types/goal_chart/specs/index.ts +++ b/packages/charts/src/chart_types/goal_chart/specs/index.ts @@ -37,6 +37,18 @@ export type BandFillColorAccessor = (input: BandFillColorAccessorInput) => Color /** @alpha */ export type GoalLabelAccessor = LabelAccessor; +/** @alpha */ +export interface GoalDomainRange { + /** + * A finite number to defined the lower bound of the domain. Defaults to 0 if _not_ finite. + */ + min: number; + /** + * A finite number to defined the upper bound of the domain. Defaults to 1 if _not_ finite. + */ + max: number; +} + /** @alpha */ export interface GoalSpec extends Spec { specType: typeof SpecType.Series; @@ -45,8 +57,18 @@ export interface GoalSpec extends Spec { base: number; target?: number; actual: number; - bands: number[]; - ticks: number[]; + /** + * array of discrete band intervals or approximate number of desired bands + */ + bands?: number | number[]; + /** + * Array of discrete tick values or approximate number of desired ticks + */ + ticks?: number | number[]; + /** + * Domain of goal charts. Limits every value to within domain. + */ + domain: GoalDomainRange; bandFillColor: BandFillColorAccessor; tickValueFormatter: GoalLabelAccessor; labelMajor: string | GoalLabelAccessor; diff --git a/packages/charts/src/components/accessibility/accessibility.test.tsx b/packages/charts/src/components/accessibility/accessibility.test.tsx index 0eedeb9042..3445b67762 100644 --- a/packages/charts/src/components/accessibility/accessibility.test.tsx +++ b/packages/charts/src/components/accessibility/accessibility.test.tsx @@ -132,6 +132,7 @@ describe('Accessibility', () => { target={260} actual={170} bands={[200, 250, 300]} + domain={{ min: 0, max: 300 }} ticks={[0, 50, 100, 150, 200, 250, 300]} labelMajor="Revenue 2020 YTD " labelMinor="(thousand USD) " @@ -155,6 +156,7 @@ describe('Accessibility', () => { target={260} actual={170} bands={bandsAscending} + domain={{ min: 0, max: 300 }} ticks={[0, 50, 100, 150, 200, 250, 300]} labelMajor="Revenue 2020 YTD " labelMinor="(thousand USD) " diff --git a/packages/charts/src/utils/common.test.ts b/packages/charts/src/utils/common.test.ts index c67e4321ad..c7e36bcf28 100644 --- a/packages/charts/src/utils/common.test.ts +++ b/packages/charts/src/utils/common.test.ts @@ -20,6 +20,8 @@ import { isUniqueArray, isDefined, isDefinedFrom, + isBetween, + clampAll, } from './common'; describe('common utilities', () => { @@ -1025,4 +1027,22 @@ describe('#isDefinedFrom', () => { ); expect(result).toEqual(values.slice(0, 3)); }); + + describe('#isBetween', () => { + it('should filter array values between min and max inclusive', () => { + expect([1, 2, 3, 4, 5, 6].filter(isBetween(2, 5, false))).toEqual([2, 3, 4, 5]); + }); + it('should filter array values between min and max exclusive', () => { + expect([1, 2, 3, 4, 5, 6].filter(isBetween(2, 5, true))).toEqual([3, 4]); + }); + }); + + describe('#clampAll', () => { + it('should clamp each value in array between min and max', () => { + expect([0, 200, 400].reduce(...clampAll(100, 300))).toEqual([100, 200, 300]); + }); + it('should clamp array values and remove duplicates', () => { + expect([0, 100, 200, 300, 400].reduce(...clampAll(100, 300))).toEqual([100, 200, 300]); + }); + }); }); diff --git a/packages/charts/src/utils/common.ts b/packages/charts/src/utils/common.ts index 816d461c85..bc1b3a48be 100644 --- a/packages/charts/src/utils/common.ts +++ b/packages/charts/src/utils/common.ts @@ -645,3 +645,30 @@ export function stripUndefined>(source: R): R return acc; }, {} as R); } + +/** + * Returns `Array.filter` callback for values between a min and max + * @internal + */ +export const isBetween = (min: number, max: number, exclusive = false): ((n: number) => boolean) => + exclusive ? (n) => n < max && n > min : (n) => n <= max && n >= min; + +/** + * Returns `Array.reduce` callback to clamp values and remove duplicates + * @internal + */ +export const clampAll = ( + min: number, + max: number, +): [callbackfn: (acc: number[], value: number) => number[], initialAcc: number[]] => { + const seen = new Set(); + return [ + (acc: number[], n: number) => { + const clampValue = clamp(n, min, max); + if (!seen.has(clampValue)) acc.push(clampValue); + seen.add(clampValue); + return acc; + }, + [], + ]; +}; diff --git a/storybook/stories/goal/10_band_in_band.story.tsx b/storybook/stories/goal/10_band_in_band.story.tsx index 5aad312fa8..443455055b 100644 --- a/storybook/stories/goal/10_band_in_band.story.tsx +++ b/storybook/stories/goal/10_band_in_band.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( target={0} actual={0} bands={[225, 300]} + domain={{ min: 0, max: 300 }} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} bandFillColor={({ value }: BandFillColorAccessorInput) => bandFillColor(value)} diff --git a/storybook/stories/goal/11_gaps.story.tsx b/storybook/stories/goal/11_gaps.story.tsx index 6d5a9570d9..a2d1f9a8b9 100644 --- a/storybook/stories/goal/11_gaps.story.tsx +++ b/storybook/stories/goal/11_gaps.story.tsx @@ -41,6 +41,7 @@ export const Example = () => { base={0} target={showTarget ? target : undefined} actual={280} + domain={{ min: 0, max: 300 }} bands={[199, 201, 249, 251, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/12_range.story.tsx b/storybook/stories/goal/12_range.story.tsx index 87bcd2bccd..b432133d7c 100644 --- a/storybook/stories/goal/12_range.story.tsx +++ b/storybook/stories/goal/12_range.story.tsx @@ -35,6 +35,7 @@ export const Example = () => ( target={0} actual={0} bands={[215, 235, 300]} + domain={{ min: 0, max: 300 }} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} bandFillColor={({ value }: BandFillColorAccessorInput) => bandFillColor(value)} diff --git a/storybook/stories/goal/13_confidence_level.story.tsx b/storybook/stories/goal/13_confidence_level.story.tsx index ba0924da07..92909a0f11 100644 --- a/storybook/stories/goal/13_confidence_level.story.tsx +++ b/storybook/stories/goal/13_confidence_level.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={226.5} actual={0} + domain={{ min: 0, max: 300 }} bands={[210, 218, 224, 229, 235, 243, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/14_one_third.story.tsx b/storybook/stories/goal/14_one_third.story.tsx index cc28b62ffd..4be3905283 100644 --- a/storybook/stories/goal/14_one_third.story.tsx +++ b/storybook/stories/goal/14_one_third.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/15_half_circle.story.tsx b/storybook/stories/goal/15_half_circle.story.tsx index 4799b373eb..6fe7ff39dd 100644 --- a/storybook/stories/goal/15_half_circle.story.tsx +++ b/storybook/stories/goal/15_half_circle.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/16_two_thirds.story.tsx b/storybook/stories/goal/16_two_thirds.story.tsx index a1050859c2..642fdc2363 100644 --- a/storybook/stories/goal/16_two_thirds.story.tsx +++ b/storybook/stories/goal/16_two_thirds.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/17_three_quarters.story.tsx b/storybook/stories/goal/17_three_quarters.story.tsx index b856e74731..7f477704a6 100644 --- a/storybook/stories/goal/17_three_quarters.story.tsx +++ b/storybook/stories/goal/17_three_quarters.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/17_total_circle.story.tsx b/storybook/stories/goal/17_total_circle.story.tsx index 564631bcc0..5c0f883176 100644 --- a/storybook/stories/goal/17_total_circle.story.tsx +++ b/storybook/stories/goal/17_total_circle.story.tsx @@ -35,6 +35,7 @@ export const Example = () => { base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 265, 280]} tickValueFormatter={({ value }) => String(value)} diff --git a/storybook/stories/goal/17_very_small_gap.story.tsx b/storybook/stories/goal/17_very_small_gap.story.tsx index 26e27cf419..caf5402f34 100644 --- a/storybook/stories/goal/17_very_small_gap.story.tsx +++ b/storybook/stories/goal/17_very_small_gap.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 265, 280]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/18_side_gauge.story.tsx b/storybook/stories/goal/18_side_gauge.story.tsx index 8a478720fd..b4a95abe1f 100644 --- a/storybook/stories/goal/18_side_gauge.story.tsx +++ b/storybook/stories/goal/18_side_gauge.story.tsx @@ -32,6 +32,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/18_side_gauge_inverted_angle_relation.story.tsx b/storybook/stories/goal/18_side_gauge_inverted_angle_relation.story.tsx index 6fdd5e4500..7bda47aeab 100644 --- a/storybook/stories/goal/18_side_gauge_inverted_angle_relation.story.tsx +++ b/storybook/stories/goal/18_side_gauge_inverted_angle_relation.story.tsx @@ -32,6 +32,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/19_horizontal_negative.story.tsx b/storybook/stories/goal/19_horizontal_negative.story.tsx index 4279b0bade..41a4e1c881 100644 --- a/storybook/stories/goal/19_horizontal_negative.story.tsx +++ b/storybook/stories/goal/19_horizontal_negative.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={-260} actual={-280} + domain={{ min: -300, max: 0 }} bands={[-200, -250, -300]} ticks={[0, -50, -100, -150, -200, -250, -300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/20_vertical_negative.story.tsx b/storybook/stories/goal/20_vertical_negative.story.tsx index e87e4cb35c..98a57e0d27 100644 --- a/storybook/stories/goal/20_vertical_negative.story.tsx +++ b/storybook/stories/goal/20_vertical_negative.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={-260} actual={-280} + domain={{ min: -300, max: 0 }} bands={[-200, -250, -300]} ticks={[0, -50, -100, -150, -200, -250, -300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/21_goal_negative.story.tsx b/storybook/stories/goal/21_goal_negative.story.tsx index 68e1f49b20..f30db1a373 100644 --- a/storybook/stories/goal/21_goal_negative.story.tsx +++ b/storybook/stories/goal/21_goal_negative.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={-260} actual={-280} + domain={{ min: -300, max: 0 }} bands={[-200, -250, -300]} ticks={[0, -50, -100, -150, -200, -250, -300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/22_horizontal_plusminus.story.tsx b/storybook/stories/goal/22_horizontal_plusminus.story.tsx index 305108a944..511d34e687 100644 --- a/storybook/stories/goal/22_horizontal_plusminus.story.tsx +++ b/storybook/stories/goal/22_horizontal_plusminus.story.tsx @@ -40,6 +40,7 @@ export const Example = () => ( base={0} target={260} actual={-80} + domain={{ min: -200, max: 300 }} bands={[-200, -100, 0, 200, 250, 300]} ticks={[-200, -100, 0, 100, 200, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/23_vertical_plusminus.story.tsx b/storybook/stories/goal/23_vertical_plusminus.story.tsx index bafc02e92e..f8257d342c 100644 --- a/storybook/stories/goal/23_vertical_plusminus.story.tsx +++ b/storybook/stories/goal/23_vertical_plusminus.story.tsx @@ -40,6 +40,7 @@ export const Example = () => ( base={0} target={260} actual={-80} + domain={{ min: -200, max: 300 }} bands={[-200, -100, 0, 200, 250, 300]} ticks={[-200, -100, 0, 100, 200, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/24_goal_plusminus.story.tsx b/storybook/stories/goal/24_goal_plusminus.story.tsx index 4e26971db8..b2b4d6f650 100644 --- a/storybook/stories/goal/24_goal_plusminus.story.tsx +++ b/storybook/stories/goal/24_goal_plusminus.story.tsx @@ -40,6 +40,7 @@ export const Example = () => ( base={0} target={260} actual={-80} + domain={{ min: -100, max: 300 }} bands={[-100, -50, 0, 200, 250, 300]} ticks={[-100, 0, 100, 200, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/25_goal_semantic.story.tsx b/storybook/stories/goal/25_goal_semantic.story.tsx index 673ab45816..fec2b5c01e 100644 --- a/storybook/stories/goal/25_goal_semantic.story.tsx +++ b/storybook/stories/goal/25_goal_semantic.story.tsx @@ -39,7 +39,7 @@ export const Example = () => { base={0} target={260} actual={170} - // doesn't mess with canvas_renderers.ts + domain={{ min: 0, max: 300 }} bands={bands} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/26_auto_linear_ticks.story.tsx b/storybook/stories/goal/26_auto_linear_ticks.story.tsx new file mode 100644 index 0000000000..b7b25339f7 --- /dev/null +++ b/storybook/stories/goal/26_auto_linear_ticks.story.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { array, boolean, number } from '@storybook/addon-knobs'; +import React from 'react'; + +import { Chart, Goal, Settings } from '@elastic/charts'; +import { BandFillColorAccessorInput } from '@elastic/charts/src/chart_types/goal_chart/specs'; +import { GoalSubtype } from '@elastic/charts/src/chart_types/goal_chart/specs/constants'; + +import { useBaseTheme } from '../../use_base_theme'; +import { getKnobsFromEnum } from '../utils/knobs'; + +export const Example = () => { + const subtype = + getKnobsFromEnum('subtype', GoalSubtype, GoalSubtype.VerticalBullet as GoalSubtype) ?? GoalSubtype.VerticalBullet; + const reverse = boolean('reverse', false); + const start = number('angleStart (π)', 5 / 4, { min: -2, max: 2, step: 1 / 8 }); + const end = number('angleEnd (π)', -1 / 4, { min: -2, max: 2, step: 1 / 8 }); + const base = number('base', 0); + const target = number('target', 260); + const actual = number('actual', 280); + const min = number('domain min', 0, { min: 0, step: 50 }); + const max = number('domain max', 300, { min, step: 50 }); + const autoTicks = boolean('auto generate ticks', true); + const ticks = autoTicks ? undefined : array('ticks', ['0', '100', '200', '300']).map(Number); + const autoBands = boolean('auto generate bands', true); + const bands = autoBands ? undefined : array('bands', ['200', '250', '300']).map(Number); + + const angleStart = start * Math.PI; + const angleEnd = end * Math.PI; + + return ( + + + String(value)} + labelMajor="Speed average" + labelMinor={subtype === GoalSubtype.Goal ? '' : `${actual} MB/s`} + centralMajor={`${actual} MB/s`} + centralMinor="" + /> + + ); +}; + +Example.parameters = { + markdown: `Leaving \`ticks\` and/or \`bands\` as \`undefined\` will automatically generate linear values given the specified domain. +If \`ticks\` and/or \`bands\` is set to \`[]\` (empty array), no ticks or bands will be displayed, respectively`, +}; diff --git a/storybook/stories/goal/2_gauge_with_target.story.tsx b/storybook/stories/goal/2_gauge_with_target.story.tsx index 745d304171..16d30d98e5 100644 --- a/storybook/stories/goal/2_gauge_with_target.story.tsx +++ b/storybook/stories/goal/2_gauge_with_target.story.tsx @@ -66,6 +66,7 @@ export const Example = () => { actual={actual} bands={bands} ticks={ticks} + domain={{ min: 0, max: 300 }} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} bandFillColor={useColors ? ({ value }: BandFillColorAccessorInput) => bandFillColor(value) : undefined} labelMajor="Revenue 2020 YTD " diff --git a/storybook/stories/goal/3_horizontal_bullet.story.tsx b/storybook/stories/goal/3_horizontal_bullet.story.tsx index fc11ef1329..69382f66ed 100644 --- a/storybook/stories/goal/3_horizontal_bullet.story.tsx +++ b/storybook/stories/goal/3_horizontal_bullet.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/4_vertical_bullet.story.tsx b/storybook/stories/goal/4_vertical_bullet.story.tsx index e10a245089..ec633f6177 100644 --- a/storybook/stories/goal/4_vertical_bullet.story.tsx +++ b/storybook/stories/goal/4_vertical_bullet.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/5_minimal.story.tsx b/storybook/stories/goal/5_minimal.story.tsx index 0e4a67d189..bc64cc0a2d 100644 --- a/storybook/stories/goal/5_minimal.story.tsx +++ b/storybook/stories/goal/5_minimal.story.tsx @@ -39,6 +39,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/6_minimal_horizontal.story.tsx b/storybook/stories/goal/6_minimal_horizontal.story.tsx index 50cd4ce1e7..3a9ec2df68 100644 --- a/storybook/stories/goal/6_minimal_horizontal.story.tsx +++ b/storybook/stories/goal/6_minimal_horizontal.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[300]} ticks={[0, 100, 200, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/7_horizontal_bar.story.tsx b/storybook/stories/goal/7_horizontal_bar.story.tsx index 34df6e1a0d..febbacebf9 100644 --- a/storybook/stories/goal/7_horizontal_bar.story.tsx +++ b/storybook/stories/goal/7_horizontal_bar.story.tsx @@ -38,6 +38,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[]} ticks={[0, 100, 200, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/8_irregular_ticks.story.tsx b/storybook/stories/goal/8_irregular_ticks.story.tsx index 48b6ae224e..da4511e1c8 100644 --- a/storybook/stories/goal/8_irregular_ticks.story.tsx +++ b/storybook/stories/goal/8_irregular_ticks.story.tsx @@ -34,6 +34,7 @@ export const Example = () => ( base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 100, 200, 250, 260, 270, 280, 290, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/9_minimal_band.story.tsx b/storybook/stories/goal/9_minimal_band.story.tsx index a2867d18b0..adda20be2d 100644 --- a/storybook/stories/goal/9_minimal_band.story.tsx +++ b/storybook/stories/goal/9_minimal_band.story.tsx @@ -32,6 +32,7 @@ export const Example = () => ( base={0} target={225} actual={0} + domain={{ min: 0, max: 300 }} bands={[300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)} diff --git a/storybook/stories/goal/goal.stories.tsx b/storybook/stories/goal/goal.stories.tsx index 8489beca87..6b60179f27 100644 --- a/storybook/stories/goal/goal.stories.tsx +++ b/storybook/stories/goal/goal.stories.tsx @@ -37,3 +37,4 @@ export { Example as horizontalPlusMinus } from './22_horizontal_plusminus.story' export { Example as verticalPlusMinus } from './23_vertical_plusminus.story'; export { Example as goalPlusMinus } from './24_goal_plusminus.story'; export { Example as goalSemantics } from './25_goal_semantic.story'; +export { Example as autoLinearTicks } from './26_auto_linear_ticks.story'; diff --git a/storybook/stories/interactions/17_png_export.story.tsx b/storybook/stories/interactions/17_png_export.story.tsx index ad25170f23..245aa2ef7c 100644 --- a/storybook/stories/interactions/17_png_export.story.tsx +++ b/storybook/stories/interactions/17_png_export.story.tsx @@ -145,6 +145,7 @@ function renderGoalchart() { base={0} target={260} actual={280} + domain={{ min: 0, max: 300 }} bands={[200, 250, 300]} ticks={[0, 50, 100, 150, 200, 250, 300]} tickValueFormatter={({ value }: BandFillColorAccessorInput) => String(value)}