Skip to content

Commit

Permalink
[Lens] Waffle - add "show values in legend" configuration property (#…
Browse files Browse the repository at this point in the history
…120471)

* [Lens] Mosaic - add show values in legend configuration property for Waffle chart type

* add tests

* resolve comments

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
alexwizp and kibanamachine authored Dec 7, 2021
1 parent 0ed5cb9 commit 4d2f618
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 60 deletions.
4 changes: 4 additions & 0 deletions x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export const pie: ExpressionFunctionDefinition<
types: ['boolean'],
help: '',
},
showValuesInLegend: {
types: ['boolean'],
help: '',
},
legendPosition: {
types: ['string'],
options: [Position.Top, Position.Right, Position.Bottom, Position.Left],
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/lens/common/expressions/pie_chart/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface SharedPieLayerState {
categoryDisplay: 'default' | 'inside' | 'hide';
legendDisplay: 'default' | 'show' | 'hide';
legendPosition?: 'left' | 'right' | 'top' | 'bottom';
showValuesInLegend?: boolean;
nestedLegend?: boolean;
percentDecimals?: number;
legendMaxLines?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export function PieComponent(
truncateLegend,
hideLabels,
palette,
showValuesInLegend,
} = props.args;
const chartTheme = chartsThemeService.useChartsTheme();
const chartBaseTheme = chartsThemeService.useChartsBaseTheme();
Expand Down Expand Up @@ -315,7 +316,7 @@ export function PieComponent(
(legend.getShowLegendDefault?.(bucketColumns) ?? false)))
}
flatLegend={legend.flat}
showLegendExtra={legend.showValues}
showLegendExtra={showValuesInLegend}
legendPosition={legendPosition || Position.Right}
legendMaxDepth={nestedLegend ? undefined : 1 /* Color is based only on first layer */}
onElementClick={props.interactive ?? true ? onElementClickHandler : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import {
byDataColorPaletteMap,
extractUniqTermsMap,
checkTableForContainsSmallValues,
shouldShowValuesInLegend,
} from './render_helpers';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import type { PieLayerState } from '../../common/expressions';

describe('render helpers', () => {
describe('#getSliceValue', () => {
Expand Down Expand Up @@ -374,4 +376,28 @@ describe('render helpers', () => {
expect(checkTableForContainsSmallValues(datatable, columnId, 1)).toBeFalsy();
});
});

describe('#shouldShowValuesInLegend', () => {
it('should firstly read the state value', () => {
expect(
shouldShowValuesInLegend({ showValuesInLegend: true } as PieLayerState, 'waffle')
).toBeTruthy();

expect(
shouldShowValuesInLegend({ showValuesInLegend: false } as PieLayerState, 'waffle')
).toBeFalsy();
});

it('should read value from meta in case of value in state is undefined', () => {
expect(
shouldShowValuesInLegend({ showValuesInLegend: undefined } as PieLayerState, 'waffle')
).toBeTruthy();

expect(shouldShowValuesInLegend({} as PieLayerState, 'waffle')).toBeTruthy();

expect(
shouldShowValuesInLegend({ showValuesInLegend: undefined } as PieLayerState, 'pie')
).toBeFalsy();
});
});
});
11 changes: 10 additions & 1 deletion x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import type { Datum, LayerValue } from '@elastic/charts';
import type { Datatable, DatatableColumn } from 'src/plugins/expressions/public';
import type { LensFilterEvent } from '../types';
import type { PieChartTypes } from '../../common/expressions/pie_chart/types';
import type { PieChartTypes, PieLayerState } from '../../common/expressions/pie_chart/types';
import type { PaletteDefinition, PaletteOutput } from '../../../../../src/plugins/charts/public';
import { PartitionChartsMeta } from './partition_charts_meta';

export function getSliceValue(d: Datum, metricColumn: DatatableColumn) {
const value = d[metricColumn.id];
Expand Down Expand Up @@ -44,6 +45,14 @@ export const isPartitionShape = (shape: PieChartTypes | string) =>
export const isTreemapOrMosaicShape = (shape: PieChartTypes | string) =>
['treemap', 'mosaic'].includes(shape);

export const shouldShowValuesInLegend = (layer: PieLayerState, shape: PieChartTypes) => {
if ('showValues' in PartitionChartsMeta[shape]?.legend) {
return layer.showValuesInLegend ?? PartitionChartsMeta[shape]?.legend?.showValues ?? true;
}

return false;
};

export const extractUniqTermsMap = (dataTable: Datatable, columnId: string) =>
[...new Set(dataTable.rows.map((item) => item[columnId]))].reduce(
(acc, item, index) => ({
Expand Down
10 changes: 7 additions & 3 deletions x-pack/plugins/lens/public/pie_visualization/to_expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* 2.0.
*/

import { Ast } from '@kbn/interpreter/common';
import { PaletteRegistry } from 'src/plugins/charts/public';
import { Operation, DatasourcePublicAPI } from '../types';
import type { Ast } from '@kbn/interpreter/common';
import type { PaletteRegistry } from 'src/plugins/charts/public';
import type { Operation, DatasourcePublicAPI } from '../types';
import { DEFAULT_PERCENT_DECIMALS } from './constants';
import { shouldShowValuesInLegend } from './render_helpers';

import type { PieVisualizationState } from '../../common/expressions';

export function toExpression(
Expand All @@ -34,6 +36,7 @@ function expressionHelper(
const operations = layer.groups
.map((columnId) => ({ columnId, operation: datasource.getOperationForColumnId(columnId) }))
.filter((o): o is { columnId: string; operation: Operation } => !!o.operation);

if (!layer.metric || !operations.length) {
return null;
}
Expand All @@ -55,6 +58,7 @@ function expressionHelper(
categoryDisplay: [layer.categoryDisplay],
legendDisplay: [layer.legendDisplay],
legendPosition: [layer.legendPosition || 'right'],
showValuesInLegend: [shouldShowValuesInLegend(layer, state.shape)],
percentDecimals: [
state.shape === 'waffle'
? DEFAULT_PERCENT_DECIMALS
Expand Down
131 changes: 76 additions & 55 deletions x-pack/plugins/lens/public/pie_visualization/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import './toolbar.scss';
import React from 'react';
import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiFlexGroup,
Expand All @@ -23,6 +23,7 @@ import type { PieVisualizationState, SharedPieLayerState } from '../../common/ex
import { VisualizationDimensionEditorProps, VisualizationToolbarProps } from '../types';
import { ToolbarPopover, LegendSettingsPopover, useDebouncedValue } from '../shared_components';
import { PalettePicker } from '../shared_components';
import { shouldShowValuesInLegend } from './render_helpers';

const legendOptions: Array<{
value: SharedPieLayerState['legendDisplay'];
Expand Down Expand Up @@ -55,6 +56,67 @@ const legendOptions: Array<{
export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationState>) {
const { state, setState } = props;
const layer = state.layers[0];

const onStateChange = useCallback(
(part: Record<string, unknown>) => {
setState({
...state,
layers: [{ ...layer, ...part }],
});
},
[layer, state, setState]
);

const onCategoryDisplayChange = useCallback(
(option) => onStateChange({ categoryDisplay: option }),
[onStateChange]
);

const onNumberDisplayChange = useCallback(
(option) => onStateChange({ numberDisplay: option }),
[onStateChange]
);

const onPercentDecimalsChange = useCallback(
(option) => {
onStateChange({ percentDecimals: option });
},
[onStateChange]
);

const onLegendDisplayChange = useCallback(
(optionId) => {
onStateChange({ legendDisplay: legendOptions.find(({ id }) => id === optionId)!.value });
},
[onStateChange]
);

const onLegendPositionChange = useCallback(
(id) => onStateChange({ legendPosition: id as Position }),
[onStateChange]
);

const onNestedLegendChange = useCallback(
(id) => onStateChange({ nestedLegend: !layer.nestedLegend }),
[layer, onStateChange]
);

const onTruncateLegendChange = useCallback(() => {
const current = layer.truncateLegend ?? true;
onStateChange({ truncateLegend: !current });
}, [layer, onStateChange]);

const onLegendMaxLinesChange = useCallback(
(val) => onStateChange({ legendMaxLines: val }),
[onStateChange]
);

const onValueInLegendChange = useCallback(() => {
onStateChange({
showValuesInLegend: !shouldShowValuesInLegend(layer, state.shape),
});
}, [layer, state.shape, onStateChange]);

if (!layer) {
return null;
}
Expand Down Expand Up @@ -87,12 +149,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat
compressed
valueOfSelected={layer.categoryDisplay}
options={categoryOptions}
onChange={(option) => {
setState({
...state,
layers: [{ ...layer, categoryDisplay: option }],
});
}}
onChange={onCategoryDisplayChange}
/>
</EuiFormRow>
) : null}
Expand All @@ -110,12 +167,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat
disabled={layer.categoryDisplay === 'hide'}
valueOfSelected={layer.categoryDisplay === 'hide' ? 'hidden' : layer.numberDisplay}
options={numberOptions}
onChange={(option) => {
setState({
...state,
layers: [{ ...layer, numberDisplay: option }],
});
}}
onChange={onNumberDisplayChange}
/>
</EuiFormRow>
) : null}
Expand All @@ -131,59 +183,28 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat
>
<DecimalPlaceSlider
value={layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS}
setValue={(value) => {
setState({
...state,
layers: [{ ...layer, percentDecimals: value }],
});
}}
setValue={onPercentDecimalsChange}
/>
</EuiFormRow>
</ToolbarPopover>
<LegendSettingsPopover
legendOptions={legendOptions}
mode={layer.legendDisplay}
onDisplayChange={(optionId) => {
setState({
...state,
layers: [
{
...layer,
legendDisplay: legendOptions.find(({ id }) => id === optionId)!.value,
},
],
});
}}
onDisplayChange={onLegendDisplayChange}
valueInLegend={shouldShowValuesInLegend(layer, state.shape)}
renderValueInLegendSwitch={
'showValues' in PartitionChartsMeta[state.shape]?.legend ?? false
}
onValueInLegendChange={onValueInLegendChange}
position={layer.legendPosition}
onPositionChange={(id) => {
setState({
...state,
layers: [{ ...layer, legendPosition: id as Position }],
});
}}
onPositionChange={onLegendPositionChange}
renderNestedLegendSwitch
nestedLegend={!!layer.nestedLegend}
onNestedLegendChange={() => {
setState({
...state,
layers: [{ ...layer, nestedLegend: !layer.nestedLegend }],
});
}}
onNestedLegendChange={onNestedLegendChange}
shouldTruncate={layer.truncateLegend ?? true}
onTruncateLegendChange={() => {
const current = layer.truncateLegend ?? true;
setState({
...state,
layers: [{ ...layer, truncateLegend: !current }],
});
}}
onTruncateLegendChange={onTruncateLegendChange}
maxLines={layer?.legendMaxLines}
onMaxLinesChange={(val) => {
setState({
...state,
layers: [{ ...layer, legendMaxLines: val }],
});
}}
onMaxLinesChange={onLegendMaxLinesChange}
/>
</EuiFlexGroup>
);
Expand Down

0 comments on commit 4d2f618

Please sign in to comment.