Skip to content

Commit

Permalink
feat(partition): legend hover options (opensearch-project#978)
Browse files Browse the repository at this point in the history
  • Loading branch information
monfera authored Jan 19, 2021
1 parent 0248ad6 commit acd1339
Show file tree
Hide file tree
Showing 31 changed files with 347 additions and 80 deletions.
2 changes: 1 addition & 1 deletion packages/osd-charts/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ module.exports = {
'no-bitwise': 0,
'no-void': 0,
yoda: 0,
'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],
'@typescript-eslint/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],
'no-restricted-globals': 0,
'no-case-declarations': 0,
'no-return-await': 0,
Expand Down
16 changes: 15 additions & 1 deletion packages/osd-charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,19 @@ export interface LegendColorPickerProps {
// @public (undocumented)
export type LegendItemListener = (series: SeriesIdentifier | null) => void;

// @public (undocumented)
export const LegendStrategy: Readonly<{
Node: "node";
Path: "path";
KeyInLayer: "keyInLayer";
Key: "key";
NodeWithDescendants: "nodeWithDescendants";
PathWithDescendants: "pathWithDescendants";
}>;

// @public (undocumented)
export type LegendStrategy = $Values<typeof LegendStrategy>;

// Warning: (ae-missing-release-tag) "LegendStyle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -1605,6 +1618,7 @@ export interface SettingsSpec extends Spec {
legendColorPicker?: LegendColorPicker;
legendMaxDepth: number;
legendPosition: Position;
legendStrategy?: LegendStrategy;
minBrushDelta?: number;
noResults?: ComponentType | ReactChild;
// (undocumented)
Expand Down Expand Up @@ -1965,7 +1979,7 @@ export type YDomainRange = YDomainBase & DomainRange;
// src/chart_types/partition_chart/layout/types/config_types.ts:128:5 - (ae-forgotten-export) The symbol "TimeMs" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/layout/types/config_types.ts:129:5 - (ae-forgotten-export) The symbol "AnimKeyframe" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/specs/index.ts:48:13 - (ae-forgotten-export) The symbol "NodeColorAccessor" needs to be exported by the entry point index.d.ts
// src/commons/series_id.ts:39:3 - (ae-forgotten-export) The symbol "SeriesKey" needs to be exported by the entry point index.d.ts
// src/commons/series_id.ts:40:3 - (ae-forgotten-export) The symbol "SeriesKey" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const computeLegendSelector = createCachedSelector(
seriesIdentifier,
isSeriesHidden: deselectedDataSeries.some((dataSeries) => dataSeries.key === seriesIdentifier.key),
isToggleable: true,
path: [{ index: 0, value: seriesIdentifier.key }],
};
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { GlobalChartState } from '../../../../state/chart_state';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getLegendSizeSelector } from '../../../../state/selectors/get_legend_size';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs';
import { Position } from '../../../../utils/commons';
import { isHorizontalLegend } from '../../../../utils/legend';
import { Config } from '../../layout/types/config_types';
import { getHeatmapConfigSelector } from './get_heatmap_config';
import { getHeatmapTableSelector } from './get_heatmap_table';
Expand Down Expand Up @@ -54,7 +54,7 @@ export const getGridHeightParamsSelector = createCachedSelector(
const xAxisHeight = visible ? fontSize : 0;
const totalVerticalPadding = padding * 2;
let legendHeight = 0;
if (showLegend && (legendPosition === Position.Top || legendPosition === Position.Bottom)) {
if (showLegend && isHorizontalLegend(legendPosition)) {
legendHeight = maxLegendHeight ?? legendSize.height;
}
const verticalRemainingSpace = containerHeight - xAxisHeight - totalVerticalPadding - legendHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* under the License.
*/

import { CategoryKey } from '../../../../commons/category';
import { LegendPath } from '../../../../state/actions/legend';
import { Color } from '../../../../utils/commons';
import { config, ValueGetterName } from '../config/config';
import { ArrayNode, HierarchyOfArrays } from '../utils/group_by_rollup';
Expand Down Expand Up @@ -148,13 +150,13 @@ interface SectorGeomSpecY {
y1px: Distance;
}

export type DataName = any; // todo consider narrowing it to eg. primitives
export type DataName = CategoryKey; // todo consider narrowing it to eg. primitives

export interface ShapeTreeNode extends TreeNode, SectorGeomSpecY {
yMidPx: Distance;
depth: number;
sortIndex: number;
path: number[];
path: LegendPath;
dataName: DataName;
value: number;
parent: ArrayNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* under the License.
*/

import { CategoryKey } from '../../../../commons/category';
import { LegendPath } from '../../../../state/actions/legend';
import { Datum } from '../../../../utils/commons';
import { Relation } from '../types/types';

Expand Down Expand Up @@ -46,7 +48,7 @@ export interface ArrayNode extends NodeDescriptor {
[CHILDREN_KEY]: HierarchyOfArrays;
[PARENT_KEY]: ArrayNode;
[SORT_INDEX_KEY]: number;
[PATH_KEY]: number[];
[PATH_KEY]: LegendPath;
}

type HierarchyOfMaps = Map<Key, MapNode>;
Expand All @@ -55,11 +57,12 @@ interface MapNode extends NodeDescriptor {
[PARENT_KEY]?: ArrayNode;
}

export type PrimitiveValue = string | number | null; // there could be more but sufficient for now
type Key = PrimitiveValue;
/** @internal */
export const HIERARCHY_ROOT_KEY: Key = '__root_key__';

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;

type NodeSorter = (a: ArrayEntry, b: ArrayEntry) => number;

export const entryKey = ([key]: ArrayEntry) => key;
Expand Down Expand Up @@ -126,8 +129,8 @@ export function groupByRollup(
});
return p;
}, new Map());
if (reductionMap.get(null) !== void 0) {
statistics.globalAggregate = (reductionMap.get(null) as MapNode)[AGGREGATE_KEY];
if (reductionMap.get(HIERARCHY_ROOT_KEY) !== undefined) {
statistics.globalAggregate = (reductionMap.get(HIERARCHY_ROOT_KEY) as MapNode)[AGGREGATE_KEY];
}
return reductionMap;
}
Expand All @@ -139,11 +142,12 @@ function getRootArrayNode(): ArrayNode {
[DEPTH_KEY]: NaN,
[CHILDREN_KEY]: children,
[INPUT_KEY]: [] as number[],
[PATH_KEY]: [] as number[],
[PATH_KEY]: [] as LegendPath,
[SORT_INDEX_KEY]: 0,
[STATISTICS_KEY]: { globalAggregate: 0 },
};
return { ...bootstrap, [PARENT_KEY]: bootstrap } as ArrayNode; // TS doesn't yet handle bootstrapping but the `Omit` above retains guarantee for all props except `[PARENT_KEY`
(bootstrap as ArrayNode)[PARENT_KEY] = bootstrap as ArrayNode;
return bootstrap as ArrayNode; // TS doesn't yet handle bootstrapping but the `Omit` above retains guarantee for all props except `[PARENT_KEY]`
}

/** @internal */
Expand Down Expand Up @@ -180,9 +184,9 @@ export function mapsToArrays(root: HierarchyOfMaps, sorter: NodeSorter | null):
});
}; // with the current algo, decreasing order is important
const tree = groupByMap(root, getRootArrayNode());
const buildPaths = ([, mapNode]: ArrayEntry, currentPath: number[]) => {
const newPath = [...currentPath, mapNode[SORT_INDEX_KEY]];
mapNode[PATH_KEY] = newPath;
const buildPaths = ([key, mapNode]: ArrayEntry, currentPath: LegendPath) => {
const newPath = [...currentPath, { index: mapNode[SORT_INDEX_KEY], value: key }];
mapNode[PATH_KEY] = newPath; // in-place mutation, so disabled `no-param-reassign`
mapNode.children.forEach((entry) => buildPaths(entry, newPath));
};
buildPaths(tree[0], []);
Expand Down
105 changes: 92 additions & 13 deletions packages/osd-charts/src/chart_types/partition_chart/partition.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { MockSeriesSpec } from '../../mocks/specs';
import { MockStore } from '../../mocks/store';
import { GlobalChartState } from '../../state/chart_state';
import { LegendItemLabel } from '../../state/selectors/get_legend_items_labels';
import { HIERARCHY_ROOT_KEY } from './layout/utils/group_by_rollup';
import { computeLegendSelector } from './state/selectors/compute_legend';
import { getLegendItemsLabels } from './state/selectors/get_legend_items_labels';

Expand Down Expand Up @@ -96,71 +97,104 @@ describe('Retain hierarchy even with arbitrary names', () => {
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 0, value: 'A' },
],
depth: 0,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
},
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 0, value: 'A' },
{ index: 0, value: 'A' },
],
depth: 1,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
},
{
childId: 'B',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'B',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 0, value: 'A' },
{ index: 1, value: 'B' },
],
depth: 1,
label: 'B',
seriesIdentifier: { key: 'B', specId: 'spec1' },
},
{
childId: 'B',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'B',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 1, value: 'B' },
],
depth: 0,
label: 'B',
seriesIdentifier: { key: 'B', specId: 'spec1' },
},
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 1, value: 'B' },
{ index: 0, value: 'A' },
],
depth: 1,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
},
{
childId: 'B',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'B',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 1, value: 'B' },
{ index: 1, value: 'B' },
],
depth: 1,
label: 'B',
seriesIdentifier: { key: 'B', specId: 'spec1' },
},
{
childId: 'C',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'C',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 2, value: 'C' },
],
depth: 0,
label: 'C',
seriesIdentifier: { key: 'C', specId: 'spec1' },
},
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 2, value: 'C' },
{ index: 0, value: 'A' },
],
depth: 1,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
},
{
childId: 'B',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'B',
path: [
{ index: 0, value: HIERARCHY_ROOT_KEY },
{ index: 2, value: 'C' },
{ index: 1, value: 'B' },
],
depth: 1,
label: 'B',
seriesIdentifier: { key: 'B', specId: 'spec1' },
Expand All @@ -174,15 +208,38 @@ describe('Retain hierarchy even with arbitrary names', () => {
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{
index: 0,
value: HIERARCHY_ROOT_KEY,
},
{
index: 0,
value: 'A',
},
],
depth: 0,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
},
{
childId: 'A',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'A',
path: [
{
index: 0,
value: HIERARCHY_ROOT_KEY,
},
{
index: 0,
value: 'A',
},
{
index: 0,
value: 'A',
},
],

depth: 1,
label: 'A',
seriesIdentifier: { key: 'A', specId: 'spec1' },
Expand All @@ -196,15 +253,37 @@ describe('Retain hierarchy even with arbitrary names', () => {
{
childId: 'C',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'C',
path: [
{
index: 0,
value: HIERARCHY_ROOT_KEY,
},
{
index: 0,
value: 'C',
},
],
depth: 0,
label: 'C',
seriesIdentifier: { key: 'C', specId: 'spec1' },
},
{
childId: 'B',
color: 'rgba(128, 0, 0, 0.5)',
dataName: 'B',
path: [
{
index: 0,
value: HIERARCHY_ROOT_KEY,
},
{
index: 0,
value: 'C',
},
{
index: 0,
value: 'B',
},
],
depth: 1,
label: 'B',
seriesIdentifier: { key: 'B', specId: 'spec1' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,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 { partitionGeometries } from '../../state/selectors/geometries';
import { getHighlightedSectorsSelector } from '../../state/selectors/get_highlighted_shapes';
import { legendHoverHighlightNodes } from '../../state/selectors/get_highlighted_shapes';
import { HighlighterComponent, HighlighterProps, DEFAULT_PROPS } from './highlighter';

const legendMapStateToProps = (state: GlobalChartState): HighlighterProps => {
Expand All @@ -38,7 +38,7 @@ const legendMapStateToProps = (state: GlobalChartState): HighlighterProps => {
config: { partitionLayout },
} = partitionGeometries(state);

const geometries = getHighlightedSectorsSelector(state);
const geometries = legendHoverHighlightNodes(state);
const canvasDimension = getChartContainerDimensionsSelector(state);
return {
chartId,
Expand Down
Loading

0 comments on commit acd1339

Please sign in to comment.