From 944ac6cf1ce12f9993411cf44bb3fa51f25b1241 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Mon, 25 Jan 2021 16:35:19 +0100 Subject: [PATCH] fix: chart state and series functions cleanup (#989) --- .playground/playground.tsx | 21 +-- ...ogeneous-visually-looks-correct-1-snap.png | Bin 0 -> 24651 bytes src/chart_types/xy_chart/utils/series.ts | 118 ++++--------- src/state/chart_state.ts | 120 ++++--------- src/utils/common.ts | 8 +- .../6_heterogeneous_cartesians.tsx | 164 ++++++++++++++++++ .../small_multiples.stories.tsx | 1 + stories/treemap/10_three_layers.tsx | 3 +- 8 files changed, 241 insertions(+), 194 deletions(-) create mode 100644 integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-small-multiples-alpha-heterogeneous-visually-looks-correct-1-snap.png create mode 100644 stories/small_multiples/6_heterogeneous_cartesians.tsx diff --git a/.playground/playground.tsx b/.playground/playground.tsx index 3c9f2ee240..0d74cc58c2 100644 --- a/.playground/playground.tsx +++ b/.playground/playground.tsx @@ -17,28 +17,9 @@ * under the License. */ -/* - * 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 React from 'react'; -import { Example } from '../stories/icicle/01_unix_icicle'; +import { Example } from '../stories/small_multiples/6_heterogeneous_cartesians'; export class Playground extends React.Component { render() { diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-small-multiples-alpha-heterogeneous-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-small-multiples-alpha-heterogeneous-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..c4a9efdc8a2f22b5261cb2463509812e22dfa21d GIT binary patch literal 24651 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 LtE0Jxoqzrh49}TZ literal 0 HcmV?d00001 diff --git a/src/chart_types/xy_chart/utils/series.ts b/src/chart_types/xy_chart/utils/series.ts index f903f38727..45433faa1a 100644 --- a/src/chart_types/xy_chart/utils/series.ts +++ b/src/chart_types/xy_chart/utils/series.ts @@ -19,11 +19,11 @@ import { SeriesIdentifier, SeriesKey } from '../../../common/series_id'; import { ScaleType } from '../../../scales/constants'; -import { GroupBySpec, BinAgg, Direction, XScaleType } from '../../../specs'; +import { BinAgg, Direction, GroupBySpec, XScaleType } from '../../../specs'; import { OrderBy } from '../../../specs/settings'; import { ColorOverrides } from '../../../state/chart_state'; import { Accessor, AccessorFn, getAccessorValue } from '../../../utils/accessor'; -import { Datum, Color, isNil } from '../../../utils/common'; +import { Color, Datum, isNil } from '../../../utils/common'; import { GroupId } from '../../../utils/ids'; import { Logger } from '../../../utils/logger'; import { ColorConfig } from '../../../utils/themes/theme'; @@ -31,8 +31,8 @@ import { groupSeriesByYGroup, isHistogramEnabled, isStackedSpec } from '../domai import { LastValues } from '../state/utils/types'; import { applyFitFunctionToDataSeries } from './fit_function_utils'; import { groupBy } from './group_data_series'; -import { BasicSeriesSpec, SeriesTypes, SeriesSpecs, SeriesNameConfigOptions, StackMode } from './specs'; -import { formatStackedDataSeriesValues, datumXSortPredicate } from './stacked_series_utils'; +import { BasicSeriesSpec, SeriesNameConfigOptions, SeriesSpecs, SeriesTypes, StackMode } from './specs'; +import { datumXSortPredicate, formatStackedDataSeriesValues } from './stacked_series_utils'; /** @internal */ export const SERIES_DELIMITER = ' - '; @@ -115,9 +115,6 @@ export function getSeriesIndex(series: SeriesIdentifier[], target: SeriesIdentif /** * Returns string form of accessor. Uses index when accessor is a function. - * - * @param accessor - * @param index * @internal */ export function getAccessorFieldName(accessor: Accessor | AccessorFn, index: number) { @@ -126,7 +123,7 @@ export function getAccessorFieldName(accessor: Accessor | AccessorFn, index: num /** * Split a dataset into multiple series depending on the accessors. - * Each series is then associated with a key thats belong to its configuration. + * Each series is then associated with a key that belongs to its configuration. * This method removes every data with an invalid x: a string or number value is required * `y` values and `mark` values are casted to number or null. * @internal @@ -329,12 +326,7 @@ function castToNumber(value: any, nonNumericValues: any[]): number | null { return num; } -/** - * Sorts data based on order of xValues - * @param dataSeries - * @param xValues - * @param xScaleType - */ +/** Sorts data based on order of xValues */ const getSortedDataSeries = ( dataSeries: DataSeries[], xValues: Set, @@ -380,14 +372,7 @@ export function getFormattedDataSeries( return [...fittedAndStackedDataSeries, ...nonStackedDataSeries]; } -/** - * - * @param seriesSpecs the map for all the series spec - * @param deselectedDataSeries the array of deselected/hidden data series - * @param enableVislibSeriesSort is optional; if not specified in , - * @param smallMultiples - * @internal - */ +/** @internal */ export function getDataSeriesFromSpecs( seriesSpecs: BasicSeriesSpec[], deselectedDataSeries: SeriesIdentifier[] = [], @@ -518,6 +503,8 @@ function getSortedOrdinalXValues( } } +const BIG_NUMBER = Number.MAX_SAFE_INTEGER; // the sort comparator must yield finite results, can't use infinities + function getSeriesNameFromOptions( options: SeriesNameConfigOptions, { yAccessor, splitAccessors }: XYChartSeriesIdentifier, @@ -530,7 +517,7 @@ function getSeriesNameFromOptions( return ( options.names .slice() - .sort(({ sortIndex: a = Infinity }, { sortIndex: b = Infinity }) => a - b) + .sort(({ sortIndex: a = BIG_NUMBER }, { sortIndex: b = BIG_NUMBER }) => a - b) .map(({ accessor, value, name }) => { const accessorValue = splitAccessors.get(accessor) ?? null; if (accessorValue === value) { @@ -557,41 +544,28 @@ export function getSeriesName( isTooltip: boolean, spec?: BasicSeriesSpec, ): string { - let delimiter = SERIES_DELIMITER; - if (spec && spec.name && typeof spec.name !== 'string') { - let customLabel: string | number | null = null; - if (typeof spec.name === 'function') { - customLabel = spec.name(seriesIdentifier, isTooltip); - } else { - delimiter = spec.name.delimiter ?? delimiter; - customLabel = getSeriesNameFromOptions(spec.name, seriesIdentifier, delimiter); - } - - if (customLabel !== null) { - return customLabel.toString(); - } + const customLabel = + typeof spec?.name === 'function' + ? spec.name(seriesIdentifier, isTooltip) + : typeof spec?.name === 'object' // extract booleans once https://github.com/microsoft/TypeScript/issues/12184 is fixed + ? getSeriesNameFromOptions(spec.name, seriesIdentifier, spec.name.delimiter ?? SERIES_DELIMITER) + : null; + + if (customLabel !== null) { + return customLabel.toString(); } - let name = ''; - const nameKeys = - spec && spec.yAccessors.length > 1 ? seriesIdentifier.seriesKeys : seriesIdentifier.seriesKeys.slice(0, -1); - - // there is one series, the is only one yAccessor, the first part is not null - if (hasSingleSeries || nameKeys.length === 0 || nameKeys[0] == null) { - if (!spec) { - return ''; - } - - if (spec.splitSeriesAccessors && nameKeys.length > 0 && nameKeys[0] != null) { - name = nameKeys.join(delimiter); - } else { - name = typeof spec.name === 'string' ? spec.name : `${spec.id}`; - } - } else { - name = nameKeys.join(delimiter); - } - - return name; + const multipleYAccessors = spec && spec.yAccessors.length > 1; + const nameKeys = multipleYAccessors ? seriesIdentifier.seriesKeys : seriesIdentifier.seriesKeys.slice(0, -1); + const nonZeroLength = nameKeys.length > 0; + + return nonZeroLength && (spec?.splitSeriesAccessors || !hasSingleSeries) + ? nameKeys.join(typeof spec?.name === 'object' ? spec.name.delimiter ?? SERIES_DELIMITER : SERIES_DELIMITER) + : spec === undefined + ? '' + : typeof spec.name === 'string' + ? spec.name + : spec.id; } function getSortIndex({ specSortIndex }: SeriesCollectionValue, total: number): number { @@ -612,12 +586,7 @@ export function getSortedDataSeriesColorsValuesMap( /** * Helper function to get highest override color. - * - * from highest to lowest: `temporary`, `seriesSpec.color` then `persisted` - * - * @param key - * @param customColors - * @param overrides + * From highest to lowest: `temporary`, `seriesSpec.color` then, unless `temporary` is set to `null`, `persisted` */ function getHighestOverride( key: string, @@ -625,32 +594,13 @@ function getHighestOverride( overrides: ColorOverrides, ): Color | undefined { const tempColor: Color | undefined | null = overrides.temporary[key]; - - if (tempColor) { - return tempColor; - } - - const customColor: Color | undefined | null = customColors.get(key); - - if (customColor) { - return customColor; - } - - if (tempColor === null) { - // Use default color when temporary and custom colors are null - return; - } - - return overrides.persisted[key]; + // Unexpected empty `tempColor` string is falsy and falls through, see comment in `export type Color = ...` + // Use default color when temporary and custom colors are null + return tempColor || customColors.get(key) || (tempColor === null ? undefined : overrides.persisted[key]); } /** * Returns color for a series given all color hierarchies - * - * @param seriesCollection - * @param chartColors - * @param customColors - * @param overrides * @internal */ export function getSeriesColors( diff --git a/src/state/chart_state.ts b/src/state/chart_state.ts index 76b70c4ead..58bfd76546 100644 --- a/src/state/chart_state.ts +++ b/src/state/chart_state.ts @@ -26,10 +26,10 @@ import { PrimitiveValue } from '../chart_types/partition_chart/layout/utils/grou import { PartitionState } from '../chart_types/partition_chart/state/chart_state'; import { XYAxisChartState } from '../chart_types/xy_chart/state/chart_state'; import { LegendItem, LegendItemExtraValues } from '../common/legend'; -import { SeriesKey, SeriesIdentifier } from '../common/series_id'; -import { TooltipInfo, TooltipAnchorPosition } from '../components/tooltip/types'; -import { Spec, PointerEvent, DEFAULT_SETTINGS_SPEC } from '../specs'; -import { Color } from '../utils/common'; +import { SeriesIdentifier, SeriesKey } from '../common/series_id'; +import { TooltipAnchorPosition, TooltipInfo } from '../components/tooltip/types'; +import { DEFAULT_SETTINGS_SPEC, PointerEvent, Spec } from '../specs'; +import { Color, keepDistinct } from '../utils/common'; import { Dimensions } from '../utils/dimensions'; import { Logger } from '../utils/logger'; import { Point } from '../utils/point'; @@ -193,7 +193,7 @@ export interface ExternalEventsState { /** @internal */ export interface ColorOverrides { - temporary: Record; + temporary: Record; // null (vs. undefined) means that `overrides.persisted[key]` in `series.ts` not be used persisted: Record; } @@ -295,25 +295,14 @@ export const chartStoreReducer = (chartId: string) => { zIndex: action.zIndex, }; case SPEC_PARSED: - const chartType = findMainChartType(state.specs); - - if (isChartTypeChanged(state, chartType)) { - const internalChartState = initInternalChartState(chartType); - return { - ...state, - specsInitialized: true, - specParsing: false, - chartType, - internalChartState, - }; - } + const chartType = chartTypeFromSpecs(state.specs); return { ...state, specsInitialized: true, specParsing: false, chartType, + internalChartState: state.chartType === chartType ? state.internalChartState : newInternalState(chartType), }; - case SPEC_UNMOUNTED: return { ...state, @@ -321,26 +310,14 @@ export const chartStoreReducer = (chartId: string) => { chartRendered: false, }; case UPSERT_SPEC: - if (!state.specParsing) { - return { - ...state, - specsInitialized: false, - chartRendered: false, - specParsing: true, - specs: { - [DEFAULT_SETTINGS_SPEC.id]: DEFAULT_SETTINGS_SPEC, - [action.spec.id]: action.spec, - }, - }; - } return { ...state, specsInitialized: false, chartRendered: false, - specs: { - ...state.specs, - [action.spec.id]: action.spec, - }, + specParsing: true, + specs: state.specParsing + ? { ...state.specs, [action.spec.id]: action.spec } + : { [DEFAULT_SETTINGS_SPEC.id]: DEFAULT_SETTINGS_SPEC, [action.spec.id]: action.spec }, }; case REMOVE_SPEC: const { [action.id]: specToRemove, ...rest } = state.specs; @@ -369,22 +346,11 @@ export const chartStoreReducer = (chartId: string) => { }; case EXTERNAL_POINTER_EVENT: // discard events from self if any - if (action.event.chartId === chartId) { - return { - ...state, - externalEvents: { - ...state.externalEvents, - pointer: null, - }, - }; - } return { ...state, externalEvents: { ...state.externalEvents, - pointer: { - ...action.event, - }, + pointer: action.event.chartId === chartId ? null : action.event, }, }; case CLEAR_TEMPORARY_COLORS: @@ -407,59 +373,41 @@ export const chartStoreReducer = (chartId: string) => { }, }; case SET_PERSISTED_COLOR: + const { [action.key]: removedPersistedColor, ...otherPersistentColors } = state.colors.persisted; return { ...state, colors: { ...state.colors, - persisted: - action.color !== null - ? { - ...state.colors.persisted, - [action.key]: action.color, - } - : (() => { - const { [action.key]: removed, ...others } = state.colors.persisted; - return others; - })(), + persisted: { + ...otherPersistentColors, + ...(action.color && { [action.key]: action.color }), + }, }, }; default: - if (getInternalIsInitializedSelector(state) !== InitStatus.Initialized) { - return state; - } - return { - ...state, - interactions: interactionsReducer(state.interactions, action, getLegendItemsSelector(state)), - }; + return getInternalIsInitializedSelector(state) === InitStatus.Initialized + ? { + ...state, + interactions: interactionsReducer(state.interactions, action, getLegendItemsSelector(state)), + } + : state; } }; }; -function findMainChartType(specs: SpecList): ChartTypes | null { - const types: Partial> = Object.keys(specs).reduce>>( - (acc, specId) => { - const { chartType } = specs[specId]; - let accumulator = acc[chartType]; - if (accumulator === undefined) { - accumulator = 0; - } else { - accumulator += 1; - } - acc[chartType] = accumulator; - return acc; - }, - {}, - ); - // https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript - const chartTypes = Object.keys(types).filter((type) => type !== ChartTypes.Global); - if (chartTypes.length > 1) { - Logger.warn('Multiple chart type on the same configuration'); +function chartTypeFromSpecs(specs: SpecList): ChartTypes | null { + const nonGlobalTypes = Object.values(specs) + .map((s) => s.chartType) + .filter((type) => type !== ChartTypes.Global) + .filter(keepDistinct); + if (nonGlobalTypes.length !== 1) { + Logger.warn(`${nonGlobalTypes.length === 0 ? 'Zero' : 'Multiple'} chart types in the same configuration`); return null; } - return chartTypes[0] as ChartTypes; + return nonGlobalTypes[0]; } -function initInternalChartState(chartType: ChartTypes | null): InternalChartState | null { +function newInternalState(chartType: ChartTypes | null): InternalChartState | null { switch (chartType) { case ChartTypes.Goal: return new GoalState(); @@ -473,7 +421,3 @@ function initInternalChartState(chartType: ChartTypes | null): InternalChartStat return null; } } - -function isChartTypeChanged(state: GlobalChartState, newChartType: ChartTypes | null) { - return state.chartType !== newChartType; -} diff --git a/src/utils/common.ts b/src/utils/common.ts index f45051fdad..0dda44d877 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -104,7 +104,7 @@ export type Datum = any; // unknown; export type Rotation = 0 | 90 | -90 | 180; /** @public */ export type Rendering = 'canvas' | 'svg'; -export type Color = string; +export type Color = string; // todo static/runtime type it this for proper color string content; several places in the code, and ultimate use, dictate it not be an empty string export type StrokeStyle = Color; // now narrower than string | CanvasGradient | CanvasPattern export const Position = Object.freeze({ @@ -539,3 +539,9 @@ export const getPercentageValue = (ratio: string | number, relativeValue: num return num && !isNaN(num) ? num : defaultValue; }; + +/** + * Predicate function, eg. to be called with [].filter, to keep distinct values + * @example [1, 2, 4, 2, 4, 0, 3, 2].filter(keepDistinct) ==> [1, 2, 4, 0, 3] + */ +export const keepDistinct = (d: T, i: number, a: T[]): boolean => a.indexOf(d) === i; diff --git a/stories/small_multiples/6_heterogeneous_cartesians.tsx b/stories/small_multiples/6_heterogeneous_cartesians.tsx new file mode 100644 index 0000000000..bc70c85827 --- /dev/null +++ b/stories/small_multiples/6_heterogeneous_cartesians.tsx @@ -0,0 +1,164 @@ +/* + * 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 { action } from '@storybook/addon-actions'; +import { boolean } from '@storybook/addon-knobs'; +import { DateTime } from 'luxon'; +import React from 'react'; + +import { + ScaleType, + Position, + Chart, + Axis, + GroupBy, + SmallMultiples, + Settings, + BarSeries, + LineAnnotation, + AnnotationDomainTypes, + LIGHT_THEME, + LineSeries, + AreaSeries, +} from '../../src'; +import { SeededDataGenerator } from '../../src/mocks/utils'; +import { SB_SOURCE_PANEL } from '../utils/storybook'; + +const dg = new SeededDataGenerator(); +const numOfDays = 7; +function generateData() { + return dg.generateGroupedSeries(numOfDays, 2).map((d) => { + return { + ...d, + x: DateTime.fromFormat(`${d.x + 1}`, 'E').toFormat('EEEE'), + y: Math.floor(d.y * 10), + g: d.g === 'a' ? 'new user' : 'existing user', + }; + }); +} +const data1 = generateData(); +const data2 = generateData(); +const data3 = generateData(); + +export const Example = () => { + const marker = ( + + MIN + + ); + const showLegend = boolean('Show Legend', false); + const onElementClick = action('onElementClick'); + + return ( + + + + + + { + return spec.id; + }} + sort="alphaAsc" + /> + + + + + + + ); +}; + +Example.story = { + parameters: { + options: { selectedPanel: SB_SOURCE_PANEL }, + info: { + text: `Similarly to the Vertical Areas example, the above chart shows an example of small multiples technique +that splits our dataset into multiple sub-series horizontally positioned one aside the other. +In this case, the \`\` id is used to specify the horizontal split via the \`splitHorizontally\` prop. + +As for single charts, we can merge and handle multiple data-series together and specify a \`by\` accessor to consider +the specific case. An additional property \`sort\` is available to configure the sorting order of the vertical or +horizontal split. +`, + }, + }, +}; diff --git a/stories/small_multiples/small_multiples.stories.tsx b/stories/small_multiples/small_multiples.stories.tsx index 40b3c66aff..d1d9bc9427 100644 --- a/stories/small_multiples/small_multiples.stories.tsx +++ b/stories/small_multiples/small_multiples.stories.tsx @@ -30,3 +30,4 @@ export { Example as verticalAreas } from './2_vertical_areas'; export { Example as horizontalBars } from './4_horizontal_bars'; export { Example as gridLines } from './3_grid_lines'; export { Example as histogramBars } from './5_histogram_bars'; +export { Example as heterogeneous } from './6_heterogeneous_cartesians'; diff --git a/stories/treemap/10_three_layers.tsx b/stories/treemap/10_three_layers.tsx index c4c7aa2b06..fdba45775f 100644 --- a/stories/treemap/10_three_layers.tsx +++ b/stories/treemap/10_three_layers.tsx @@ -26,6 +26,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; import { palettes } from '../../src/mocks/hierarchical/palettes'; +import { keepDistinct } from '../../src/utils/common'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { countryLookup, productLookup, regionLookup } from '../utils/utils'; @@ -33,7 +34,7 @@ const interpolator = hueInterpolator(palettes.CET2s.map(([r, g, b]) => [r, g, b, const countries = mocks.sunburst .map((d: any) => d.dest) - .filter((d: any, i: number, a: any[]) => a.indexOf(d) === i) + .filter(keepDistinct) .sort() .reverse();