From d78d1ce9d16abc4c9f5c7469a7adb5ade02dcae4 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 28 Jan 2021 21:50:19 +0100 Subject: [PATCH] refactor(partition): improving on chart events and callbacks (#991) * feat: add more metadata for event handlers * chore: api update and addition of property documentation * chore: added model key --- .playground/playground.tsx | 2 +- api/charts.api.md | 27 ++++++++--- docs/0-Intro/1-Overview.mdx | 4 +- .../state/selectors/picked_shapes.ts | 3 ++ .../partition_chart/layout/config/config.ts | 21 +++++---- .../partition_chart/layout/types/types.ts | 15 ++++++ .../layout/types/viewmodel_types.ts | 4 +- .../layout/utils/group_by_rollup.ts | 14 ++++-- .../layout/viewmodel/viewmodel.ts | 6 +-- .../renderer/canvas/partition.tsx | 3 +- .../partition_chart/state/chart_state.tsx | 9 ++-- .../state/selectors/compute_legend.ts | 4 +- .../state/selectors/get_legend_items_extra.ts | 4 +- .../selectors/get_legend_items_labels.ts | 4 +- .../selectors/on_element_click_caller.ts | 4 +- .../state/selectors/on_element_out_caller.ts | 4 +- .../state/selectors/on_element_over_caller.ts | 4 +- .../{pie_spec.ts => partition_spec.ts} | 4 +- .../state/selectors/picked_shapes.test.ts | 47 +++++++++++++++++-- .../state/selectors/picked_shapes.ts | 44 +++++++++++------ .../state/selectors/tooltip.ts | 4 +- src/common/category.ts | 3 ++ src/index.ts | 4 ++ src/specs/settings.tsx | 25 ++++++++++ src/state/actions/legend.ts | 2 + stories/icicle/02_unix_flame.tsx | 4 ++ stories/legend/10_sunburst.tsx | 5 +- stories/stylings/20_partition_background.tsx | 5 +- stories/sunburst/15_single_sunburst.tsx | 5 +- stories/sunburst/26_percentage.tsx | 5 +- stories/sunburst/27_heterogeneous_depth.tsx | 5 +- stories/sunburst/9_sunburst_three_layers.tsx | 5 +- stories/treemap/3_mid_two.tsx | 4 +- stories/treemap/4_two_layer_stress.tsx | 4 +- stories/treemap/5_multicolor.tsx | 7 +-- stories/treemap/6_custom_style.tsx | 7 +-- stories/treemap/7_percentage.tsx | 4 +- stories/treemap/8_groove_text.tsx | 4 +- 38 files changed, 243 insertions(+), 86 deletions(-) rename src/chart_types/partition_chart/state/selectors/{pie_spec.ts => partition_spec.ts} (89%) diff --git a/.playground/playground.tsx b/.playground/playground.tsx index 0d74cc58c2..26d1e2d7b5 100644 --- a/.playground/playground.tsx +++ b/.playground/playground.tsx @@ -19,7 +19,7 @@ import React from 'react'; -import { Example } from '../stories/small_multiples/6_heterogeneous_cartesians'; +import { Example } from '../stories/icicle/02_unix_flame'; export class Playground extends React.Component { render() { diff --git a/api/charts.api.md b/api/charts.api.md index efd696ec70..0ae309dab0 100644 --- a/api/charts.api.md +++ b/api/charts.api.md @@ -324,6 +324,9 @@ export interface BubbleSeriesStyle { point: PointStyle; } +// @public (undocumented) +export type CategoryKey = string; + // Warning: (ae-forgotten-export) The symbol "ChartProps" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "ChartState" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Chart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1021,15 +1024,12 @@ export type HorizontalAlignment = $Values; // @public export type IndexedAccessorFn = UnaryAccessorFn | BinaryAccessorFn; -// Warning: (ae-missing-release-tag) "LayerValue" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export interface LayerValue { - // Warning: (ae-forgotten-export) The symbol "PrimitiveValue" needs to be exported by the entry point index.d.ts - // - // (undocumented) + depth: number; groupByRollup: PrimitiveValue; - // (undocumented) + path: LegendPath; + sortIndex: number; value: number; } @@ -1064,6 +1064,15 @@ export interface LegendColorPickerProps { // @public (undocumented) export type LegendItemListener = (series: SeriesIdentifier | null) => void; +// @public (undocumented) +export type LegendPath = LegendPathElement[]; + +// @public (undocumented) +export type LegendPathElement = { + index: number; + value: CategoryKey; +}; + // @public (undocumented) export const LegendStrategy: Readonly<{ Node: "node"; @@ -1187,6 +1196,9 @@ export function mergeWithDefaultAnnotationRect(config?: Partial countryLookup[d].name, shape: { fillColor: (d) => { - return categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex); + return categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex); }, }, }, @@ -387,7 +387,7 @@ Now if you set the `textContrast` to true as well, these slices also become blac nodeLabel: (d) => countryLookup[d].name, shape: { fillColor: (d) => { - return categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex); + return categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex); }, }, }, diff --git a/src/chart_types/goal_chart/state/selectors/picked_shapes.ts b/src/chart_types/goal_chart/state/selectors/picked_shapes.ts index 5c78e0cabb..b50a65d2e0 100644 --- a/src/chart_types/goal_chart/state/selectors/picked_shapes.ts +++ b/src/chart_types/goal_chart/state/selectors/picked_shapes.ts @@ -49,6 +49,9 @@ export const getPickedShapesLayerValues = createCachedSelector( values.push({ groupByRollup: 'Actual', value: model.actual, + sortIndex: 0, + path: [], + depth: 0, }); return values.reverse(); }); diff --git a/src/chart_types/partition_chart/layout/config/config.ts b/src/chart_types/partition_chart/layout/config/config.ts index 74fdae77a3..6b1c8bab9d 100644 --- a/src/chart_types/partition_chart/layout/config/config.ts +++ b/src/chart_types/partition_chart/layout/config/config.ts @@ -18,17 +18,22 @@ */ import { Config, PartitionLayout, Numeric } from '../types/config_types'; -import { FONT_STYLES, FONT_VARIANTS } from '../types/types'; +import { FONT_STYLES, FONT_VARIANTS, MODEL_KEY } from '../types/types'; import { ShapeTreeNode } from '../types/viewmodel_types'; import { GOLDEN_RATIO, TAU } from '../utils/constants'; import { AGGREGATE_KEY, STATISTICS_KEY } from '../utils/group_by_rollup'; -const log10 = Math.log(10); +const LOG_10 = Math.log(10); + function significantDigitCount(d: number): number { - let n = Math.abs(parseFloat(String(d).replace('.', ''))); // remove decimal and make positive - if (n == 0) return 0; - while (n != 0 && n % 10 == 0) n /= 10; - return Math.floor(Math.log(n) / log10) + 1; + let n = Math.abs(parseFloat(String(d).replace('.', ''))); + if (n === 0) { + return 0; + } + while (n !== 0 && n % 10 === 0) { + n /= 10; + } + return Math.floor(Math.log(n) / LOG_10) + 1; } export function sumValueGetter(node: ShapeTreeNode): number { @@ -36,11 +41,11 @@ export function sumValueGetter(node: ShapeTreeNode): number { } export function percentValueGetter(node: ShapeTreeNode): number { - return (100 * node[AGGREGATE_KEY]) / node.parent[STATISTICS_KEY].globalAggregate; + return (100 * node[AGGREGATE_KEY]) / node[MODEL_KEY][STATISTICS_KEY].globalAggregate; } export function ratioValueGetter(node: ShapeTreeNode): number { - return node[AGGREGATE_KEY] / node.parent[STATISTICS_KEY].globalAggregate; + return node[AGGREGATE_KEY] / node[MODEL_KEY][STATISTICS_KEY].globalAggregate; } export const VALUE_GETTERS = Object.freeze({ percent: percentValueGetter, ratio: ratioValueGetter } as const); diff --git a/src/chart_types/partition_chart/layout/types/types.ts b/src/chart_types/partition_chart/layout/types/types.ts index 647b4b18a9..9abe93b254 100644 --- a/src/chart_types/partition_chart/layout/types/types.ts +++ b/src/chart_types/partition_chart/layout/types/types.ts @@ -108,3 +108,18 @@ export interface Rectangle extends Origin { export interface Part extends Rectangle { node: ArrayEntry; } + +/** + * It's an unfortunate accident that 'parent' is used both + * - for linking an ArrayNode to a QuadViewModel, and + * - for recursively linking the parent ArrayNode to an ArrayNode (child) in the tree + * + * By extracting out the 'MODEL_KEY', we make the distinction clear, while the API, which depends on this, doesn't + * change. This makes an eventual API change a single-line change, assuming `[MODEL_KEY]` is used where needed, and just there + * + * Todo: + * - replace users' use of `s.parent` with `s[MODEL_KEY]` for the ShapeTreeNode -> ArrayNode access + * - change MODEL_KEY to something other than 'parent' when it's done (might still be breaking change) + */ +/** @public */ +export const MODEL_KEY = 'parent'; diff --git a/src/chart_types/partition_chart/layout/types/viewmodel_types.ts b/src/chart_types/partition_chart/layout/types/viewmodel_types.ts index 9737a1cb5e..da9870fb18 100644 --- a/src/chart_types/partition_chart/layout/types/viewmodel_types.ts +++ b/src/chart_types/partition_chart/layout/types/viewmodel_types.ts @@ -26,7 +26,7 @@ import { VerticalAlignments } from '../viewmodel/constants'; import { LinkLabelsViewModelSpec } from '../viewmodel/link_text_layout'; import { Config } from './config_types'; import { Coordinate, Distance, Pixels, PointObject, PointTuple, PointTuples, Radian } from './geometry_types'; -import { Font } from './types'; +import { Font, MODEL_KEY } from './types'; /** @internal */ export type LinkLabelVM = { @@ -159,7 +159,7 @@ export interface ShapeTreeNode extends TreeNode, SectorGeomSpecY { path: LegendPath; dataName: DataName; value: number; - parent: ArrayNode; + [MODEL_KEY]: ArrayNode; } export type RawTextGetter = (node: ShapeTreeNode) => string; diff --git a/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts b/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts index 9f49e0d273..68fa1ee4d0 100644 --- a/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts +++ b/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts @@ -19,7 +19,7 @@ import { CategoryKey } from '../../../../common/category'; import { LegendPath } from '../../../../state/actions/legend'; -import { Datum } from '../../../../utils/common'; +import { Datum, ValueAccessor } from '../../../../utils/common'; import { Relation } from '../types/types'; export const AGGREGATE_KEY = 'value'; @@ -60,6 +60,7 @@ interface MapNode extends NodeDescriptor { /** @internal */ export const HIERARCHY_ROOT_KEY: Key = '__root_key__'; +/** @public */ export type PrimitiveValue = string | number | null; // there could be more but sufficient for now type Key = CategoryKey; export type Sorter = (a: number, b: number) => number; @@ -88,10 +89,17 @@ export function pathAccessor(n: ArrayEntry) { const ascending: Sorter = (a, b) => a - b; const descending: Sorter = (a, b) => b - a; +/** @public */ +export function getNodeName(node: ArrayNode) { + const index = node[SORT_INDEX_KEY]; + const arrayEntry: ArrayEntry = node[PARENT_KEY][CHILDREN_KEY][index]; + return entryKey(arrayEntry); +} + /** @internal */ export function groupByRollup( keyAccessors: Array<((a: Datum) => Key) | ((a: Datum, i: number) => Key)>, - valueAccessor: (v: any) => any, + valueAccessor: ValueAccessor, { reducer, identity, @@ -108,7 +116,7 @@ export function groupByRollup( const keyCount = keyAccessors.length; let pointer: HierarchyOfMaps = p; keyAccessors.forEach((keyAccessor, i) => { - const key = keyAccessor(n, index); + const key: Key = keyAccessor(n, index); const last = i === keyCount - 1; const node = pointer.get(key); const inputIndices = node?.[INPUT_KEY] ?? []; diff --git a/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts b/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts index e7dd225c2e..08d0c9d690 100644 --- a/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts +++ b/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts @@ -23,7 +23,7 @@ import { percentValueGetter } from '../config/config'; import { meanAngle } from '../geometry'; import { Config, PartitionLayout } from '../types/config_types'; import { Distance, Pixels, PointTuple, Radius } from '../types/geometry_types'; -import { TextMeasure, Part } from '../types/types'; +import { TextMeasure, Part, MODEL_KEY } from '../types/types'; import { nullShapeViewModel, OutsideLinksViewModel, @@ -104,7 +104,7 @@ export function makeQuadViewModel( const layer = layers[node.depth - 1]; const fillColorSpec = layer && layer.shape && layer.shape.fillColor; const fill = fillColorSpec ?? 'rgba(128,0,0,0.5)'; - const shapeFillColor = typeof fill === 'function' ? fill(node, node.sortIndex, node.parent.children) : fill; + const shapeFillColor = typeof fill === 'function' ? fill(node, node.sortIndex, node[MODEL_KEY].children) : fill; const { r, g, b, opacity } = stringToRGB(shapeFillColor); const fillColor = argsToRGBString(r, g, b, opacity * opacityMultiplier); const strokeWidth = sectorLineWidth; @@ -407,7 +407,7 @@ function partToShapeTreeNode(treemapLayout: boolean, innerRadius: Radius, ringTh dataName: entryKey(node), depth: depthAccessor(node), value: aggregateAccessor(node), - parent: parentAccessor(node), + [MODEL_KEY]: parentAccessor(node), sortIndex: sortIndexAccessor(node), path: pathAccessor(node), x0, diff --git a/src/chart_types/partition_chart/renderer/canvas/partition.tsx b/src/chart_types/partition_chart/renderer/canvas/partition.tsx index 45bf58ce70..0b5ddfdc6e 100644 --- a/src/chart_types/partition_chart/renderer/canvas/partition.tsx +++ b/src/chart_types/partition_chart/renderer/canvas/partition.tsx @@ -26,6 +26,7 @@ import { GlobalChartState } from '../../../../state/chart_state'; import { getChartContainerDimensionsSelector } from '../../../../state/selectors/get_chart_container_dimensions'; import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized'; import { Dimensions } from '../../../../utils/dimensions'; +import { MODEL_KEY } from '../../layout/types/types'; import { nullShapeViewModel, QuadViewModel, ShapeViewModel } from '../../layout/types/viewmodel_types'; import { INPUT_KEY } from '../../layout/utils/group_by_rollup'; import { partitionGeometries } from '../../state/selectors/geometries'; @@ -114,7 +115,7 @@ class PartitionComponent extends React.Component { const pickedShapes: Array = picker(x, y); const datumIndices = new Set(); pickedShapes.forEach((shape) => { - const node = shape.parent; + const node = shape[MODEL_KEY]; const shapeNode = node.children.find(([key]) => key === shape.dataName); if (shapeNode) { const indices = shapeNode[1][INPUT_KEY] || []; diff --git a/src/chart_types/partition_chart/state/chart_state.tsx b/src/chart_types/partition_chart/state/chart_state.tsx index eafc5bf9d6..7154c51438 100644 --- a/src/chart_types/partition_chart/state/chart_state.tsx +++ b/src/chart_types/partition_chart/state/chart_state.tsx @@ -35,7 +35,7 @@ import { isTooltipVisibleSelector } from './selectors/is_tooltip_visible'; import { createOnElementClickCaller } from './selectors/on_element_click_caller'; import { createOnElementOutCaller } from './selectors/on_element_out_caller'; import { createOnElementOverCaller } from './selectors/on_element_over_caller'; -import { getPieSpec } from './selectors/pie_spec'; +import { getPartitionSpec } from './selectors/partition_spec'; import { getTooltipInfoSelector } from './selectors/tooltip'; /** @internal */ @@ -55,7 +55,7 @@ export class PartitionState implements InternalChartState { } isInitialized(globalState: GlobalChartState) { - return getPieSpec(globalState) !== null ? InitStatus.Initialized : InitStatus.SpecNotInitialized; + return getPartitionSpec(globalState) !== null ? InitStatus.Initialized : InitStatus.SpecNotInitialized; } isBrushAvailable() { @@ -99,7 +99,10 @@ export class PartitionState implements InternalChartState { } isTooltipVisible(globalState: GlobalChartState) { - return { visible: isTooltipVisibleSelector(globalState), isExternal: false }; + return { + visible: isTooltipVisibleSelector(globalState), + isExternal: false, + }; } getTooltipInfo(globalState: GlobalChartState) { diff --git a/src/chart_types/partition_chart/state/selectors/compute_legend.ts b/src/chart_types/partition_chart/state/selectors/compute_legend.ts index 15430684e0..30f6225d4d 100644 --- a/src/chart_types/partition_chart/state/selectors/compute_legend.ts +++ b/src/chart_types/partition_chart/state/selectors/compute_legend.ts @@ -28,11 +28,11 @@ import { isHierarchicalLegend } from '../../../../utils/legend'; import { QuadViewModel } from '../../layout/types/viewmodel_types'; import { map } from '../iterables'; import { partitionGeometries } from './geometries'; -import { getPieSpec } from './pie_spec'; +import { getPartitionSpec } from './partition_spec'; /** @internal */ export const computeLegendSelector = createCachedSelector( - [getPieSpec, getSettingsSpecSelector, partitionGeometries], + [getPartitionSpec, getSettingsSpecSelector, partitionGeometries], (pieSpec, { flatLegend, legendMaxDepth, legendPosition }, { quadViewModel }): LegendItem[] => { if (!pieSpec) { return []; diff --git a/src/chart_types/partition_chart/state/selectors/get_legend_items_extra.ts b/src/chart_types/partition_chart/state/selectors/get_legend_items_extra.ts index e24c4b0c3b..9074bc2b01 100644 --- a/src/chart_types/partition_chart/state/selectors/get_legend_items_extra.ts +++ b/src/chart_types/partition_chart/state/selectors/get_legend_items_extra.ts @@ -26,12 +26,12 @@ import { getChartIdSelector } from '../../../../state/selectors/get_chart_id'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { HierarchyOfArrays, CHILDREN_KEY } from '../../layout/utils/group_by_rollup'; import { PartitionSpec } from '../../specs'; -import { getPieSpec } from './pie_spec'; +import { getPartitionSpec } from './partition_spec'; import { getTree } from './tree'; /** @internal */ export const getLegendItemsExtra = createCachedSelector( - [getPieSpec, getSettingsSpecSelector, getTree], + [getPartitionSpec, getSettingsSpecSelector, getTree], (pieSpec, { legendMaxDepth }, tree): Map => { const legendExtraValues = new Map(); diff --git a/src/chart_types/partition_chart/state/selectors/get_legend_items_labels.ts b/src/chart_types/partition_chart/state/selectors/get_legend_items_labels.ts index 9aedd42cbf..b9a2c6da10 100644 --- a/src/chart_types/partition_chart/state/selectors/get_legend_items_labels.ts +++ b/src/chart_types/partition_chart/state/selectors/get_legend_items_labels.ts @@ -24,12 +24,12 @@ import { LegendItemLabel } from '../../../../state/selectors/get_legend_items_la import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { CHILDREN_KEY, HierarchyOfArrays, HIERARCHY_ROOT_KEY } from '../../layout/utils/group_by_rollup'; import { Layer } from '../../specs'; -import { getPieSpec } from './pie_spec'; +import { getPartitionSpec } from './partition_spec'; import { getTree } from './tree'; /** @internal */ export const getLegendItemsLabels = createCachedSelector( - [getPieSpec, getSettingsSpecSelector, getTree], + [getPartitionSpec, getSettingsSpecSelector, getTree], (pieSpec, { legendMaxDepth }, tree): LegendItemLabel[] => pieSpec ? flatSlicesNames(pieSpec.layers, 0, tree).filter(({ depth }) => depth <= legendMaxDepth) : [], )(getChartIdSelector); diff --git a/src/chart_types/partition_chart/state/selectors/on_element_click_caller.ts b/src/chart_types/partition_chart/state/selectors/on_element_click_caller.ts index 72c8765b46..8415076cc8 100644 --- a/src/chart_types/partition_chart/state/selectors/on_element_click_caller.ts +++ b/src/chart_types/partition_chart/state/selectors/on_element_click_caller.ts @@ -27,8 +27,8 @@ import { GlobalChartState, PointerState } from '../../../../state/chart_state'; import { getLastClickSelector } from '../../../../state/selectors/get_last_click'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { isClicking } from '../../../../state/utils'; +import { getPartitionSpec } from './partition_spec'; import { getPickedShapesLayerValues } from './picked_shapes'; -import { getPieSpec } from './pie_spec'; /** * Will call the onElementClick listener every time the following preconditions are met: @@ -43,7 +43,7 @@ export function createOnElementClickCaller(): (state: GlobalChartState) => void return (state: GlobalChartState) => { if (selector === null && state.chartType === ChartTypes.Partition) { selector = createCachedSelector( - [getPieSpec, getLastClickSelector, getSettingsSpecSelector, getPickedShapesLayerValues], + [getPartitionSpec, getLastClickSelector, getSettingsSpecSelector, getPickedShapesLayerValues], (pieSpec, lastClick: PointerState | null, settings: SettingsSpec, pickedShapes): void => { if (!pieSpec) { return; diff --git a/src/chart_types/partition_chart/state/selectors/on_element_out_caller.ts b/src/chart_types/partition_chart/state/selectors/on_element_out_caller.ts index f6a3a2a58b..1a6b6b1e00 100644 --- a/src/chart_types/partition_chart/state/selectors/on_element_out_caller.ts +++ b/src/chart_types/partition_chart/state/selectors/on_element_out_caller.ts @@ -24,8 +24,8 @@ import { ChartTypes } from '../../..'; import { GlobalChartState } from '../../../../state/chart_state'; import { getChartIdSelector } from '../../../../state/selectors/get_chart_id'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; +import { getPartitionSpec } from './partition_spec'; import { getPickedShapesLayerValues } from './picked_shapes'; -import { getPieSpec } from './pie_spec'; /** * Will call the onElementOut listener every time the following preconditions are met: @@ -39,7 +39,7 @@ export function createOnElementOutCaller(): (state: GlobalChartState) => void { return (state: GlobalChartState) => { if (selector === null && state.chartType === ChartTypes.Partition) { selector = createCachedSelector( - [getPieSpec, getPickedShapesLayerValues, getSettingsSpecSelector], + [getPartitionSpec, getPickedShapesLayerValues, getSettingsSpecSelector], (pieSpec, pickedShapes, settings): void => { if (!pieSpec) { return; diff --git a/src/chart_types/partition_chart/state/selectors/on_element_over_caller.ts b/src/chart_types/partition_chart/state/selectors/on_element_over_caller.ts index a9cf07c49f..092ab38b32 100644 --- a/src/chart_types/partition_chart/state/selectors/on_element_over_caller.ts +++ b/src/chart_types/partition_chart/state/selectors/on_element_over_caller.ts @@ -26,8 +26,8 @@ import { LayerValue } from '../../../../specs'; import { GlobalChartState } from '../../../../state/chart_state'; import { getChartIdSelector } from '../../../../state/selectors/get_chart_id'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; +import { getPartitionSpec } from './partition_spec'; import { getPickedShapesLayerValues } from './picked_shapes'; -import { getPieSpec } from './pie_spec'; function isOverElement(prevPickedShapes: Array> = [], nextPickedShapes: Array>) { if (nextPickedShapes.length === 0) { @@ -66,7 +66,7 @@ export function createOnElementOverCaller(): (state: GlobalChartState) => void { return (state: GlobalChartState) => { if (selector === null && state.chartType === ChartTypes.Partition) { selector = createCachedSelector( - [getPieSpec, getPickedShapesLayerValues, getSettingsSpecSelector], + [getPartitionSpec, getPickedShapesLayerValues, getSettingsSpecSelector], (pieSpec, nextPickedShapes, settings): void => { if (!pieSpec) { return; diff --git a/src/chart_types/partition_chart/state/selectors/pie_spec.ts b/src/chart_types/partition_chart/state/selectors/partition_spec.ts similarity index 89% rename from src/chart_types/partition_chart/state/selectors/pie_spec.ts rename to src/chart_types/partition_chart/state/selectors/partition_spec.ts index bf25d6da6c..aba87e54f3 100644 --- a/src/chart_types/partition_chart/state/selectors/pie_spec.ts +++ b/src/chart_types/partition_chart/state/selectors/partition_spec.ts @@ -18,13 +18,13 @@ */ import { ChartTypes } from '../../..'; -import { SpecTypes } from '../../../../specs/constants'; +import { SpecTypes } from '../../../../specs'; import { GlobalChartState } from '../../../../state/chart_state'; import { getSpecsFromStore } from '../../../../state/utils'; import { PartitionSpec } from '../../specs'; /** @internal */ -export function getPieSpec(state: GlobalChartState): PartitionSpec | null { +export function getPartitionSpec(state: GlobalChartState): PartitionSpec | null { const pieSpecs = getSpecsFromStore(state.specs, ChartTypes.Partition, SpecTypes.Series); return pieSpecs.length > 0 ? pieSpecs[0] : null; } diff --git a/src/chart_types/partition_chart/state/selectors/picked_shapes.test.ts b/src/chart_types/partition_chart/state/selectors/picked_shapes.test.ts index 1fc84f84a7..8352fa2546 100644 --- a/src/chart_types/partition_chart/state/selectors/picked_shapes.test.ts +++ b/src/chart_types/partition_chart/state/selectors/picked_shapes.test.ts @@ -25,6 +25,7 @@ import { updateParentDimensions } from '../../../../state/actions/chart_settings import { onMouseDown, onMouseUp, onPointerMove } from '../../../../state/actions/mouse'; import { upsertSpec, specParsed } from '../../../../state/actions/specs'; import { chartStoreReducer, GlobalChartState } from '../../../../state/chart_state'; +import { HIERARCHY_ROOT_KEY } from '../../layout/utils/group_by_rollup'; import { PartitionSpec } from '../../specs'; import { partitionGeometries } from './geometries'; import { createOnElementClickCaller } from './on_element_click_caller'; @@ -96,8 +97,27 @@ describe('Picked shapes selector', () => { expect(onClickListener.mock.calls[0][0]).toEqual([ [ [ - { groupByRollup: 'b', value: 2 }, - { groupByRollup: 'b', value: 1 }, + { + groupByRollup: 'b', + value: 2, + depth: 1, + sortIndex: 1, + path: [ + { index: 0, value: HIERARCHY_ROOT_KEY }, + { index: 1, value: 'b' }, + ], + }, + { + groupByRollup: 'b', + value: 1, + depth: 2, + sortIndex: 1, + path: [ + { index: 0, value: HIERARCHY_ROOT_KEY }, + { index: 1, value: 'b' }, + { index: 1, value: 'b' }, + ], + }, ], { specId: treemapSpec.id, @@ -128,8 +148,27 @@ describe('Picked shapes selector', () => { expect(onClickListener.mock.calls[0][0]).toEqual([ [ [ - { groupByRollup: 'b', value: 2 }, - { groupByRollup: 'b', value: 1 }, + { + groupByRollup: 'b', + value: 2, + depth: 1, + sortIndex: 1, + path: [ + { index: 0, value: HIERARCHY_ROOT_KEY }, + { index: 1, value: 'b' }, + ], + }, + { + groupByRollup: 'b', + value: 1, + depth: 2, + sortIndex: 1, + path: [ + { index: 0, value: HIERARCHY_ROOT_KEY }, + { index: 1, value: 'b' }, + { index: 1, value: 'b' }, + ], + }, ], { specId: sunburstSpec.id, diff --git a/src/chart_types/partition_chart/state/selectors/picked_shapes.ts b/src/chart_types/partition_chart/state/selectors/picked_shapes.ts index f12b886eb5..05612f826b 100644 --- a/src/chart_types/partition_chart/state/selectors/picked_shapes.ts +++ b/src/chart_types/partition_chart/state/selectors/picked_shapes.ts @@ -21,8 +21,16 @@ import createCachedSelector from 're-reselect'; import { LayerValue } from '../../../../specs'; import { GlobalChartState } from '../../../../state/chart_state'; +import { MODEL_KEY } from '../../layout/types/types'; import { QuadViewModel } from '../../layout/types/viewmodel_types'; -import { PARENT_KEY, DEPTH_KEY, AGGREGATE_KEY, CHILDREN_KEY, SORT_INDEX_KEY } from '../../layout/utils/group_by_rollup'; +import { + AGGREGATE_KEY, + DEPTH_KEY, + getNodeName, + PARENT_KEY, + PATH_KEY, + SORT_INDEX_KEY, +} from '../../layout/utils/group_by_rollup'; import { partitionGeometries } from './geometries'; function getCurrentPointerPosition(state: GlobalChartState) { @@ -50,25 +58,31 @@ export const getPickedShapesLayerValues = createCachedSelector( /** @internal */ export function pickShapesLayerValues(pickedShapes: QuadViewModel[]): Array> { const maxDepth = pickedShapes.reduce((acc, curr) => Math.max(acc, curr.depth), 0); - const elements = pickedShapes - .filter(({ depth }) => depth === maxDepth) - .map>((model) => { + return pickedShapes + .filter(({ depth }) => depth === maxDepth) // eg. lowest layer in a treemap, where layers overlap in screen space; doesn't apply to sunburst/flame + .map>((viewModel) => { const values: Array = []; values.push({ - groupByRollup: model.dataName, - value: model.value, + groupByRollup: viewModel.dataName, + value: viewModel[AGGREGATE_KEY], + depth: viewModel[DEPTH_KEY], + sortIndex: viewModel[SORT_INDEX_KEY], + path: viewModel[PATH_KEY], }); - let parent = model[PARENT_KEY]; - let index = model[PARENT_KEY].sortIndex; - while (parent[DEPTH_KEY] > 0) { - const value = parent[AGGREGATE_KEY]; - const dataName = parent[PARENT_KEY][CHILDREN_KEY][index][0]; - values.push({ groupByRollup: dataName, value }); + let node = viewModel[MODEL_KEY]; + while (node[DEPTH_KEY] > 0) { + const value = node[AGGREGATE_KEY]; + const dataName = getNodeName(node); + values.push({ + groupByRollup: dataName, + value, + depth: node[DEPTH_KEY], + sortIndex: node[SORT_INDEX_KEY], + path: node[PATH_KEY], + }); - parent = parent[PARENT_KEY]; - index = parent[SORT_INDEX_KEY]; + node = node[PARENT_KEY]; } return values.reverse(); }); - return elements; } diff --git a/src/chart_types/partition_chart/state/selectors/tooltip.ts b/src/chart_types/partition_chart/state/selectors/tooltip.ts index d5b5cc99f6..954a5b4044 100644 --- a/src/chart_types/partition_chart/state/selectors/tooltip.ts +++ b/src/chart_types/partition_chart/state/selectors/tooltip.ts @@ -21,8 +21,8 @@ import createCachedSelector from 're-reselect'; import { TooltipInfo } from '../../../../components/tooltip/types'; import { percentValueGetter, sumValueGetter } from '../../layout/config/config'; +import { getPartitionSpec } from './partition_spec'; import { getPickedShapes } from './picked_shapes'; -import { getPieSpec } from './pie_spec'; import { valueGetterFunction } from './scenegraph'; const EMPTY_TOOLTIP = Object.freeze({ @@ -32,7 +32,7 @@ const EMPTY_TOOLTIP = Object.freeze({ /** @internal */ export const getTooltipInfoSelector = createCachedSelector( - [getPieSpec, getPickedShapes], + [getPartitionSpec, getPickedShapes], (pieSpec, pickedShapes): TooltipInfo => { if (!pieSpec) { return EMPTY_TOOLTIP; diff --git a/src/common/category.ts b/src/common/category.ts index 80c63f9fa8..d1a4253cd5 100644 --- a/src/common/category.ts +++ b/src/common/category.ts @@ -25,5 +25,8 @@ * - allow a descriptor object, eg. `{ key: PrimitiveValue, label: string }` * - allow an accessor that operates on the key, and maps it to a label */ + +/** @public */ export type CategoryKey = string; + export type CategoryLabel = string; diff --git a/src/index.ts b/src/index.ts index 6415db1dcd..907598a83d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,6 +34,8 @@ export { XYChartSeriesIdentifier, DataSeriesDatum, FilledValues } from './chart_ export { AnnotationTooltipFormatter, CustomAnnotationTooltip } from './chart_types/xy_chart/annotations/types'; export { GeometryValue } from './utils/geometry'; export { LegendStrategy } from './chart_types/partition_chart/state/selectors/get_highlighted_shapes'; +export { LegendPath, LegendPathElement } from './state/actions/legend'; +export { CategoryKey } from './common/category'; export { Config as PartitionConfig, FillLabelConfig as PartitionFillLabel, @@ -41,6 +43,8 @@ export { } from './chart_types/partition_chart/layout/types/config_types'; export { Config as HeatmapConfig } from './chart_types/heatmap/layout/types/config_types'; export { Layer as PartitionLayer } from './chart_types/partition_chart/specs/index'; +export { PrimitiveValue } from './chart_types/partition_chart/layout/utils/group_by_rollup'; +export { MODEL_KEY } from './chart_types/partition_chart/layout/types/types'; export * from './chart_types/goal_chart/specs/index'; export { Accessor, diff --git a/src/specs/settings.tsx b/src/specs/settings.tsx index 79369b0d68..654b0b9cfe 100644 --- a/src/specs/settings.tsx +++ b/src/specs/settings.tsx @@ -29,6 +29,7 @@ import { SeriesIdentifier } from '../common/series_id'; import { TooltipPortalSettings } from '../components'; import { CustomTooltip } from '../components/tooltip/types'; import { ScaleContinuousType, ScaleOrdinalType } from '../scales'; +import { LegendPath } from '../state/actions/legend'; import { getConnect, specComponentFactory } from '../state/spec_factory'; import { Accessor } from '../utils/accessor'; import { Color, Position, Rendering, Rotation } from '../utils/common'; @@ -39,9 +40,33 @@ import { SeriesCompareFn } from '../utils/series_sort'; import { PartialTheme, Theme } from '../utils/themes/theme'; import { BinAgg, BrushAxis, DEFAULT_SETTINGS_SPEC, Direction, PointerEventType, TooltipType } from './constants'; +/** @public */ export interface LayerValue { + /** + * The category value as retrieved by the `groupByRollup` callback + */ groupByRollup: PrimitiveValue; + /** + * Numerical value of the partition + */ value: number; + /** + * The position index of the sub-partition within its containing partition + */ + sortIndex: number; + /** + * The depth of the partition in terms of the layered partition tree, where + * 0 is root (single, not visualized root of the partitioning tree), + * 1 is pie chart slices and innermost layer of sunburst, or 1st level treemap/flame/icicle breakdown + * 2 and above are increasingly outer layers + * maximum value is on the deepest leaf node + */ + depth: number; + /** + * It contains the full path of the partition node, which is an array of `{index, value}` tuples + * where `index` corresponds to `sortIndex` and `value` corresponds `groupByRollup` + */ + path: LegendPath; } export interface GroupBrushExtent { diff --git a/src/state/actions/legend.ts b/src/state/actions/legend.ts index 3338314cdc..a65a587bf3 100644 --- a/src/state/actions/legend.ts +++ b/src/state/actions/legend.ts @@ -29,8 +29,10 @@ export const ON_LEGEND_ITEM_OUT = 'ON_LEGEND_ITEM_OUT'; /** @internal */ export const ON_TOGGLE_DESELECT_SERIES = 'ON_TOGGLE_DESELECT_SERIES'; +/** @public */ export type LegendPathElement = { index: number; value: CategoryKey }; +/** @public */ export type LegendPath = LegendPathElement[]; interface LegendItemOverAction { diff --git a/stories/icicle/02_unix_flame.tsx b/stories/icicle/02_unix_flame.tsx index 88df8b654a..ed7c1d0ecc 100644 --- a/stories/icicle/02_unix_flame.tsx +++ b/stories/icicle/02_unix_flame.tsx @@ -35,6 +35,10 @@ export const Example = () => { legendStrategy={LegendStrategy.PathWithDescendants} legendMaxDepth={maxDepth} theme={STORYBOOK_LIGHT_THEME} + onElementClick={(e) => { + // eslint-disable-next-line no-console + console.log(e); + }} /> { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -86,7 +87,7 @@ export const Example = () => { nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/stylings/20_partition_background.tsx b/stories/stylings/20_partition_background.tsx index 2db37ff4bc..d0c1243810 100644 --- a/stories/stylings/20_partition_background.tsx +++ b/stories/stylings/20_partition_background.tsx @@ -22,6 +22,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, PartialTheme, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; import { @@ -62,7 +63,7 @@ export const Example = () => { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -70,7 +71,7 @@ export const Example = () => { nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/15_single_sunburst.tsx b/stories/sunburst/15_single_sunburst.tsx index 94400fb77d..e0932e46da 100644 --- a/stories/sunburst/15_single_sunburst.tsx +++ b/stories/sunburst/15_single_sunburst.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; @@ -52,7 +53,7 @@ export const Example = () => ( groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName.replace(/\s/g, '\u00A0'), shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -60,7 +61,7 @@ export const Example = () => ( nodeLabel: (d: any) => countryLookup[d].name.replace(/\s/g, '\u00A0'), shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/26_percentage.tsx b/stories/sunburst/26_percentage.tsx index db53cb0405..78704c719c 100644 --- a/stories/sunburst/26_percentage.tsx +++ b/stories/sunburst/26_percentage.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; @@ -54,7 +55,7 @@ export const Example = () => ( groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -62,7 +63,7 @@ export const Example = () => ( nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/27_heterogeneous_depth.tsx b/stories/sunburst/27_heterogeneous_depth.tsx index 6cf4fa06e0..895aad74af 100644 --- a/stories/sunburst/27_heterogeneous_depth.tsx +++ b/stories/sunburst/27_heterogeneous_depth.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { PrimitiveValue } from '../../src/chart_types/partition_chart/layout/utils/group_by_rollup'; import { mocks } from '../../src/mocks/hierarchical'; @@ -53,7 +54,7 @@ export const Example = () => ( groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: PrimitiveValue) => d !== null && regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -62,7 +63,7 @@ export const Example = () => ( showAccessor: (d: PrimitiveValue) => !(['chn', 'hkg', 'jpn', 'kor'] as PrimitiveValue[]).includes(d), shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/9_sunburst_three_layers.tsx b/stories/sunburst/9_sunburst_three_layers.tsx index 0d3818ae49..c5dff5c55a 100644 --- a/stories/sunburst/9_sunburst_three_layers.tsx +++ b/stories/sunburst/9_sunburst_three_layers.tsx @@ -22,6 +22,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; @@ -55,7 +56,7 @@ export const Example = () => ( nodeLabel: (d: any) => regionLookup[d].regionName, fillLabel: { maximizeFontSize: boolean('Maximize font size layer 2', true) }, shape: { - fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d[MODEL_KEY].sortIndex), }, }, { @@ -64,7 +65,7 @@ export const Example = () => ( fillLabel: { maximizeFontSize: boolean('Maximize font size layer 3', true) }, shape: { fillColor: (d: ShapeTreeNode) => - discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d[MODEL_KEY].parent.sortIndex), }, }, ]} diff --git a/stories/treemap/3_mid_two.tsx b/stories/treemap/3_mid_two.tsx index b668073f81..fe8e5e0ae6 100644 --- a/stories/treemap/3_mid_two.tsx +++ b/stories/treemap/3_mid_two.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { arrayToLookup, hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; @@ -70,7 +71,8 @@ export const Example = () => ( fillColor: (d: ShapeTreeNode) => // primarily, pick color based on parent's index, but then perturb by the index within the parent interpolatorTurbo( - (d.parent.sortIndex + d.sortIndex / d.parent.children.length) / (d.parent.parent.children.length + 1), + (d[MODEL_KEY].sortIndex + d.sortIndex / d[MODEL_KEY].children.length) / + (d[MODEL_KEY].parent.children.length + 1), ), }, }, diff --git a/stories/treemap/4_two_layer_stress.tsx b/stories/treemap/4_two_layer_stress.tsx index 12c38466cc..9e5597512c 100644 --- a/stories/treemap/4_two_layer_stress.tsx +++ b/stories/treemap/4_two_layer_stress.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { arrayToLookup, hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; @@ -74,7 +75,8 @@ export const Example = () => ( fillColor: (d: ShapeTreeNode) => // primarily, pick color based on parent's index, but then perturb by the index within the parent interpolatorTurbo( - (d.parent.sortIndex + d.sortIndex / d.parent.children.length) / (d.parent.parent.children.length + 1), + (d[MODEL_KEY].sortIndex + d.sortIndex / d[MODEL_KEY].children.length) / + (d[MODEL_KEY].parent.children.length + 1), ), }, }, diff --git a/stories/treemap/5_multicolor.tsx b/stories/treemap/5_multicolor.tsx index 487562423f..3ba1a4edd1 100644 --- a/stories/treemap/5_multicolor.tsx +++ b/stories/treemap/5_multicolor.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { arrayToLookup, hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; import { countryDimension } from '../../src/mocks/hierarchical/dimension_codes'; @@ -33,10 +34,10 @@ const countryLookup = arrayToLookup((d: Datum) => d.country, countryDimension); // style calcs const interpolatorCET2s = hueInterpolator(palettes.CET2s.map(([r, g, b]) => [r, g, b, 0.7])); -const defaultFillColor = (colorMaker: any) => ({ parent }: any) => { - const root = parent.parent; +const defaultFillColor = (colorMaker: any) => ({ [MODEL_KEY]: model }: any) => { + const root = model.parent; const siblingCountLayer1 = root.children.length; - return colorMaker(parent.sortIndex / (siblingCountLayer1 + 1)); + return colorMaker(model.sortIndex / (siblingCountLayer1 + 1)); }; export const Example = () => ( diff --git a/stories/treemap/6_custom_style.tsx b/stories/treemap/6_custom_style.tsx index 4395ad9573..83e626ef7b 100644 --- a/stories/treemap/6_custom_style.tsx +++ b/stories/treemap/6_custom_style.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { arrayToLookup } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; import { countryDimension } from '../../src/mocks/hierarchical/dimension_codes'; @@ -29,10 +30,10 @@ import { regionLookup } from '../utils/utils'; const countryLookup = arrayToLookup((d: Datum) => d.country, countryDimension); -const fillColor = ({ parent }: any) => { - const root = parent.parent; +const fillColor = ({ [MODEL_KEY]: model }: any) => { + const root = model.parent; const siblingCountLayer1 = root.children.length; - const i = parent.sortIndex; + const i = model.sortIndex; const shade = Math.pow(0.3 + 0.5 * (i / (siblingCountLayer1 - 1)), 1 / 3); return `rgb(${Math.round(255 * shade)},${Math.round(255 * shade)},${Math.round(255 * shade)})`; }; diff --git a/stories/treemap/7_percentage.tsx b/stories/treemap/7_percentage.tsx index 7e2c5abbc7..a664b9e849 100644 --- a/stories/treemap/7_percentage.tsx +++ b/stories/treemap/7_percentage.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config, percentValueGetter } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { arrayToLookup, hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; @@ -77,7 +78,8 @@ export const Example = () => ( fillColor: (d: ShapeTreeNode) => // primarily, pick color based on parent's index, but then perturb by the index within the parent interpolatorTurbo( - (d.parent.sortIndex + d.sortIndex / d.parent.children.length) / (d.parent.parent.children.length + 1), + (d[MODEL_KEY].sortIndex + d.sortIndex / d[MODEL_KEY].children.length) / + (d[MODEL_KEY].parent.children.length + 1), ), }, }, diff --git a/stories/treemap/8_groove_text.tsx b/stories/treemap/8_groove_text.tsx index dd1d9bc49b..22757b1865 100644 --- a/stories/treemap/8_groove_text.tsx +++ b/stories/treemap/8_groove_text.tsx @@ -22,6 +22,7 @@ import React from 'react'; import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; +import { MODEL_KEY } from '../../src/chart_types/partition_chart/layout/types/types'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { arrayToLookup, hueInterpolator } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; @@ -89,7 +90,8 @@ export const Example = () => ( fillColor: (d: ShapeTreeNode) => // primarily, pick color based on parent's index, but then perturb by the index within the parent interpolatorTurbo( - (d.parent.sortIndex + d.sortIndex / d.parent.children.length) / (d.parent.parent.children.length + 1), + (d[MODEL_KEY].sortIndex + d.sortIndex / d[MODEL_KEY].children.length) / + (d[MODEL_KEY].parent.children.length + 1), ), }, },