From 8f6c1aa6599081eab80aba74ab1a264175752221 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 14:25:36 -0700 Subject: [PATCH 1/6] feat(specs): add hideInLegend to spec props --- src/lib/series/specs.ts | 4 ++++ src/specs/area_series.tsx | 1 + src/specs/bar_series.tsx | 1 + src/specs/basic_series.tsx | 1 + src/specs/line_series.tsx | 1 + stories/legend.tsx | 42 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 50 insertions(+) diff --git a/src/lib/series/specs.ts b/src/lib/series/specs.ts index 89ce080139..f6f976a33f 100644 --- a/src/lib/series/specs.ts +++ b/src/lib/series/specs.ts @@ -39,6 +39,10 @@ export interface SeriesSpec { seriesType: 'bar' | 'line' | 'area' | 'basic'; /** Custom colors for series */ customSeriesColors?: CustomSeriesColorsMap; + /** If the series should appear in the legend + * @default false + */ + hideInLegend: boolean; } export type CustomSeriesColorsMap = Map; diff --git a/src/specs/area_series.tsx b/src/specs/area_series.tsx index 34614a6357..5ee5bb716d 100644 --- a/src/specs/area_series.tsx +++ b/src/specs/area_series.tsx @@ -16,6 +16,7 @@ export class AreaSeriesSpecComponent extends PureComponent { xAccessor: 'x', yAccessors: ['y'], yScaleToDataExtent: false, + hideInLegend: false, }; componentDidMount() { const { chartStore, children, ...config } = this.props; diff --git a/src/specs/bar_series.tsx b/src/specs/bar_series.tsx index 5d8927328a..71c4ade8db 100644 --- a/src/specs/bar_series.tsx +++ b/src/specs/bar_series.tsx @@ -16,6 +16,7 @@ export class BarSeriesSpecComponent extends PureComponent { xAccessor: 'x', yAccessors: ['y'], yScaleToDataExtent: false, + hideInLegend: false, }; componentDidMount() { const { chartStore, children, ...config } = this.props; diff --git a/src/specs/basic_series.tsx b/src/specs/basic_series.tsx index 87758709ee..e23a6851b0 100644 --- a/src/specs/basic_series.tsx +++ b/src/specs/basic_series.tsx @@ -16,6 +16,7 @@ export class BasicSeriesSpecComponent extends PureComponent { xAccessor: 'x', yAccessors: ['y'], yScaleToDataExtent: false, + hideInLegend: false, }; componentDidMount() { const { chartStore, children, ...config } = this.props; diff --git a/src/specs/line_series.tsx b/src/specs/line_series.tsx index 5289884502..f345b06f69 100644 --- a/src/specs/line_series.tsx +++ b/src/specs/line_series.tsx @@ -16,6 +16,7 @@ export class LineSeriesSpecComponent extends PureComponent { xAccessor: 'x', yAccessors: ['y'], yScaleToDataExtent: false, + hideInLegend: false, }; componentDidMount() { const { chartStore, children, ...config } = this.props; diff --git a/stories/legend.tsx b/stories/legend.tsx index af65ea5927..55f6f91b1b 100644 --- a/stories/legend.tsx +++ b/stories/legend.tsx @@ -7,6 +7,7 @@ import { Chart, getAxisId, getSpecId, + LineSeries, Position, ScaleType, Settings, @@ -40,6 +41,7 @@ storiesOf('Legend', module) splitSeriesAccessors={['g1', 'g2']} data={TestDatasets.BARCHART_2Y2G} yScaleToDataExtent={false} + hideInLegend={false} /> ); @@ -164,4 +166,44 @@ storiesOf('Legend', module) /> ); + }) + .add('hide legend items by series', () => { + return ( + + + + Number(d).toFixed(2)} + /> + + + + + ); }); From 7588fae68084573aa7650220009844289883bf23 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 14:42:28 -0700 Subject: [PATCH 2/6] refactor(legend): change series visibility property to isSeriesVisible --- src/components/legend.tsx | 8 ++++---- src/components/legend_element.tsx | 10 +++++----- src/lib/series/legend.test.ts | 18 ++++++++++-------- src/lib/series/legend.ts | 6 +++--- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/components/legend.tsx b/src/components/legend.tsx index 04f7737ef8..a9eec954ef 100644 --- a/src/components/legend.tsx +++ b/src/components/legend.tsx @@ -75,11 +75,11 @@ class LegendComponent extends React.Component { onMouseLeave: this.onLegendItemMouseout, }; - const { color, label, isVisible } = item; + const { color, label, isSeriesVisible } = item; return ( - {this.renderLegendElement({ color, label, isVisible }, item.key)} + {this.renderLegendElement({ color, label, isSeriesVisible }, item.key)} ); })} @@ -98,10 +98,10 @@ class LegendComponent extends React.Component { } private renderLegendElement = ( - { color, label, isVisible }: Partial, + { color, label, isSeriesVisible }: Partial, legendItemKey: string, ) => { - const props = { color, label, isVisible, legendItemKey }; + const props = { color, label, isSeriesVisible, legendItemKey }; return ; } diff --git a/src/components/legend_element.tsx b/src/components/legend_element.tsx index 85aba2ab3e..f36b7be950 100644 --- a/src/components/legend_element.tsx +++ b/src/components/legend_element.tsx @@ -21,7 +21,7 @@ interface LegendElementProps { legendItemKey: string; color: string | undefined; label: string | undefined; - isVisible?: boolean; + isSeriesVisible?: boolean; } interface LegendElementState { @@ -52,7 +52,7 @@ class LegendElementComponent extends React.Component - {this.renderVisibilityButton(legendItemKey, isVisible)} + {this.renderVisibilityButton(legendItemKey, isSeriesVisible)} { - const iconType = isVisible ? 'eye' : 'eyeClosed'; + private renderVisibilityButton = (legendItemKey: string, isSeriesVisible: boolean = true) => { + const iconType = isSeriesVisible ? 'eye' : 'eyeClosed'; return ( { @@ -65,7 +67,7 @@ describe('Legends', () => { color: 'red', label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries1a', }, ]; @@ -80,14 +82,14 @@ describe('Legends', () => { color: 'red', label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries1a', }, { color: 'blue', label: 'a - b', value: { colorValues: ['a', 'b'], specId: 'spec1' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries1b', }, ]; @@ -102,14 +104,14 @@ describe('Legends', () => { color: 'red', label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries1a', }, { color: 'green', label: 'spec2', value: { colorValues: [], specId: 'spec2' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries2a', }, ]; @@ -129,7 +131,7 @@ describe('Legends', () => { color: 'violet', label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, - isVisible: true, + isSeriesVisible: true, key: 'colorSeries1a', }, ]; @@ -146,7 +148,7 @@ describe('Legends', () => { const legend = computeLegend(seriesColor, emptyColorMap, specs, 'violet', deselectedDataSeries); - const visibility = [...legend.values()].map((item) => item.isVisible); + const visibility = [...legend.values()].map((item) => item.isSeriesVisible); expect(visibility).toEqual([true, true, true, true]); }); @@ -161,7 +163,7 @@ describe('Legends', () => { const legend = computeLegend(seriesColor, emptyColorMap, specs, 'violet', deselectedDataSeries); - const visibility = [...legend.values()].map((item) => item.isVisible); + const visibility = [...legend.values()].map((item) => item.isSeriesVisible); expect(visibility).toEqual([false, false, true, true]); }); it('returns the right series label for a color series', () => { diff --git a/src/lib/series/legend.ts b/src/lib/series/legend.ts index b455a74d9e..00e3c48eb1 100644 --- a/src/lib/series/legend.ts +++ b/src/lib/series/legend.ts @@ -8,7 +8,7 @@ export interface LegendItem { color: string; label: string; value: DataSeriesColorsValues; - isVisible?: boolean; + isSeriesVisible?: boolean; } export function computeLegend( seriesColor: Map, @@ -24,7 +24,7 @@ export function computeLegend( const color = seriesColorMap.get(key) || defaultColor; const hasSingleSeries = seriesColor.size === 1; const label = getSeriesColorLabel(series.colorValues, hasSingleSeries, spec); - const isVisible = deselectedDataSeries + const isSeriesVisible = deselectedDataSeries ? findDataSeriesByColorValues(deselectedDataSeries, series) < 0 : true; @@ -37,7 +37,7 @@ export function computeLegend( color, label, value: series, - isVisible, + isSeriesVisible, }); }); return legendItems; From 8ad56623fa5b67946e7488618bc1cb53443731e2 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 14:47:31 -0700 Subject: [PATCH 3/6] test: update specs in tests with new property --- src/lib/series/series.test.ts | 6 ++++++ src/state/chart_state.test.ts | 1 + src/state/test/interactions.test.ts | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/lib/series/series.test.ts b/src/lib/series/series.test.ts index 301644a9ab..d79772eec5 100644 --- a/src/lib/series/series.test.ts +++ b/src/lib/series/series.test.ts @@ -181,6 +181,7 @@ describe('Series', () => { yAccessors: ['y'], yScaleToDataExtent: false, data: TestDataset.BARCHART_1Y0G, + hideInLegend: false, }; const spec2: BasicSeriesSpec = { id: getSpecId('spec2'), @@ -193,6 +194,7 @@ describe('Series', () => { stackAccessors: ['x'], yScaleToDataExtent: false, data: TestDataset.BARCHART_2Y0G, + hideInLegend: false, }; seriesSpecs.set(spec1.id, spec1); seriesSpecs.set(spec2.id, spec2); @@ -212,6 +214,7 @@ describe('Series', () => { yAccessors: ['y'], yScaleToDataExtent: false, data: TestDataset.BARCHART_1Y0G, + hideInLegend: false, }; const spec2: BasicSeriesSpec = { id: getSpecId('spec2'), @@ -224,6 +227,7 @@ describe('Series', () => { stackAccessors: ['x'], yScaleToDataExtent: false, data: TestDataset.BARCHART_2Y0G, + hideInLegend: false, }; seriesSpecs.set(spec1.id, spec1); seriesSpecs.set(spec2.id, spec2); @@ -245,6 +249,7 @@ describe('Series', () => { yAccessors: ['y'], yScaleToDataExtent: false, data: TestDataset.BARCHART_1Y0G, + hideInLegend: false, }; const specs = new Map(); @@ -293,6 +298,7 @@ describe('Series', () => { stackAccessors: ['x'], yScaleToDataExtent: false, data: TestDataset.BARCHART_2Y0G, + hideInLegend: false, }; seriesSpecs.set(splitSpec.id, splitSpec); diff --git a/src/state/chart_state.test.ts b/src/state/chart_state.test.ts index 5fb1cf9118..6abc3fede8 100644 --- a/src/state/chart_state.test.ts +++ b/src/state/chart_state.test.ts @@ -25,6 +25,7 @@ describe('Chart Store', () => { yAccessors: ['y'], xScaleType: ScaleType.Linear, yScaleType: ScaleType.Linear, + hideInLegend: false, }; const firstLegendItem = { diff --git a/src/state/test/interactions.test.ts b/src/state/test/interactions.test.ts index c544457c45..7b361bada0 100644 --- a/src/state/test/interactions.test.ts +++ b/src/state/test/interactions.test.ts @@ -22,6 +22,7 @@ const ordinalBarSeries: BarSeriesSpec = { yAccessors: [1], xScaleType: ScaleType.Ordinal, yScaleType: ScaleType.Linear, + hideInLegend: false, }; const linearBarSeries: BarSeriesSpec = { id: SPEC_ID, @@ -33,6 +34,7 @@ const linearBarSeries: BarSeriesSpec = { yAccessors: [1], xScaleType: ScaleType.Linear, yScaleType: ScaleType.Linear, + hideInLegend: false, }; const chartTop = 10; const chartLeft = 10; From 062f2cbe320a63f65bbc09f829b13f5b28a93949 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 15:08:19 -0700 Subject: [PATCH 4/6] feat(legend): hide legend item if spec hideInLegend true --- src/components/_legend.scss | 4 ++++ src/components/legend.tsx | 8 +++++--- src/lib/series/legend.test.ts | 10 ++++++++-- src/lib/series/legend.ts | 7 +++++++ stories/legend.tsx | 5 +++++ 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/components/_legend.scss b/src/components/_legend.scss index f91ba35c19..755b60379a 100644 --- a/src/components/_legend.scss +++ b/src/components/_legend.scss @@ -97,6 +97,10 @@ $elasticChartsLegendMaxHeight: $euiSize * 4; text-decoration: underline; } } + + &.elasticChartsLegendList__item--hidden { + display: none; + } } .elasticChartsLegendListItem__title { diff --git a/src/components/legend.tsx b/src/components/legend.tsx index a9eec954ef..46ba3bd320 100644 --- a/src/components/legend.tsx +++ b/src/components/legend.tsx @@ -68,15 +68,17 @@ class LegendComponent extends React.Component { responsive={false} > {[...legendItems.values()].map((item) => { + const { color, label, isSeriesVisible, isLegendItemVisible } = item; + const legendItemProps = { key: item.key, - className: 'elasticChartsLegendList__item', + className: classNames('elasticChartsLegendList__item', { + 'elasticChartsLegendList__item--hidden': !isLegendItemVisible, + }), onMouseEnter: this.onLegendItemMouseover(item.key), onMouseLeave: this.onLegendItemMouseout, }; - const { color, label, isSeriesVisible } = item; - return ( {this.renderLegendElement({ color, label, isSeriesVisible }, item.key)} diff --git a/src/lib/series/legend.test.ts b/src/lib/series/legend.test.ts index 9a9a6320f3..c2558c9196 100644 --- a/src/lib/series/legend.test.ts +++ b/src/lib/series/legend.test.ts @@ -68,6 +68,7 @@ describe('Legends', () => { label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries1a', }, ]; @@ -83,6 +84,7 @@ describe('Legends', () => { label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries1a', }, { @@ -90,6 +92,7 @@ describe('Legends', () => { label: 'a - b', value: { colorValues: ['a', 'b'], specId: 'spec1' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries1b', }, ]; @@ -105,6 +108,7 @@ describe('Legends', () => { label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries1a', }, { @@ -112,6 +116,7 @@ describe('Legends', () => { label: 'spec2', value: { colorValues: [], specId: 'spec2' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries2a', }, ]; @@ -132,6 +137,7 @@ describe('Legends', () => { label: 'Spec 1 title', value: { colorValues: [], specId: 'spec1' }, isSeriesVisible: true, + isLegendItemVisible: true, key: 'colorSeries1a', }, ]; @@ -150,7 +156,7 @@ describe('Legends', () => { const visibility = [...legend.values()].map((item) => item.isSeriesVisible); - expect(visibility).toEqual([true, true, true, true]); + expect(visibility).toEqual([true, true, true]); }); it('selectively sets series to visible when there are deselectedDataSeries items', () => { seriesColor.set('colorSeries1a', colorValues1a); @@ -164,7 +170,7 @@ describe('Legends', () => { const legend = computeLegend(seriesColor, emptyColorMap, specs, 'violet', deselectedDataSeries); const visibility = [...legend.values()].map((item) => item.isSeriesVisible); - expect(visibility).toEqual([false, false, true, true]); + expect(visibility).toEqual([false, false, true]); }); it('returns the right series label for a color series', () => { let label = getSeriesColorLabel([], true); diff --git a/src/lib/series/legend.ts b/src/lib/series/legend.ts index 00e3c48eb1..663c729cb6 100644 --- a/src/lib/series/legend.ts +++ b/src/lib/series/legend.ts @@ -9,6 +9,7 @@ export interface LegendItem { label: string; value: DataSeriesColorsValues; isSeriesVisible?: boolean; + isLegendItemVisible?: boolean; } export function computeLegend( seriesColor: Map, @@ -21,6 +22,11 @@ export function computeLegend( seriesColor.forEach((series, key) => { const spec = specs.get(series.specId); + if (!spec) { + return; + } + const { hideInLegend } = spec; + const color = seriesColorMap.get(key) || defaultColor; const hasSingleSeries = seriesColor.size === 1; const label = getSeriesColorLabel(series.colorValues, hasSingleSeries, spec); @@ -38,6 +44,7 @@ export function computeLegend( label, value: series, isSeriesVisible, + isLegendItemVisible: !hideInLegend, }); }); return legendItems; diff --git a/stories/legend.tsx b/stories/legend.tsx index 55f6f91b1b..d0a357a0b4 100644 --- a/stories/legend.tsx +++ b/stories/legend.tsx @@ -168,6 +168,9 @@ storiesOf('Legend', module) ); }) .add('hide legend items by series', () => { + const hideBarSeriesInLegend = boolean('hide bar series in legend', false); + const hideLineSeriesInLegend = boolean('hide line series in legend', false); + return ( @@ -192,6 +195,7 @@ storiesOf('Legend', module) yAccessors={['y']} data={[{ x: 0, y: 2 }, { x: 1, y: 7 }, { x: 2, y: 3 }, { x: 3, y: 6 }]} yScaleToDataExtent={false} + hideInLegend={hideBarSeriesInLegend} /> ); From bf051613ab74b56211e0be2228e5f6f342d992f2 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 15:28:41 -0700 Subject: [PATCH 5/6] fix(spec): make hideInLegend optional (defaults to false anyway) --- src/lib/series/specs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/series/specs.ts b/src/lib/series/specs.ts index f6f976a33f..9b3fab873c 100644 --- a/src/lib/series/specs.ts +++ b/src/lib/series/specs.ts @@ -42,7 +42,7 @@ export interface SeriesSpec { /** If the series should appear in the legend * @default false */ - hideInLegend: boolean; + hideInLegend?: boolean; } export type CustomSeriesColorsMap = Map; From 12b5fb1017ba03bf16e0ab408959f8c9823094f1 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 3 Apr 2019 15:43:19 -0700 Subject: [PATCH 6/6] refactor(legend): refactor spec check to occur with label check --- src/lib/series/legend.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/series/legend.ts b/src/lib/series/legend.ts index 663c729cb6..b4983b30d8 100644 --- a/src/lib/series/legend.ts +++ b/src/lib/series/legend.ts @@ -22,11 +22,6 @@ export function computeLegend( seriesColor.forEach((series, key) => { const spec = specs.get(series.specId); - if (!spec) { - return; - } - const { hideInLegend } = spec; - const color = seriesColorMap.get(key) || defaultColor; const hasSingleSeries = seriesColor.size === 1; const label = getSeriesColorLabel(series.colorValues, hasSingleSeries, spec); @@ -34,10 +29,12 @@ export function computeLegend( ? findDataSeriesByColorValues(deselectedDataSeries, series) < 0 : true; - if (!label) { + if (!label || !spec) { return; } + const { hideInLegend } = spec; + legendItems.set(key, { key, color,