From a5c67a7aa8054e8cecd431ee21d38044c6a0dbc5 Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Mon, 22 Nov 2021 18:21:29 +0300 Subject: [PATCH 01/18] [WIP][Lens] Waffle visualization type Closes: #107059 --- .../common/expressions/pie_chart/types.ts | 2 +- .../lens/public/assets/chart_waffle.tsx | 31 ++++ .../public/pie_visualization/constants.ts | 97 ----------- .../partition_charts_meta.ts | 161 ++++++++++++++++++ .../pie_visualization/render_function.tsx | 8 +- .../pie_visualization/render_helpers.ts | 14 +- .../pie_visualization/suggestions.test.ts | 4 +- .../public/pie_visualization/suggestions.ts | 99 +++++++++-- .../lens/public/pie_visualization/toolbar.tsx | 80 ++++----- .../pie_visualization/visualization.tsx | 113 ++++++------ 10 files changed, 385 insertions(+), 224 deletions(-) create mode 100644 x-pack/plugins/lens/public/assets/chart_waffle.tsx create mode 100644 x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts index 00fc7abaa043b..8c9ec4e5a54e7 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts @@ -8,7 +8,7 @@ import type { PaletteOutput } from '../../../../../../src/plugins/charts/common'; import type { LensMultiTable, LayerType } from '../../types'; -export type PieChartTypes = 'donut' | 'pie' | 'treemap' | 'mosaic'; +export type PieChartTypes = 'donut' | 'pie' | 'treemap' | 'mosaic' | 'waffle'; export interface SharedPieLayerState { groups: string[]; diff --git a/x-pack/plugins/lens/public/assets/chart_waffle.tsx b/x-pack/plugins/lens/public/assets/chart_waffle.tsx new file mode 100644 index 0000000000000..b9ee0557faea9 --- /dev/null +++ b/x-pack/plugins/lens/public/assets/chart_waffle.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { EuiIconProps } from '@elastic/eui'; + +export const LensIconChartWaffle = ({ title, titleId, ...props }: Omit<EuiIconProps, 'type'>) => ( + <svg + viewBox="0 0 30 22" + width={30} + height={22} + fill="none" + xmlns="http://www.w3.org/2000/svg" + aria-labelledby={titleId} + {...props} + > + {title ? <title id={titleId} /> : null} + <path + className="lensChartIcon__accent" + d="M16 1a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1V1zM4 13a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1v-2zM17 6a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1V7a1 1 0 00-1-1h-2zM23 0a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1V1a1 1 0 00-1-1h-2zM5 0a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1V1a1 1 0 00-1-1H5zM4 7a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V7zM11 0a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1V1a1 1 0 00-1-1h-2zM10 7a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1V7zM11 12a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 00-1-1h-2zM22 7a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1V7z" + /> + <path + className="lensChartIcon__subdued" + d="M22 13a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1v-2zM4 19a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1v-2zM16 19a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1v-2zM11 18a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 00-1-1h-2zM23 18a1 1 0 00-1 1v2a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 00-1-1h-2zM16 13a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 01-1 1h-2a1 1 0 01-1-1v-2z" + /> + </svg> +); diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index be0afc65aed3b..bfb263b415891 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -5,101 +5,4 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; -import { PartitionLayout } from '@elastic/charts'; -import { LensIconChartDonut } from '../assets/chart_donut'; -import { LensIconChartPie } from '../assets/chart_pie'; -import { LensIconChartTreemap } from '../assets/chart_treemap'; -import { LensIconChartMosaic } from '../assets/chart_mosaic'; - -import type { SharedPieLayerState } from '../../common/expressions'; - -interface CategoryOption { - value: SharedPieLayerState['categoryDisplay']; - inputDisplay: string; -} - -const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { - defaultMessage: 'Proportion', -}); - -const categoryOptions: CategoryOption[] = [ - { - value: 'default', - inputDisplay: i18n.translate('xpack.lens.pieChart.showCategoriesLabel', { - defaultMessage: 'Inside or outside', - }), - }, - { - value: 'inside', - inputDisplay: i18n.translate('xpack.lens.pieChart.fitInsideOnlyLabel', { - defaultMessage: 'Inside only', - }), - }, - { - value: 'hide', - inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', { - defaultMessage: 'Hide labels', - }), - }, -]; - -const categoryOptionsTreemap: CategoryOption[] = [ - { - value: 'default', - inputDisplay: i18n.translate('xpack.lens.pieChart.showTreemapCategoriesLabel', { - defaultMessage: 'Show labels', - }), - }, - { - value: 'hide', - inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', { - defaultMessage: 'Hide labels', - }), - }, -]; - -export const CHART_NAMES = { - donut: { - icon: LensIconChartDonut, - label: i18n.translate('xpack.lens.pie.donutLabel', { - defaultMessage: 'Donut', - }), - partitionType: PartitionLayout.sunburst, - groupLabel, - categoryOptions, - }, - pie: { - icon: LensIconChartPie, - label: i18n.translate('xpack.lens.pie.pielabel', { - defaultMessage: 'Pie', - }), - partitionType: PartitionLayout.sunburst, - groupLabel, - categoryOptions, - }, - treemap: { - icon: LensIconChartTreemap, - label: i18n.translate('xpack.lens.pie.treemaplabel', { - defaultMessage: 'Treemap', - }), - partitionType: PartitionLayout.treemap, - groupLabel, - categoryOptions: categoryOptionsTreemap, - }, - mosaic: { - icon: LensIconChartMosaic, - label: i18n.translate('xpack.lens.pie.mosaiclabel', { - defaultMessage: 'Mosaic', - }), - partitionType: PartitionLayout.mosaic, - groupLabel, - categoryOptions: [] as CategoryOption[], - }, -}; - -export const MAX_PIE_BUCKETS = 3; -export const MAX_TREEMAP_BUCKETS = 2; -export const MAX_MOSAIC_BUCKETS = 2; - export const DEFAULT_PERCENT_DECIMALS = 2; diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts new file mode 100644 index 0000000000000..b88a457cc8f9e --- /dev/null +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { PartitionLayout } from '@elastic/charts'; +import type { EuiIconProps } from '@elastic/eui'; + +import { LensIconChartDonut } from '../assets/chart_donut'; +import { LensIconChartPie } from '../assets/chart_pie'; +import { LensIconChartTreemap } from '../assets/chart_treemap'; +import { LensIconChartMosaic } from '../assets/chart_mosaic'; +import { LensIconChartWaffle } from '../assets/chart_waffle'; + +import type { SharedPieLayerState } from '../../common/expressions'; +import type { PieChartTypes } from '../../common/expressions/pie_chart/types'; + +interface PartitionChartMeta { + icon: ({ title, titleId, ...props }: Omit<EuiIconProps, 'type'>) => JSX.Element; + label: string; + partitionType: PartitionLayout; + groupLabel: string; + categoryOptions: Array<{ + value: SharedPieLayerState['categoryDisplay']; + inputDisplay: string; + }>; + numberOptions: Array<{ + value: SharedPieLayerState['numberDisplay']; + inputDisplay: string; + }>; + maxBuckets: number; + isExperimental?: boolean; + requiredMinDimensionCount?: number; + flatLegend?: boolean; +} + +const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { + defaultMessage: 'Proportion', +}); + +const categoryOptions: PartitionChartMeta['categoryOptions'] = [ + { + value: 'default', + inputDisplay: i18n.translate('xpack.lens.pieChart.showCategoriesLabel', { + defaultMessage: 'Inside or outside', + }), + }, + { + value: 'inside', + inputDisplay: i18n.translate('xpack.lens.pieChart.fitInsideOnlyLabel', { + defaultMessage: 'Inside only', + }), + }, + { + value: 'hide', + inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', { + defaultMessage: 'Hide labels', + }), + }, +]; + +const categoryOptionsTreemap: PartitionChartMeta['categoryOptions'] = [ + { + value: 'default', + inputDisplay: i18n.translate('xpack.lens.pieChart.showTreemapCategoriesLabel', { + defaultMessage: 'Show labels', + }), + }, + { + value: 'hide', + inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', { + defaultMessage: 'Hide labels', + }), + }, +]; + +const numberOptions: PartitionChartMeta['numberOptions'] = [ + { + value: 'hidden', + inputDisplay: i18n.translate('xpack.lens.pieChart.hiddenNumbersLabel', { + defaultMessage: 'Hide from chart', + }), + }, + { + value: 'percent', + inputDisplay: i18n.translate('xpack.lens.pieChart.showPercentValuesLabel', { + defaultMessage: 'Show percent', + }), + }, + { + value: 'value', + inputDisplay: i18n.translate('xpack.lens.pieChart.showFormatterValuesLabel', { + defaultMessage: 'Show value', + }), + }, +]; + +export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { + donut: { + icon: LensIconChartDonut, + label: i18n.translate('xpack.lens.pie.donutLabel', { + defaultMessage: 'Donut', + }), + partitionType: PartitionLayout.sunburst, + groupLabel, + categoryOptions, + numberOptions, + maxBuckets: 3, + }, + pie: { + icon: LensIconChartPie, + label: i18n.translate('xpack.lens.pie.pielabel', { + defaultMessage: 'Pie', + }), + partitionType: PartitionLayout.sunburst, + groupLabel, + categoryOptions, + numberOptions, + maxBuckets: 3, + }, + treemap: { + icon: LensIconChartTreemap, + label: i18n.translate('xpack.lens.pie.treemaplabel', { + defaultMessage: 'Treemap', + }), + partitionType: PartitionLayout.treemap, + groupLabel, + categoryOptions: categoryOptionsTreemap, + numberOptions, + maxBuckets: 2, + }, + mosaic: { + icon: LensIconChartMosaic, + label: i18n.translate('xpack.lens.pie.mosaiclabel', { + defaultMessage: 'Mosaic', + }), + partitionType: PartitionLayout.mosaic, + groupLabel, + categoryOptions: [], + numberOptions, + maxBuckets: 2, + isExperimental: true, + requiredMinDimensionCount: 2, + }, + waffle: { + icon: LensIconChartWaffle, + label: i18n.translate('xpack.lens.pie.wafflelabel', { + defaultMessage: 'Waffle', + }), + partitionType: PartitionLayout.waffle, + groupLabel, + categoryOptions: [], + numberOptions: [], + maxBuckets: 1, + isExperimental: true, + flatLegend: true, + }, +}; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 2bf9827bb976e..f2faed801b797 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -25,7 +25,8 @@ import { import { RenderMode } from 'src/plugins/expressions'; import type { LensFilterEvent } from '../types'; import { VisualizationContainer } from '../visualization_container'; -import { CHART_NAMES, DEFAULT_PERCENT_DECIMALS } from './constants'; +import { DEFAULT_PERCENT_DECIMALS } from './constants'; +import { PartitionChartsMeta } from './partition_charts_meta'; import type { FormatFactory } from '../../common'; import type { PieExpressionProps } from '../../common/expressions'; import { @@ -210,7 +211,7 @@ export function PieComponent( }); const config: RecursivePartial<PartitionConfig> = { - partitionLayout: CHART_NAMES[shape].partitionType, + partitionLayout: PartitionChartsMeta[shape].partitionType, fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, outerSizeRatio: 1, specialFirstInnermostSector: true, @@ -292,7 +293,7 @@ export function PieComponent( id="xpack.lens.pie.pieWithNegativeWarningLabel" defaultMessage="{chartType} charts can't render with negative values." values={{ - chartType: CHART_NAMES[shape].label, + chartType: PartitionChartsMeta[shape].label, }} /> </EuiText> @@ -322,6 +323,7 @@ export function PieComponent( bucketColumns.length > 1 && !isTreemapOrMosaicShape(shape))) } + flatLegend={PartitionChartsMeta[shape].flatLegend} legendPosition={legendPosition || Position.Right} legendMaxDepth={nestedLegend ? undefined : 1 /* Color is based only on first layer */} onElementClick={props.interactive ?? true ? onElementClickHandler : undefined} diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts index bdffacde65639..fa20eb6f20fa8 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts +++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts @@ -39,7 +39,7 @@ export function getFilterContext( } export const isPartitionShape = (shape: PieChartTypes | string) => - ['donut', 'pie', 'treemap', 'mosaic'].includes(shape); + ['donut', 'pie', 'treemap', 'mosaic', 'waffle'].includes(shape); export const isTreemapOrMosaicShape = (shape: PieChartTypes | string) => ['treemap', 'mosaic'].includes(shape); @@ -95,3 +95,15 @@ export const byDataColorPaletteMap = ( }, }; }; + +export const checkTableForContainsSmallValues = ( + dataTable: Datatable, + columnId: string, + minPercentage: number +) => { + const overallSum = dataTable.rows.reduce( + (partialSum, row) => Number(row[columnId]) + partialSum, + 0 + ); + return dataTable.rows.some((row) => (row[columnId] / overallSum) * 100 < minPercentage); +}; diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts index 656d00960766e..30e5c22d2af5e 100644 --- a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts +++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts @@ -304,7 +304,7 @@ describe('suggestions', () => { state: undefined, keptLayerIds: ['first'], }); - expect(currentSuggestions).toHaveLength(4); + expect(currentSuggestions).toHaveLength(5); expect(currentSuggestions.every((s) => s.hide)).toEqual(true); }); @@ -324,7 +324,7 @@ describe('suggestions', () => { state: undefined, keptLayerIds: ['first'], }); - expect(currentSuggestions).toHaveLength(4); + expect(currentSuggestions).toHaveLength(5); expect(currentSuggestions.every((s) => s.hide)).toEqual(true); }); diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts index 30cd63752f420..c0adf7befa1fc 100644 --- a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts +++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts @@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n'; import type { SuggestionRequest, TableSuggestionColumn, VisualizationSuggestion } from '../types'; import { layerTypes } from '../../common'; import type { PieVisualizationState } from '../../common/expressions'; -import { CHART_NAMES, MAX_MOSAIC_BUCKETS, MAX_PIE_BUCKETS, MAX_TREEMAP_BUCKETS } from './constants'; -import { isPartitionShape, isTreemapOrMosaicShape } from './render_helpers'; +import { PartitionChartsMeta } from './partition_charts_meta'; +import { isPartitionShape } from './render_helpers'; +import { PieChartTypes } from '../../common/expressions/pie_chart/types'; function hasIntervalScale(columns: TableSuggestionColumn[]) { return columns.some((col) => col.operation.scale === 'interval'); @@ -30,6 +31,27 @@ function shouldReject({ table, keptLayerIds, state }: SuggestionRequest<PieVisua ); } +function getNewShape( + groups: TableSuggestionColumn[], + subVisualizationId?: PieVisualizationState['shape'] +) { + if (subVisualizationId) { + return subVisualizationId; + } + + let newShape: PieVisualizationState['shape'] | undefined; + + if (groups.length !== 1 && !subVisualizationId) { + newShape = 'pie'; + } + + return newShape ?? 'donut'; +} + +function hasCustomSuggestionsExists(shape: PieChartTypes | string | undefined) { + return shape ? ['treemap', 'waffle', 'mosaic'].includes(shape) : false; +} + export function suggestions({ table, state, @@ -45,7 +67,11 @@ export function suggestions({ const [groups, metrics] = partition(table.columns, (col) => col.operation.isBucketed); - if (metrics.length > 1 || groups.length > Math.max(MAX_PIE_BUCKETS, MAX_TREEMAP_BUCKETS)) { + if ( + metrics.length > 1 || + groups.length > + Math.max(...Object.values(PartitionChartsMeta).map(({ maxBuckets }) => maxBuckets)) + ) { return []; } @@ -61,20 +87,18 @@ export function suggestions({ const results: Array<VisualizationSuggestion<PieVisualizationState>> = []; - if (groups.length <= MAX_PIE_BUCKETS && !isTreemapOrMosaicShape(subVisualizationId!)) { - let newShape: PieVisualizationState['shape'] = - (subVisualizationId as PieVisualizationState['shape']) || 'donut'; - if (groups.length !== 1 && !subVisualizationId) { - newShape = 'pie'; - } - + if ( + groups.length <= PartitionChartsMeta.pie.maxBuckets && + !hasCustomSuggestionsExists(subVisualizationId) + ) { + const newShape = getNewShape(groups, subVisualizationId as PieVisualizationState['shape']); const baseSuggestion: VisualizationSuggestion<PieVisualizationState> = { title: i18n.translate('xpack.lens.pie.suggestionLabel', { defaultMessage: 'As {chartName}', - values: { chartName: CHART_NAMES[newShape].label }, + values: { chartName: PartitionChartsMeta[newShape].label }, description: 'chartName is already translated', }), - score: state && !isTreemapOrMosaicShape(state.shape) ? 0.6 : 0.4, + score: state && !hasCustomSuggestionsExists(state.shape) ? 0.6 : 0.4, state: { shape: newShape, palette: mainPalette || state?.palette, @@ -104,7 +128,7 @@ export function suggestions({ hide: table.changeType === 'reduced' || hasIntervalScale(groups) || - (state && !isTreemapOrMosaicShape(state.shape)), + (state && !hasCustomSuggestionsExists(state.shape)), }; results.push(baseSuggestion); @@ -112,7 +136,7 @@ export function suggestions({ ...baseSuggestion, title: i18n.translate('xpack.lens.pie.suggestionLabel', { defaultMessage: 'As {chartName}', - values: { chartName: CHART_NAMES[newShape === 'pie' ? 'donut' : 'pie'].label }, + values: { chartName: PartitionChartsMeta[newShape === 'pie' ? 'donut' : 'pie'].label }, description: 'chartName is already translated', }), score: 0.1, @@ -125,7 +149,7 @@ export function suggestions({ } if ( - groups.length <= MAX_TREEMAP_BUCKETS && + groups.length <= PartitionChartsMeta.treemap.maxBuckets && (!subVisualizationId || subVisualizationId === 'treemap') ) { results.push({ @@ -174,7 +198,7 @@ export function suggestions({ } if ( - groups.length <= MAX_MOSAIC_BUCKETS && + groups.length <= PartitionChartsMeta.mosaic.maxBuckets && (!subVisualizationId || subVisualizationId === 'mosaic') ) { results.push({ @@ -216,6 +240,49 @@ export function suggestions({ }); } + if ( + groups.length <= PartitionChartsMeta.waffle.maxBuckets && + (!subVisualizationId || subVisualizationId === 'waffle') + ) { + results.push({ + title: i18n.translate('xpack.lens.pie.waffleSuggestionLabel', { + defaultMessage: 'As Waffle', + }), + score: state?.shape === 'waffle' ? 0.7 : 0.5, + state: { + shape: 'waffle', + palette: mainPalette || state?.palette, + layers: [ + state?.layers[0] + ? { + ...state.layers[0], + layerId: table.layerId, + groups: groups.map((col) => col.columnId), + metric: metricColumnId, + categoryDisplay: 'default', + layerType: layerTypes.DATA, + } + : { + layerId: table.layerId, + groups: groups.map((col) => col.columnId), + metric: metricColumnId, + numberDisplay: 'percent', + categoryDisplay: 'default', + legendDisplay: 'default', + nestedLegend: false, + layerType: layerTypes.DATA, + }, + ], + }, + previewIcon: 'bullseye', + hide: + groups.length !== 1 || + table.changeType === 'reduced' || + hasIntervalScale(groups) || + (state && state.shape === 'waffle'), + }); + } + return [...results] .map((suggestion) => ({ ...suggestion, diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 23003a4ec3404..7bb7da9b3223e 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -17,36 +17,13 @@ import { } from '@elastic/eui'; import type { Position } from '@elastic/charts'; import type { PaletteRegistry } from 'src/plugins/charts/public'; -import { DEFAULT_PERCENT_DECIMALS, CHART_NAMES } from './constants'; +import { DEFAULT_PERCENT_DECIMALS } from './constants'; +import { PartitionChartsMeta } from './partition_charts_meta'; import type { PieVisualizationState, SharedPieLayerState } from '../../common/expressions'; import { VisualizationDimensionEditorProps, VisualizationToolbarProps } from '../types'; import { ToolbarPopover, LegendSettingsPopover, useDebouncedValue } from '../shared_components'; import { PalettePicker } from '../shared_components'; -const numberOptions: Array<{ - value: SharedPieLayerState['numberDisplay']; - inputDisplay: string; -}> = [ - { - value: 'hidden', - inputDisplay: i18n.translate('xpack.lens.pieChart.hiddenNumbersLabel', { - defaultMessage: 'Hide from chart', - }), - }, - { - value: 'percent', - inputDisplay: i18n.translate('xpack.lens.pieChart.showPercentValuesLabel', { - defaultMessage: 'Show percent', - }), - }, - { - value: 'value', - inputDisplay: i18n.translate('xpack.lens.pieChart.showFormatterValuesLabel', { - defaultMessage: 'Show value', - }), - }, -]; - const legendOptions: Array<{ value: SharedPieLayerState['legendDisplay']; label: string; @@ -81,6 +58,8 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat if (!layer) { return null; } + const { categoryOptions, numberOptions } = PartitionChartsMeta[state.shape]; + return ( <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" responsive={false}> <ToolbarPopover @@ -91,7 +70,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat groupPosition="left" buttonDataTestSubj="lnsLabelsButton" > - {state.shape && CHART_NAMES[state.shape].categoryOptions.length ? ( + {categoryOptions.length ? ( <EuiFormRow label={i18n.translate('xpack.lens.pieChart.labelPositionLabel', { defaultMessage: 'Position', @@ -102,7 +81,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat <EuiSuperSelect compressed valueOfSelected={layer.categoryDisplay} - options={CHART_NAMES[state.shape].categoryOptions} + options={categoryOptions} onChange={(option) => { setState({ ...state, @@ -112,27 +91,32 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat /> </EuiFormRow> ) : null} - <EuiFormRow - label={i18n.translate('xpack.lens.pieChart.numberLabels', { - defaultMessage: 'Values', - })} - fullWidth - display="columnCompressed" - > - <EuiSuperSelect - compressed - disabled={layer.categoryDisplay === 'hide'} - valueOfSelected={layer.categoryDisplay === 'hide' ? 'hidden' : layer.numberDisplay} - options={numberOptions} - onChange={(option) => { - setState({ - ...state, - layers: [{ ...layer, numberDisplay: option }], - }); - }} - /> - </EuiFormRow> - <EuiHorizontalRule margin="s" /> + + {numberOptions.length ? ( + <EuiFormRow + label={i18n.translate('xpack.lens.pieChart.numberLabels', { + defaultMessage: 'Values', + })} + fullWidth + display="columnCompressed" + > + <EuiSuperSelect + compressed + disabled={layer.categoryDisplay === 'hide'} + valueOfSelected={layer.categoryDisplay === 'hide' ? 'hidden' : layer.numberDisplay} + options={numberOptions} + onChange={(option) => { + setState({ + ...state, + layers: [{ ...layer, numberDisplay: option }], + }); + }} + /> + </EuiFormRow> + ) : null} + + {numberOptions.length + categoryOptions.length ? <EuiHorizontalRule margin="s" /> : null} + <EuiFormRow label={i18n.translate('xpack.lens.pieChart.percentDecimalsLabel', { defaultMessage: 'Maximum decimal places for percent', diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index f72a6e5bef11e..eec82d8ed57af 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -20,8 +20,9 @@ import { toExpression, toPreviewExpression } from './to_expression'; import type { PieLayerState, PieVisualizationState } from '../../common/expressions'; import { layerTypes } from '../../common'; import { suggestions } from './suggestions'; -import { CHART_NAMES, MAX_PIE_BUCKETS, MAX_TREEMAP_BUCKETS } from './constants'; +import { PartitionChartsMeta } from './partition_charts_meta'; import { DimensionEditor, PieToolbar } from './toolbar'; +import { checkTableForContainsSmallValues } from './render_helpers'; function newLayerState(layerId: string): PieLayerState { return { @@ -65,33 +66,13 @@ export const getPieVisualization = ({ }): Visualization<PieVisualizationState> => ({ id: 'lnsPie', - visualizationTypes: [ - { - id: 'donut', - icon: CHART_NAMES.donut.icon, - label: CHART_NAMES.donut.label, - groupLabel: CHART_NAMES.donut.groupLabel, - }, - { - id: 'pie', - icon: CHART_NAMES.pie.icon, - label: CHART_NAMES.pie.label, - groupLabel: CHART_NAMES.pie.groupLabel, - }, - { - id: 'treemap', - icon: CHART_NAMES.treemap.icon, - label: CHART_NAMES.treemap.label, - groupLabel: CHART_NAMES.treemap.groupLabel, - }, - { - id: 'mosaic', - icon: CHART_NAMES.mosaic.icon, - label: CHART_NAMES.mosaic.label, - showExperimentalBadge: true, - groupLabel: CHART_NAMES.mosaic.groupLabel, - }, - ], + visualizationTypes: Object.entries(PartitionChartsMeta).map(([key, meta]) => ({ + id: key, + icon: meta.icon, + label: meta.label, + groupLabel: meta.groupLabel, + showExperimentalBadge: meta.isExperimental, + })), getVisualizationTypeId(state) { return state.shape; @@ -109,7 +90,7 @@ export const getPieVisualization = ({ }, getDescription(state) { - return CHART_NAMES[state.shape] ?? CHART_NAMES.pie; + return PartitionChartsMeta[state.shape] ?? PartitionChartsMeta.pie; }, switchVisualizationType: (visualizationTypeId, state) => ({ @@ -161,25 +142,25 @@ export const getPieVisualization = ({ }; switch (state.shape) { - case 'mosaic': - case 'treemap': + case 'donut': + case 'pie': return { ...baseProps, - groupLabel: i18n.translate('xpack.lens.pie.treemapGroupLabel', { - defaultMessage: 'Group by', + groupLabel: i18n.translate('xpack.lens.pie.sliceGroupLabel', { + defaultMessage: 'Slice by', }), - supportsMoreColumns: sortedColumns.length < MAX_TREEMAP_BUCKETS, - dataTestSubj: 'lnsPie_groupByDimensionPanel', - requiredMinDimensionCount: state.shape === 'mosaic' ? 2 : undefined, + supportsMoreColumns: sortedColumns.length < PartitionChartsMeta.pie.maxBuckets, + dataTestSubj: 'lnsPie_sliceByDimensionPanel', }; default: return { ...baseProps, - groupLabel: i18n.translate('xpack.lens.pie.sliceGroupLabel', { - defaultMessage: 'Slice by', + groupLabel: i18n.translate('xpack.lens.pie.treemapGroupLabel', { + defaultMessage: 'Group by', }), - supportsMoreColumns: sortedColumns.length < MAX_PIE_BUCKETS, - dataTestSubj: 'lnsPie_sliceByDimensionPanel', + supportsMoreColumns: sortedColumns.length < PartitionChartsMeta[state.shape].maxBuckets, + dataTestSubj: 'lnsPie_groupByDimensionPanel', + requiredMinDimensionCount: PartitionChartsMeta[state.shape].requiredMinDimensionCount, }; } }; @@ -271,33 +252,53 @@ export const getPieVisualization = ({ if (state?.layers.length === 0 || !frame.activeData) { return; } - - const metricColumnsWithArrayValues = []; + const warningMessages = []; for (const layer of state.layers) { const { layerId, metric } = layer; - const rows = frame.activeData[layerId] && frame.activeData[layerId].rows; + const rows = frame.activeData[layerId]?.rows; + const numericColumn = frame.activeData[layerId]?.columns.find( + ({ meta }) => meta?.type === 'number' + ); + if (!rows || !metric) { break; } - const columnToLabel = frame.datasourceLayers[layerId].getOperationForColumnId(metric)?.label; + if ( + numericColumn && + state.shape === 'waffle' && + checkTableForContainsSmallValues(frame.activeData[layerId], numericColumn.id, 1) + ) { + warningMessages.push( + <FormattedMessage + id="xpack.lens.pie.smallValuesWarningMessage" + defaultMessage="The received data contains too small values that can be incorrectly visualized in the {shape} chart" + values={{ + shape: <strong>{state.shape}</strong>, + }} + /> + ); + } + + const columnToLabel = frame.datasourceLayers[layerId].getOperationForColumnId(metric)?.label; const hasArrayValues = rows.some((row) => Array.isArray(row[metric])); if (hasArrayValues) { - metricColumnsWithArrayValues.push(columnToLabel || metric); + warningMessages.push( + <FormattedMessage + key={columnToLabel || metric} + id="xpack.lens.pie.arrayValues" + defaultMessage="{label} contains array values. Your visualization may not render as + expected." + values={{ + label: <strong>{columnToLabel || metric}</strong>, + }} + /> + ); } } - return metricColumnsWithArrayValues.map((label) => ( - <FormattedMessage - key={label} - id="xpack.lens.pie.arrayValues" - defaultMessage="{label} contains array values. Your visualization may not render as - expected." - values={{ - label: <strong>{label}</strong>, - }} - /> - )); + + return warningMessages; }, getErrorMessages(state) { From 3a58f8841782cb55236168a97a59a0d8cf67bca6 Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Tue, 23 Nov 2021 18:15:16 +0300 Subject: [PATCH 02/18] add showExtraLegend for waffle --- .../public/pie_visualization/partition_charts_meta.ts | 10 ++++++++-- .../lens/public/pie_visualization/render_function.tsx | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index b88a457cc8f9e..90d55430c5d8a 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -34,7 +34,10 @@ interface PartitionChartMeta { maxBuckets: number; isExperimental?: boolean; requiredMinDimensionCount?: number; - flatLegend?: boolean; + legend?: { + flat?: boolean; + showValues?: boolean; + }; } const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { @@ -156,6 +159,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { numberOptions: [], maxBuckets: 1, isExperimental: true, - flatLegend: true, + legend: { + flat: true, + showValues: true, + }, }, }; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index f2faed801b797..93ed429e07746 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -323,7 +323,8 @@ export function PieComponent( bucketColumns.length > 1 && !isTreemapOrMosaicShape(shape))) } - flatLegend={PartitionChartsMeta[shape].flatLegend} + flatLegend={PartitionChartsMeta[shape].legend?.flat} + showLegendExtra={PartitionChartsMeta[shape].legend?.showValues} legendPosition={legendPosition || Position.Right} legendMaxDepth={nestedLegend ? undefined : 1 /* Color is based only on first layer */} onElementClick={props.interactive ?? true ? onElementClickHandler : undefined} From 7291eefe6df68cc413653e9d084d3fc08ef2629e Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Wed, 24 Nov 2021 14:12:14 +0300 Subject: [PATCH 03/18] add tests --- .../pie_visualization/render_helpers.test.ts | 57 ++++++++ .../pie_visualization/suggestions.test.ts | 129 ++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts index dd27632b36e44..d86500ff8a4fa 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts +++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts @@ -13,6 +13,7 @@ import { getFilterContext, byDataColorPaletteMap, extractUniqTermsMap, + checkTableForContainsSmallValues, } from './render_helpers'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; @@ -317,4 +318,60 @@ describe('render helpers', () => { ); }); }); + + describe('#checkTableForContainsSmallValues', () => { + let datatable: Datatable; + const columnId = 'foo'; + + beforeEach(() => { + datatable = { + rows: [], + } as unknown as Datatable; + }); + + it('should return true if the data contains values less than the target percentage (1)', () => { + datatable.rows = [ + { + [columnId]: 80, + }, + { + [columnId]: 20, + }, + { + [columnId]: 1, + }, + ]; + expect(checkTableForContainsSmallValues(datatable, columnId, 1)).toBeTruthy(); + }); + + it('should return true if the data contains values less than the target percentage (42)', () => { + datatable.rows = [ + { + [columnId]: 58, + }, + { + [columnId]: 42, + }, + { + [columnId]: 1, + }, + ]; + expect(checkTableForContainsSmallValues(datatable, columnId, 42)).toBeTruthy(); + }); + + it('should return false if the data contains values greater than the target percentage', () => { + datatable.rows = [ + { + [columnId]: 22, + }, + { + [columnId]: 56, + }, + { + [columnId]: 12, + }, + ]; + expect(checkTableForContainsSmallValues(datatable, columnId, 1)).toBeFalsy(); + }); + }); }); diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts index 30e5c22d2af5e..92dde282da502 100644 --- a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts +++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts @@ -921,4 +921,133 @@ describe('suggestions', () => { ).toMatchInlineSnapshot(`Array []`); }); }); + + describe('waffle', () => { + it('should reject when currently active and unchanged data', () => { + expect( + suggestions({ + table: { + layerId: 'first', + isMultiRow: true, + columns: [], + changeType: 'unchanged', + }, + state: { + shape: 'waffle', + layers: [ + { + layerId: 'first', + layerType: layerTypes.DATA, + groups: [], + metric: 'a', + + numberDisplay: 'hidden', + categoryDisplay: 'default', + legendDisplay: 'default', + }, + ], + }, + keptLayerIds: ['first'], + }) + ).toHaveLength(0); + }); + + it('waffle type should be added only in case of 1 group', () => { + expect( + suggestions({ + table: { + layerId: 'first', + isMultiRow: true, + columns: [ + { + columnId: 'a', + operation: { label: 'Top 5', dataType: 'string' as DataType, isBucketed: true }, + }, + { + columnId: 'b', + operation: { label: 'Count', dataType: 'number' as DataType, isBucketed: false }, + }, + ], + changeType: 'unchanged', + }, + state: { + shape: 'waffle', + layers: [ + { + layerId: 'first', + layerType: layerTypes.DATA, + groups: ['a', 'b'], + metric: 'c', + + numberDisplay: 'hidden', + categoryDisplay: 'inside', + legendDisplay: 'show', + percentDecimals: 0, + legendMaxLines: 1, + truncateLegend: true, + nestedLegend: true, + }, + ], + }, + keptLayerIds: ['first'], + }).filter(({ hide, state }) => !hide && state.shape === 'waffle') + ).toMatchInlineSnapshot(`Array []`); + }); + + it('waffle type should be added only in case of 1 group (negative test)', () => { + const meta: Parameters<typeof suggestions>[0] = { + table: { + layerId: 'first', + isMultiRow: true, + columns: [ + { + columnId: 'c', + operation: { label: 'Count', dataType: 'number' as DataType, isBucketed: false }, + }, + ], + changeType: 'unchanged', + }, + state: { + shape: 'pie', + layers: [ + { + layerId: 'first', + layerType: layerTypes.DATA, + groups: ['a', 'b'], + metric: 'c', + + numberDisplay: 'hidden', + categoryDisplay: 'inside', + legendDisplay: 'show', + percentDecimals: 0, + legendMaxLines: 1, + truncateLegend: true, + nestedLegend: true, + }, + ], + }, + keptLayerIds: ['first'], + }; + + // test with no group + expect( + suggestions(meta).filter(({ hide, state }) => !hide && state.shape === 'waffle') + ).toMatchInlineSnapshot(`Array []`); + + meta.table.columns.push({ + columnId: 'b', + operation: { label: 'Top 6', dataType: 'string' as DataType, isBucketed: true }, + }); + + meta.table.columns.push({ + columnId: 'c', + operation: { label: 'Top 7', dataType: 'string' as DataType, isBucketed: true }, + }); + + // test with 2 groups + expect( + suggestions(meta).filter(({ hide, state }) => !hide && state.shape === 'waffle') + ).toMatchInlineSnapshot(`Array []`); + }); + }); }); From 34f6cb62487e7b0a8f4040b4902f9407fd5f07a6 Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Thu, 25 Nov 2021 17:12:59 +0300 Subject: [PATCH 04/18] resolved 1 and 5 --- .../pie_visualization/partition_charts_meta.ts | 17 ++++++++++++++++- .../pie_visualization/render_function.tsx | 13 +++++++------ .../public/pie_visualization/visualization.tsx | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 90d55430c5d8a..caeffa5250784 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -17,6 +17,7 @@ import { LensIconChartWaffle } from '../assets/chart_waffle'; import type { SharedPieLayerState } from '../../common/expressions'; import type { PieChartTypes } from '../../common/expressions/pie_chart/types'; +import type { DatatableColumn } from '../../../../../src/plugins/expressions'; interface PartitionChartMeta { icon: ({ title, titleId, ...props }: Omit<EuiIconProps, 'type'>) => JSX.Element; @@ -34,9 +35,10 @@ interface PartitionChartMeta { maxBuckets: number; isExperimental?: boolean; requiredMinDimensionCount?: number; - legend?: { + legend: { flat?: boolean; showValues?: boolean; + getShowLegendDefault?: (bucketColumns: DatatableColumn[]) => boolean; }; } @@ -112,6 +114,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { categoryOptions, numberOptions, maxBuckets: 3, + legend: { + getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, + }, }, pie: { icon: LensIconChartPie, @@ -123,6 +128,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { categoryOptions, numberOptions, maxBuckets: 3, + legend: { + getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, + }, }, treemap: { icon: LensIconChartTreemap, @@ -134,6 +142,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { categoryOptions: categoryOptionsTreemap, numberOptions, maxBuckets: 2, + legend: { + getShowLegendDefault: () => false, + }, }, mosaic: { icon: LensIconChartMosaic, @@ -147,6 +158,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { maxBuckets: 2, isExperimental: true, requiredMinDimensionCount: 2, + legend: { + getShowLegendDefault: () => false, + }, }, waffle: { icon: LensIconChartWaffle, @@ -162,6 +176,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { legend: { flat: true, showValues: true, + getShowLegendDefault: () => true, }, }, }; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 09acce5c47322..b09bc05aa82b8 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -210,8 +210,10 @@ export function PieComponent( }; }); + const { legend, partitionType: partitionLayout, label: chartType } = PartitionChartsMeta[shape]; + const config: RecursivePartial<PartitionConfig> = { - partitionLayout: PartitionChartsMeta[shape].partitionType, + partitionLayout, fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, outerSizeRatio: 1, specialFirstInnermostSector: true, @@ -293,7 +295,7 @@ export function PieComponent( id="xpack.lens.pie.pieWithNegativeWarningLabel" defaultMessage="{chartType} charts can't render with negative values." values={{ - chartType: PartitionChartsMeta[shape].label, + chartType, }} /> </EuiText> @@ -320,11 +322,10 @@ export function PieComponent( !hideLabels && (legendDisplay === 'show' || (legendDisplay === 'default' && - bucketColumns.length > 1 && - !isTreemapOrMosaicShape(shape))) + (legend.getShowLegendDefault?.(bucketColumns) ?? false))) } - flatLegend={PartitionChartsMeta[shape].legend?.flat} - showLegendExtra={PartitionChartsMeta[shape].legend?.showValues} + flatLegend={legend.flat} + showLegendExtra={legend.showValues} legendPosition={legendPosition || Position.Right} legendMaxDepth={nestedLegend ? undefined : 1 /* Color is based only on first layer */} onElementClick={props.interactive ?? true ? onElementClickHandler : undefined} diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index 51698bc3dd43f..0eb56ce090aff 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -276,6 +276,7 @@ export const getPieVisualization = ({ if ( numericColumn && state.shape === 'waffle' && + layer.groups.length && checkTableForContainsSmallValues(frame.activeData[layerId], numericColumn.id, 1) ) { warningMessages.push( From 33ee2beb9d0f04a346a2d1b8ca1e0c6d747f6c27 Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Thu, 25 Nov 2021 17:54:23 +0300 Subject: [PATCH 05/18] resolved 6 --- .../partition_charts_meta.ts | 58 ++++++++++++------- .../public/pie_visualization/to_expression.ts | 6 +- .../lens/public/pie_visualization/toolbar.tsx | 7 ++- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index caeffa5250784..932b9e9500090 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -24,17 +24,20 @@ interface PartitionChartMeta { label: string; partitionType: PartitionLayout; groupLabel: string; - categoryOptions: Array<{ - value: SharedPieLayerState['categoryDisplay']; - inputDisplay: string; - }>; - numberOptions: Array<{ - value: SharedPieLayerState['numberDisplay']; - inputDisplay: string; - }>; maxBuckets: number; isExperimental?: boolean; requiredMinDimensionCount?: number; + toolbarPopover: { + isDisabled?: boolean; + categoryOptions: Array<{ + value: SharedPieLayerState['categoryDisplay']; + inputDisplay: string; + }>; + numberOptions: Array<{ + value: SharedPieLayerState['numberDisplay']; + inputDisplay: string; + }>; + }; legend: { flat?: boolean; showValues?: boolean; @@ -46,7 +49,7 @@ const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { defaultMessage: 'Proportion', }); -const categoryOptions: PartitionChartMeta['categoryOptions'] = [ +const categoryOptions: PartitionChartMeta['toolbarPopover']['categoryOptions'] = [ { value: 'default', inputDisplay: i18n.translate('xpack.lens.pieChart.showCategoriesLabel', { @@ -67,7 +70,7 @@ const categoryOptions: PartitionChartMeta['categoryOptions'] = [ }, ]; -const categoryOptionsTreemap: PartitionChartMeta['categoryOptions'] = [ +const categoryOptionsTreemap: PartitionChartMeta['toolbarPopover']['categoryOptions'] = [ { value: 'default', inputDisplay: i18n.translate('xpack.lens.pieChart.showTreemapCategoriesLabel', { @@ -82,7 +85,7 @@ const categoryOptionsTreemap: PartitionChartMeta['categoryOptions'] = [ }, ]; -const numberOptions: PartitionChartMeta['numberOptions'] = [ +const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [ { value: 'hidden', inputDisplay: i18n.translate('xpack.lens.pieChart.hiddenNumbersLabel', { @@ -111,9 +114,11 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { }), partitionType: PartitionLayout.sunburst, groupLabel, - categoryOptions, - numberOptions, maxBuckets: 3, + toolbarPopover: { + categoryOptions, + numberOptions, + }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, }, @@ -125,9 +130,11 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { }), partitionType: PartitionLayout.sunburst, groupLabel, - categoryOptions, - numberOptions, maxBuckets: 3, + toolbarPopover: { + categoryOptions, + numberOptions, + }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, }, @@ -139,9 +146,11 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { }), partitionType: PartitionLayout.treemap, groupLabel, - categoryOptions: categoryOptionsTreemap, - numberOptions, maxBuckets: 2, + toolbarPopover: { + categoryOptions: categoryOptionsTreemap, + numberOptions, + }, legend: { getShowLegendDefault: () => false, }, @@ -153,14 +162,16 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { }), partitionType: PartitionLayout.mosaic, groupLabel, - categoryOptions: [], - numberOptions, maxBuckets: 2, isExperimental: true, - requiredMinDimensionCount: 2, + toolbarPopover: { + categoryOptions: [], + numberOptions, + }, legend: { getShowLegendDefault: () => false, }, + requiredMinDimensionCount: 2, }, waffle: { icon: LensIconChartWaffle, @@ -169,10 +180,13 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { }), partitionType: PartitionLayout.waffle, groupLabel, - categoryOptions: [], - numberOptions: [], maxBuckets: 1, isExperimental: true, + toolbarPopover: { + isDisabled: true, + categoryOptions: [], + numberOptions: [], + }, legend: { flat: true, showValues: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index fd754906ceb02..e13fbf62708ee 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -55,7 +55,11 @@ function expressionHelper( categoryDisplay: [layer.categoryDisplay], legendDisplay: [layer.legendDisplay], legendPosition: [layer.legendPosition || 'right'], - percentDecimals: [layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS], + percentDecimals: [ + state.shape === 'waffle' + ? DEFAULT_PERCENT_DECIMALS + : layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS, + ], legendMaxLines: [layer.legendMaxLines ?? 1], truncateLegend: [layer.truncateLegend ?? true], nestedLegend: [!!layer.nestedLegend], diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 7bb7da9b3223e..195a72cca9fed 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -58,7 +58,11 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat if (!layer) { return null; } - const { categoryOptions, numberOptions } = PartitionChartsMeta[state.shape]; + const { + categoryOptions, + numberOptions, + isDisabled: isToolbarPopoverDisabled, + } = PartitionChartsMeta[state.shape].toolbarPopover; return ( <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" responsive={false}> @@ -66,6 +70,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat title={i18n.translate('xpack.lens.pieChart.valuesLabel', { defaultMessage: 'Labels', })} + isDisabled={Boolean(isToolbarPopoverDisabled)} type="labels" groupPosition="left" buttonDataTestSubj="lnsLabelsButton" From 76ff6e92ed2084dd55e4b71aa70466b153bfa5d3 Mon Sep 17 00:00:00 2001 From: Alexey Antonov <alexwizp@gmail.com> Date: Wed, 1 Dec 2021 14:17:04 +0300 Subject: [PATCH 06/18] add sortPredicate for waffle chart type --- .../partition_charts_meta.ts | 20 ++++++++++++++++++- .../pie_visualization/render_function.tsx | 14 ++----------- .../public/pie_visualization/suggestions.ts | 10 +++++----- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 932b9e9500090..4f16ab01ba19c 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { PartitionLayout } from '@elastic/charts'; +import { ArrayEntry, PartitionLayout } from '@elastic/charts'; import type { EuiIconProps } from '@elastic/eui'; import { LensIconChartDonut } from '../assets/chart_donut'; @@ -43,6 +43,10 @@ interface PartitionChartMeta { showValues?: boolean; getShowLegendDefault?: (bucketColumns: DatatableColumn[]) => boolean; }; + sortPredicate?: ( + bucketColumns: DatatableColumn[], + sortingMap: Record<string, number> + ) => (node1: ArrayEntry, node2: ArrayEntry) => number; } const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { @@ -172,6 +176,16 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { getShowLegendDefault: () => false, }, requiredMinDimensionCount: 2, + sortPredicate: + (bucketColumns, sortingMap) => + ([name1, node1], [, node2]) => { + // Sorting for first group + if (bucketColumns.length === 1 || (node1.children.length && name1 in sortingMap)) { + return sortingMap[name1]; + } + // Sorting for second group + return node2.value - node1.value; + }, }, waffle: { icon: LensIconChartWaffle, @@ -192,5 +206,9 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { showValues: true, getShowLegendDefault: () => true, }, + sortPredicate: + () => + ([, node1], [, node2]) => + node2.value - node1.value, }, }; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index b09bc05aa82b8..539d69207f5f9 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -127,7 +127,7 @@ export function PieComponent( ); } - let sortingMap: Record<string, number>; + let sortingMap: Record<string, number> = {}; if (shape === 'mosaic') { sortingMap = extractUniqTermsMap(firstTable, bucketColumns[0].id); } @@ -146,17 +146,7 @@ export function PieComponent( return String(d); }, fillLabel, - sortPredicate: - shape === 'mosaic' - ? ([name1, node1], [, node2]) => { - // Sorting for first group - if (bucketColumns.length === 1 || (node1.children.length && name1 in sortingMap)) { - return sortingMap[name1]; - } - // Sorting for second group - return node2.value - node1.value; - } - : undefined, + sortPredicate: PartitionChartsMeta[shape].sortPredicate?.(bucketColumns, sortingMap), shape: { fillColor: (d) => { const seriesLayers: SeriesLayer[] = []; diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts index c0adf7befa1fc..f638bfd908be4 100644 --- a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts +++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts @@ -52,6 +52,10 @@ function hasCustomSuggestionsExists(shape: PieChartTypes | string | undefined) { return shape ? ['treemap', 'waffle', 'mosaic'].includes(shape) : false; } +const maximumGroupLength = Math.max( + ...Object.values(PartitionChartsMeta).map(({ maxBuckets }) => maxBuckets) +); + export function suggestions({ table, state, @@ -67,11 +71,7 @@ export function suggestions({ const [groups, metrics] = partition(table.columns, (col) => col.operation.isBucketed); - if ( - metrics.length > 1 || - groups.length > - Math.max(...Object.values(PartitionChartsMeta).map(({ maxBuckets }) => maxBuckets)) - ) { + if (metrics.length > 1 || groups.length > maximumGroupLength) { return []; } From 137a82d6a26960be2ae18051db26983d1456210e Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Wed, 1 Dec 2021 17:00:13 +0300 Subject: [PATCH 07/18] [Lens] Pie and donuts should have a size ratio setting --- .../common/expressions/pie_chart/pie_chart.ts | 8 ++ .../common/expressions/pie_chart/types.ts | 2 + .../public/pie_visualization/constants.ts | 8 ++ .../partition_charts_meta.ts | 37 +++++++++ .../pie_visualization/render_function.tsx | 6 +- .../public/pie_visualization/to_expression.ts | 8 +- .../lens/public/pie_visualization/toolbar.tsx | 78 +++++++++++++++++-- 7 files changed, 138 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts index 053b46e480c7b..e7b40ef218802 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts @@ -97,6 +97,14 @@ export const pie: ExpressionFunctionDefinition< help: '', types: ['palette'], }, + pieSizeRatio: { + types: ['number'], + help: '', + }, + donutInnerAreaRatio: { + types: ['number'], + help: '', + }, }, inputTypes: ['lens_multitable'], fn(data: LensMultiTable, args: PieExpressionArgs) { diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts index 8c9ec4e5a54e7..eae58136afa85 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts @@ -19,6 +19,8 @@ export interface SharedPieLayerState { legendPosition?: 'left' | 'right' | 'top' | 'bottom'; nestedLegend?: boolean; percentDecimals?: number; + pieSizeRatio?: number; + donutInnerAreaRatio?: number; legendMaxLines?: number; truncateLegend?: boolean; } diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index bfb263b415891..14594a76abcbb 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -6,3 +6,11 @@ */ export const DEFAULT_PERCENT_DECIMALS = 2; + +export const DEFAULT_DONUT_INNER_AREA_RATIO = 0.3; + +export enum PIE_SIZE_RATIO { + SMALL = 0.6, + MEDIUM = 0.8, + LARGE = 1, +} diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 4f16ab01ba19c..1e1e38a2121f6 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -14,6 +14,7 @@ import { LensIconChartPie } from '../assets/chart_pie'; import { LensIconChartTreemap } from '../assets/chart_treemap'; import { LensIconChartMosaic } from '../assets/chart_mosaic'; import { LensIconChartWaffle } from '../assets/chart_waffle'; +import { PIE_SIZE_RATIO } from './constants'; import type { SharedPieLayerState } from '../../common/expressions'; import type { PieChartTypes } from '../../common/expressions/pie_chart/types'; @@ -29,6 +30,7 @@ interface PartitionChartMeta { requiredMinDimensionCount?: number; toolbarPopover: { isDisabled?: boolean; + hasInnerAreaSizeSetting?: boolean; categoryOptions: Array<{ value: SharedPieLayerState['categoryDisplay']; inputDisplay: string; @@ -37,6 +39,11 @@ interface PartitionChartMeta { value: SharedPieLayerState['numberDisplay']; inputDisplay: string; }>; + sizeRatioOptions: Array<{ + id: string; + value: PIE_SIZE_RATIO; + label: string; + }>; }; legend: { flat?: boolean; @@ -110,6 +117,30 @@ const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [ }, ]; +const sizeRatioOptions: PartitionChartMeta['toolbarPopover']['sizeRatioOptions'] = [ + { + id: 'pieSizeOption-small', + value: PIE_SIZE_RATIO.SMALL, + label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.small', { + defaultMessage: 'Small', + }), + }, + { + id: 'pieSizeOption-medium', + value: PIE_SIZE_RATIO.MEDIUM, + label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.medium', { + defaultMessage: 'Medium', + }), + }, + { + id: 'pieSizeOption-large', + value: PIE_SIZE_RATIO.LARGE, + label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.large', { + defaultMessage: 'Large', + }), + }, +]; + export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { donut: { icon: LensIconChartDonut, @@ -122,6 +153,8 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, + sizeRatioOptions, + hasInnerAreaSizeSetting: true, }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -138,6 +171,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, + sizeRatioOptions, }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -154,6 +188,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: categoryOptionsTreemap, numberOptions, + sizeRatioOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -171,6 +206,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: [], numberOptions, + sizeRatioOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -200,6 +236,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { isDisabled: true, categoryOptions: [], numberOptions: [], + sizeRatioOptions: [], }, legend: { flat: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 539d69207f5f9..de36dbd270c3d 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -82,6 +82,8 @@ export function PieComponent( legendPosition, nestedLegend, percentDecimals, + pieSizeRatio, + donutInnerAreaRatio, legendMaxLines, truncateLegend, hideLabels, @@ -205,7 +207,7 @@ export function PieComponent( const config: RecursivePartial<PartitionConfig> = { partitionLayout, fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, - outerSizeRatio: 1, + outerSizeRatio: pieSizeRatio, specialFirstInnermostSector: true, minFontSize: 10, maxFontSize: 16, @@ -228,7 +230,7 @@ export function PieComponent( config.fillLabel = { textColor: 'rgba(0,0,0,0)' }; } } else { - config.emptySizeRatio = shape === 'donut' ? 0.3 : 0; + config.emptySizeRatio = shape === 'donut' ? donutInnerAreaRatio : 0; if (hideLabels || categoryDisplay === 'hide') { // Force all labels to be linked, then prevent links from showing diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index e13fbf62708ee..9f1f747a34253 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -8,7 +8,11 @@ import { Ast } from '@kbn/interpreter/common'; import { PaletteRegistry } from 'src/plugins/charts/public'; import { Operation, DatasourcePublicAPI } from '../types'; -import { DEFAULT_PERCENT_DECIMALS } from './constants'; +import { + DEFAULT_DONUT_INNER_AREA_RATIO, + DEFAULT_PERCENT_DECIMALS, + PIE_SIZE_RATIO, +} from './constants'; import type { PieVisualizationState } from '../../common/expressions'; export function toExpression( @@ -55,6 +59,8 @@ function expressionHelper( categoryDisplay: [layer.categoryDisplay], legendDisplay: [layer.legendDisplay], legendPosition: [layer.legendPosition || 'right'], + pieSizeRatio: [layer.pieSizeRatio ?? PIE_SIZE_RATIO.LARGE], + donutInnerAreaRatio: [layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO], percentDecimals: [ state.shape === 'waffle' ? DEFAULT_PERCENT_DECIMALS diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 195a72cca9fed..6a494ad4891f8 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -14,10 +14,11 @@ import { EuiSuperSelect, EuiRange, EuiHorizontalRule, + EuiButtonGroup, } from '@elastic/eui'; import type { Position } from '@elastic/charts'; import type { PaletteRegistry } from 'src/plugins/charts/public'; -import { DEFAULT_PERCENT_DECIMALS } from './constants'; +import { DEFAULT_DONUT_INNER_AREA_RATIO, DEFAULT_PERCENT_DECIMALS } from './constants'; import { PartitionChartsMeta } from './partition_charts_meta'; import type { PieVisualizationState, SharedPieLayerState } from '../../common/expressions'; import { VisualizationDimensionEditorProps, VisualizationToolbarProps } from '../types'; @@ -52,6 +53,10 @@ const legendOptions: Array<{ }, ]; +const sizeLabel = i18n.translate('xpack.lens.pieChart.sizeLabel', { + defaultMessage: 'Size', +}); + export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationState>) { const { state, setState } = props; const layer = state.layers[0]; @@ -61,6 +66,8 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat const { categoryOptions, numberOptions, + sizeRatioOptions, + hasInnerAreaSizeSetting, isDisabled: isToolbarPopoverDisabled, } = PartitionChartsMeta[state.shape].toolbarPopover; @@ -129,7 +136,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat fullWidth display="rowCompressed" > - <DecimalPlaceSlider + <DebouncedValueSlider value={layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS} setValue={(value) => { setState({ @@ -137,9 +144,59 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat layers: [{ ...layer, percentDecimals: value }], }); }} + dataTestSubj="indexPattern-dimension-formatDecimals" /> </EuiFormRow> </ToolbarPopover> + <ToolbarPopover + title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { + defaultMessage: 'Visual options', + })} + type="visualOptions" + groupPosition="center" + buttonDataTestSubj="lnsVisualOptionsButton" + > + <EuiFormRow label={sizeLabel} display="columnCompressed" fullWidth> + <EuiButtonGroup + isFullWidth + name="pieSizeRatio" + buttonSize="compressed" + legend={sizeLabel} + options={sizeRatioOptions} + idSelected={ + sizeRatioOptions.find(({ value }) => value === layer.pieSizeRatio)?.id || + 'pieSizeOption-large' + } + onChange={(sizeId) => { + const pieSizeRatio = sizeRatioOptions.find(({ id }) => id === sizeId)?.value; + setState({ ...state, layers: [{ ...layer, pieSizeRatio }] }); + }} + /> + </EuiFormRow> + {hasInnerAreaSizeSetting && ( + <EuiFormRow + label={i18n.translate('xpack.lens.pieChart.donutInnerAreaSize', { + defaultMessage: 'Size of inner empty area', + })} + fullWidth + display="rowCompressed" + > + <DebouncedValueSlider + min={20} + max={70} + step={10} + value={(layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO) * 100} + setValue={(value) => { + const donutInnerAreaRatio = value / 100; + setState({ + ...state, + layers: [{ ...layer, donutInnerAreaRatio }], + }); + }} + /> + </EuiFormRow> + )} + </ToolbarPopover> <LegendSettingsPopover legendOptions={legendOptions} mode={layer.legendDisplay} @@ -189,12 +246,20 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat ); } -const DecimalPlaceSlider = ({ +const DebouncedValueSlider = ({ value, setValue, + dataTestSubj, + step, + min = 0, + max = 10, }: { value: number; setValue: (value: number) => void; + dataTestSubj?: string; + min?: number; + max?: number; + step?: number; }) => { const { inputValue, handleInputChange } = useDebouncedValue( { @@ -205,10 +270,11 @@ const DecimalPlaceSlider = ({ ); return ( <EuiRange - data-test-subj="indexPattern-dimension-formatDecimals" + data-test-subj={dataTestSubj} value={inputValue} - min={0} - max={10} + min={min} + max={max} + step={step} showInput compressed onChange={(e) => { From 7a40ed1f96b868cec40e66a4bb578c10b400ae4d Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Wed, 1 Dec 2021 17:05:55 +0300 Subject: [PATCH 08/18] Add a missed condition --- .../lens/public/pie_visualization/toolbar.tsx | 94 ++++++++++--------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 6a494ad4891f8..ff996cbcec50b 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -148,55 +148,57 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat /> </EuiFormRow> </ToolbarPopover> - <ToolbarPopover - title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { - defaultMessage: 'Visual options', - })} - type="visualOptions" - groupPosition="center" - buttonDataTestSubj="lnsVisualOptionsButton" - > - <EuiFormRow label={sizeLabel} display="columnCompressed" fullWidth> - <EuiButtonGroup - isFullWidth - name="pieSizeRatio" - buttonSize="compressed" - legend={sizeLabel} - options={sizeRatioOptions} - idSelected={ - sizeRatioOptions.find(({ value }) => value === layer.pieSizeRatio)?.id || - 'pieSizeOption-large' - } - onChange={(sizeId) => { - const pieSizeRatio = sizeRatioOptions.find(({ id }) => id === sizeId)?.value; - setState({ ...state, layers: [{ ...layer, pieSizeRatio }] }); - }} - /> - </EuiFormRow> - {hasInnerAreaSizeSetting && ( - <EuiFormRow - label={i18n.translate('xpack.lens.pieChart.donutInnerAreaSize', { - defaultMessage: 'Size of inner empty area', - })} - fullWidth - display="rowCompressed" - > - <DebouncedValueSlider - min={20} - max={70} - step={10} - value={(layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO) * 100} - setValue={(value) => { - const donutInnerAreaRatio = value / 100; - setState({ - ...state, - layers: [{ ...layer, donutInnerAreaRatio }], - }); + {sizeRatioOptions.length ? ( + <ToolbarPopover + title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { + defaultMessage: 'Visual options', + })} + type="visualOptions" + groupPosition="center" + buttonDataTestSubj="lnsVisualOptionsButton" + > + <EuiFormRow label={sizeLabel} display="columnCompressed" fullWidth> + <EuiButtonGroup + isFullWidth + name="pieSizeRatio" + buttonSize="compressed" + legend={sizeLabel} + options={sizeRatioOptions} + idSelected={ + sizeRatioOptions.find(({ value }) => value === layer.pieSizeRatio)?.id || + 'pieSizeOption-large' + } + onChange={(sizeId) => { + const pieSizeRatio = sizeRatioOptions.find(({ id }) => id === sizeId)?.value; + setState({ ...state, layers: [{ ...layer, pieSizeRatio }] }); }} /> </EuiFormRow> - )} - </ToolbarPopover> + {hasInnerAreaSizeSetting && ( + <EuiFormRow + label={i18n.translate('xpack.lens.pieChart.donutInnerAreaSize', { + defaultMessage: 'Size of inner empty area', + })} + fullWidth + display="rowCompressed" + > + <DebouncedValueSlider + min={20} + max={70} + step={10} + value={(layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO) * 100} + setValue={(value) => { + const donutInnerAreaRatio = value / 100; + setState({ + ...state, + layers: [{ ...layer, donutInnerAreaRatio }], + }); + }} + /> + </EuiFormRow> + )} + </ToolbarPopover> + ) : null} <LegendSettingsPopover legendOptions={legendOptions} mode={layer.legendDisplay} From f7907ad119cc4a42d034a517fa20b8aef61a3647 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Thu, 2 Dec 2021 14:31:31 +0300 Subject: [PATCH 09/18] Fix changing size for smallSlices --- .../lens/public/pie_visualization/render_function.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index de36dbd270c3d..d207fb15f1da1 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -25,7 +25,7 @@ import { import { RenderMode } from 'src/plugins/expressions'; import type { LensFilterEvent } from '../types'; import { VisualizationContainer } from '../visualization_container'; -import { DEFAULT_PERCENT_DECIMALS } from './constants'; +import { DEFAULT_PERCENT_DECIMALS, PIE_SIZE_RATIO } from './constants'; import { PartitionChartsMeta } from './partition_charts_meta'; import type { FormatFactory } from '../../common'; import type { PieExpressionProps } from '../../common/expressions'; @@ -246,7 +246,8 @@ export function PieComponent( const smallSlices = slices.filter((value) => value < 0.02).length; if (smallSlices) { // shrink up to 20% to give some room for the linked values - config.outerSizeRatio = 1 / (1 + Math.min(smallSlices * 0.05, 0.2)); + config.outerSizeRatio = + (pieSizeRatio ?? PIE_SIZE_RATIO.LARGE) / (1 + Math.min(smallSlices * 0.05, 0.2)); } } } From 4833ef591f455fd0d6239f1f47fa11a78a0ef770 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Mon, 6 Dec 2021 17:03:14 +0300 Subject: [PATCH 10/18] Add donut inner area size setting to pie visualization and update it for lens --- .../pie/public/editor/collections.ts | 25 +++++++ .../pie/public/editor/components/pie.tsx | 29 +++++++- .../vis_types/pie/public/editor/constants.ts | 13 ++++ src/plugins/vis_types/pie/public/pie_fn.ts | 6 ++ src/plugins/vis_types/pie/public/to_ast.ts | 1 + .../vis_types/pie/public/types/types.ts | 2 + .../vis_types/pie/public/utils/get_config.ts | 2 +- .../vis_types/pie/public/vis_type/pie.ts | 2 + .../common/expressions/pie_chart/pie_chart.ts | 6 +- .../common/expressions/pie_chart/types.ts | 3 +- .../public/pie_visualization/constants.ts | 10 ++- .../partition_charts_meta.ts | 65 +++++++++-------- .../pie_visualization/render_function.tsx | 12 ++-- .../public/pie_visualization/to_expression.ts | 9 +-- .../lens/public/pie_visualization/toolbar.tsx | 72 ++++++------------- 15 files changed, 143 insertions(+), 114 deletions(-) create mode 100644 src/plugins/vis_types/pie/public/editor/constants.ts diff --git a/src/plugins/vis_types/pie/public/editor/collections.ts b/src/plugins/vis_types/pie/public/editor/collections.ts index d65e933a8835c..27d32f4b940aa 100644 --- a/src/plugins/vis_types/pie/public/editor/collections.ts +++ b/src/plugins/vis_types/pie/public/editor/collections.ts @@ -7,6 +7,7 @@ */ import { i18n } from '@kbn/i18n'; +import { DONUT_INNER_AREA_SIZE } from './constants'; import { LabelPositions, ValueFormats } from '../types'; export const getLabelPositions = [ @@ -38,3 +39,27 @@ export const getValuesFormats = [ value: ValueFormats.VALUE, }, ]; + +export const donutInnerAreaSizeOptions = [ + { + id: 'donutInnerAreaSizeOption-small', + value: DONUT_INNER_AREA_SIZE.SMALL, + label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.small', { + defaultMessage: 'Small', + }), + }, + { + id: 'donutInnerAreaSizeOption-medium', + value: DONUT_INNER_AREA_SIZE.MEDIUM, + label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.medium', { + defaultMessage: 'Medium', + }), + }, + { + id: 'donutInnerAreaSizeOption-large', + value: DONUT_INNER_AREA_SIZE.LARGE, + label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.large', { + defaultMessage: 'Large', + }), + }, +]; diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 50e599b5ef5f3..0d9a05cdb3ae1 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -17,6 +17,7 @@ import { EuiIconTip, EuiFlexItem, EuiFlexGroup, + EuiButtonGroup, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -33,11 +34,15 @@ import { TruncateLabelsOption } from './truncate_labels'; import { PaletteRegistry } from '../../../../../charts/public'; import { DEFAULT_PERCENT_DECIMALS } from '../../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../../types'; -import { getLabelPositions, getValuesFormats } from '../collections'; +import { donutInnerAreaSizeOptions, getLabelPositions, getValuesFormats } from '../collections'; import { getLegendPositions } from '../positions'; export interface PieOptionsProps extends VisEditorOptionsProps<PieVisParams>, PieTypeProps {} +const donutInnerAreaSizeLabel = i18n.translate('visTypePie.editors.pie.donutInnerAreaSizeLabel', { + defaultMessage: 'Inner area size', +}); + function DecimalSlider<ParamName extends string>({ paramName, value, @@ -116,6 +121,28 @@ const PieOptions = (props: PieOptionsProps) => { value={stateParams.isDonut} setValue={setValue} /> + {stateParams.isDonut && ( + <EuiFormRow label={donutInnerAreaSizeLabel} fullWidth> + <EuiButtonGroup + isFullWidth + name="donutInnerAreaSize" + buttonSize="compressed" + legend={donutInnerAreaSizeLabel} + options={donutInnerAreaSizeOptions} + idSelected={ + donutInnerAreaSizeOptions.find( + ({ value }) => value === stateParams.donutInnerAreaSize + )?.id || 'donutInnerAreaSizeOption-medium' + } + onChange={(sizeId) => { + const donutInnerAreaSize = donutInnerAreaSizeOptions.find( + ({ id }) => id === sizeId + )?.value; + setValue('donutInnerAreaSize', donutInnerAreaSize); + }} + /> + </EuiFormRow> + )} <BasicOptions {...props} legendPositions={getLegendPositions} /> {props.showElasticChartsOptions && ( <> diff --git a/src/plugins/vis_types/pie/public/editor/constants.ts b/src/plugins/vis_types/pie/public/editor/constants.ts new file mode 100644 index 0000000000000..04331cd15db4e --- /dev/null +++ b/src/plugins/vis_types/pie/public/editor/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export enum DONUT_INNER_AREA_SIZE { + SMALL = 0.2, + MEDIUM = 0.3, + LARGE = 0.5, +} diff --git a/src/plugins/vis_types/pie/public/pie_fn.ts b/src/plugins/vis_types/pie/public/pie_fn.ts index 74e8127712399..75a578e9db99c 100644 --- a/src/plugins/vis_types/pie/public/pie_fn.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.ts @@ -117,6 +117,12 @@ export const createPieVisFn = (): VisTypePieExpressionFunctionDefinition => ({ }), default: false, }, + donutInnerAreaSize: { + types: ['number'], + help: i18n.translate('visTypePie.function.args.donutInnerAreaSizeHelpText', { + defaultMessage: 'Defines donut inner empty area size', + }), + }, palette: { types: ['string'], help: i18n.translate('visTypePie.function.args.paletteHelpText', { diff --git a/src/plugins/vis_types/pie/public/to_ast.ts b/src/plugins/vis_types/pie/public/to_ast.ts index fbfffbb77d5fb..060c6ab4f765f 100644 --- a/src/plugins/vis_types/pie/public/to_ast.ts +++ b/src/plugins/vis_types/pie/public/to_ast.ts @@ -54,6 +54,7 @@ export const toExpressionAst: VisToExpressionAst<PieVisParams> = async (vis, par maxLegendLines: vis.params.maxLegendLines, distinctColors: vis.params?.distinctColors, isDonut: vis.params.isDonut, + donutInnerAreaSize: vis.params.donutInnerAreaSize, palette: vis.params?.palette?.name, labels: prepareLabels(vis.params.labels), metric: schemas.metric.map(prepareDimension), diff --git a/src/plugins/vis_types/pie/public/types/types.ts b/src/plugins/vis_types/pie/public/types/types.ts index fb5efb5971805..25d3d24e44c3c 100644 --- a/src/plugins/vis_types/pie/public/types/types.ts +++ b/src/plugins/vis_types/pie/public/types/types.ts @@ -13,6 +13,7 @@ import type { SerializedFieldFormat } from '../../../../field_formats/common'; import { ExpressionValueVisDimension } from '../../../../visualizations/public'; import { ExpressionValuePieLabels } from '../expression_functions/pie_labels'; import { PaletteOutput, ChartsPluginSetup } from '../../../../charts/public'; +import { DONUT_INNER_AREA_SIZE } from '../editor/constants'; export interface Dimension { accessor: number; @@ -38,6 +39,7 @@ interface PieCommonParams { maxLegendLines: number; distinctColors: boolean; isDonut: boolean; + donutInnerAreaSize?: DONUT_INNER_AREA_SIZE; } export interface LabelsParams { diff --git a/src/plugins/vis_types/pie/public/utils/get_config.ts b/src/plugins/vis_types/pie/public/utils/get_config.ts index 9f67155145820..e27954e6cb2fc 100644 --- a/src/plugins/vis_types/pie/public/utils/get_config.ts +++ b/src/plugins/vis_types/pie/public/utils/get_config.ts @@ -54,7 +54,7 @@ export const getConfig = ( sectorLineStroke: chartTheme.lineSeriesStyle?.point?.fill, sectorLineWidth: 1.5, circlePadding: 4, - emptySizeRatio: visParams.isDonut ? 0.3 : 0, + emptySizeRatio: visParams.isDonut ? visParams.donutInnerAreaSize : 0, ...usingMargin, }; if (!visParams.labels.show) { diff --git a/src/plugins/vis_types/pie/public/vis_type/pie.ts b/src/plugins/vis_types/pie/public/vis_type/pie.ts index 0d012ed95b5d9..b526a733d3eaa 100644 --- a/src/plugins/vis_types/pie/public/vis_type/pie.ts +++ b/src/plugins/vis_types/pie/public/vis_type/pie.ts @@ -14,6 +14,7 @@ import { DEFAULT_PERCENT_DECIMALS } from '../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../types'; import { toExpressionAst } from '../to_ast'; import { getPieOptions } from '../editor/components'; +import { DONUT_INNER_AREA_SIZE } from '../editor/constants'; export const getPieVisTypeDefinition = ({ showElasticChartsOptions = false, @@ -39,6 +40,7 @@ export const getPieVisTypeDefinition = ({ maxLegendLines: 1, distinctColors: false, isDonut: true, + donutInnerAreaSize: DONUT_INNER_AREA_SIZE.MEDIUM, palette: { type: 'palette', name: 'default', diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts index e7b40ef218802..8eddc48ca4535 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts @@ -97,11 +97,7 @@ export const pie: ExpressionFunctionDefinition< help: '', types: ['palette'], }, - pieSizeRatio: { - types: ['number'], - help: '', - }, - donutInnerAreaRatio: { + donutInnerAreaSize: { types: ['number'], help: '', }, diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts index eae58136afa85..423819e3c8593 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts @@ -19,8 +19,7 @@ export interface SharedPieLayerState { legendPosition?: 'left' | 'right' | 'top' | 'bottom'; nestedLegend?: boolean; percentDecimals?: number; - pieSizeRatio?: number; - donutInnerAreaRatio?: number; + donutInnerAreaSize?: number; legendMaxLines?: number; truncateLegend?: boolean; } diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index 14594a76abcbb..b9d0954b17bce 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -7,10 +7,8 @@ export const DEFAULT_PERCENT_DECIMALS = 2; -export const DEFAULT_DONUT_INNER_AREA_RATIO = 0.3; - -export enum PIE_SIZE_RATIO { - SMALL = 0.6, - MEDIUM = 0.8, - LARGE = 1, +export enum DONUT_INNER_AREA_SIZE { + SMALL = 0.2, + MEDIUM = 0.3, + LARGE = 0.5, } diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 1e1e38a2121f6..7b205e7a83cae 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -14,7 +14,7 @@ import { LensIconChartPie } from '../assets/chart_pie'; import { LensIconChartTreemap } from '../assets/chart_treemap'; import { LensIconChartMosaic } from '../assets/chart_mosaic'; import { LensIconChartWaffle } from '../assets/chart_waffle'; -import { PIE_SIZE_RATIO } from './constants'; +import { DONUT_INNER_AREA_SIZE } from './constants'; import type { SharedPieLayerState } from '../../common/expressions'; import type { PieChartTypes } from '../../common/expressions/pie_chart/types'; @@ -30,7 +30,6 @@ interface PartitionChartMeta { requiredMinDimensionCount?: number; toolbarPopover: { isDisabled?: boolean; - hasInnerAreaSizeSetting?: boolean; categoryOptions: Array<{ value: SharedPieLayerState['categoryDisplay']; inputDisplay: string; @@ -39,9 +38,9 @@ interface PartitionChartMeta { value: SharedPieLayerState['numberDisplay']; inputDisplay: string; }>; - sizeRatioOptions: Array<{ + donutInnerAreaSizeOptions: Array<{ id: string; - value: PIE_SIZE_RATIO; + value: DONUT_INNER_AREA_SIZE; label: string; }>; }; @@ -117,29 +116,30 @@ const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [ }, ]; -const sizeRatioOptions: PartitionChartMeta['toolbarPopover']['sizeRatioOptions'] = [ - { - id: 'pieSizeOption-small', - value: PIE_SIZE_RATIO.SMALL, - label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.small', { - defaultMessage: 'Small', - }), - }, - { - id: 'pieSizeOption-medium', - value: PIE_SIZE_RATIO.MEDIUM, - label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.medium', { - defaultMessage: 'Medium', - }), - }, - { - id: 'pieSizeOption-large', - value: PIE_SIZE_RATIO.LARGE, - label: i18n.translate('xpack.lens.pieChart.sizeRatioOptions.large', { - defaultMessage: 'Large', - }), - }, -]; +const donutInnerAreaSizeOptions: PartitionChartMeta['toolbarPopover']['donutInnerAreaSizeOptions'] = + [ + { + id: 'donutInnerAreaSizeOption-small', + value: DONUT_INNER_AREA_SIZE.SMALL, + label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.small', { + defaultMessage: 'Small', + }), + }, + { + id: 'donutInnerAreaSizeOption-medium', + value: DONUT_INNER_AREA_SIZE.MEDIUM, + label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.medium', { + defaultMessage: 'Medium', + }), + }, + { + id: 'donutInnerAreaSizeOption-large', + value: DONUT_INNER_AREA_SIZE.LARGE, + label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.large', { + defaultMessage: 'Large', + }), + }, + ]; export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { donut: { @@ -153,8 +153,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - sizeRatioOptions, - hasInnerAreaSizeSetting: true, + donutInnerAreaSizeOptions, }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -171,7 +170,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - sizeRatioOptions, + donutInnerAreaSizeOptions: [], }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -188,7 +187,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: categoryOptionsTreemap, numberOptions, - sizeRatioOptions: [], + donutInnerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -206,7 +205,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: [], numberOptions, - sizeRatioOptions: [], + donutInnerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -236,7 +235,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { isDisabled: true, categoryOptions: [], numberOptions: [], - sizeRatioOptions: [], + donutInnerAreaSizeOptions: [], }, legend: { flat: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index d207fb15f1da1..5c6ea7b3f1ce4 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -25,7 +25,7 @@ import { import { RenderMode } from 'src/plugins/expressions'; import type { LensFilterEvent } from '../types'; import { VisualizationContainer } from '../visualization_container'; -import { DEFAULT_PERCENT_DECIMALS, PIE_SIZE_RATIO } from './constants'; +import { DEFAULT_PERCENT_DECIMALS } from './constants'; import { PartitionChartsMeta } from './partition_charts_meta'; import type { FormatFactory } from '../../common'; import type { PieExpressionProps } from '../../common/expressions'; @@ -82,8 +82,7 @@ export function PieComponent( legendPosition, nestedLegend, percentDecimals, - pieSizeRatio, - donutInnerAreaRatio, + donutInnerAreaSize, legendMaxLines, truncateLegend, hideLabels, @@ -207,7 +206,7 @@ export function PieComponent( const config: RecursivePartial<PartitionConfig> = { partitionLayout, fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, - outerSizeRatio: pieSizeRatio, + outerSizeRatio: 1, specialFirstInnermostSector: true, minFontSize: 10, maxFontSize: 16, @@ -230,7 +229,7 @@ export function PieComponent( config.fillLabel = { textColor: 'rgba(0,0,0,0)' }; } } else { - config.emptySizeRatio = shape === 'donut' ? donutInnerAreaRatio : 0; + config.emptySizeRatio = shape === 'donut' ? donutInnerAreaSize : 0; if (hideLabels || categoryDisplay === 'hide') { // Force all labels to be linked, then prevent links from showing @@ -246,8 +245,7 @@ export function PieComponent( const smallSlices = slices.filter((value) => value < 0.02).length; if (smallSlices) { // shrink up to 20% to give some room for the linked values - config.outerSizeRatio = - (pieSizeRatio ?? PIE_SIZE_RATIO.LARGE) / (1 + Math.min(smallSlices * 0.05, 0.2)); + config.outerSizeRatio = 1 / (1 + Math.min(smallSlices * 0.05, 0.2)); } } } diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index 9f1f747a34253..af71fccc9cde3 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -8,11 +8,7 @@ import { Ast } from '@kbn/interpreter/common'; import { PaletteRegistry } from 'src/plugins/charts/public'; import { Operation, DatasourcePublicAPI } from '../types'; -import { - DEFAULT_DONUT_INNER_AREA_RATIO, - DEFAULT_PERCENT_DECIMALS, - PIE_SIZE_RATIO, -} from './constants'; +import { DEFAULT_PERCENT_DECIMALS, DONUT_INNER_AREA_SIZE } from './constants'; import type { PieVisualizationState } from '../../common/expressions'; export function toExpression( @@ -59,8 +55,7 @@ function expressionHelper( categoryDisplay: [layer.categoryDisplay], legendDisplay: [layer.legendDisplay], legendPosition: [layer.legendPosition || 'right'], - pieSizeRatio: [layer.pieSizeRatio ?? PIE_SIZE_RATIO.LARGE], - donutInnerAreaRatio: [layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO], + donutInnerAreaSize: [layer.donutInnerAreaSize ?? DONUT_INNER_AREA_SIZE.MEDIUM], percentDecimals: [ state.shape === 'waffle' ? DEFAULT_PERCENT_DECIMALS diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index ff996cbcec50b..6dc417920d5ea 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import type { Position } from '@elastic/charts'; import type { PaletteRegistry } from 'src/plugins/charts/public'; -import { DEFAULT_DONUT_INNER_AREA_RATIO, DEFAULT_PERCENT_DECIMALS } from './constants'; +import { DEFAULT_PERCENT_DECIMALS } from './constants'; import { PartitionChartsMeta } from './partition_charts_meta'; import type { PieVisualizationState, SharedPieLayerState } from '../../common/expressions'; import { VisualizationDimensionEditorProps, VisualizationToolbarProps } from '../types'; @@ -53,8 +53,8 @@ const legendOptions: Array<{ }, ]; -const sizeLabel = i18n.translate('xpack.lens.pieChart.sizeLabel', { - defaultMessage: 'Size', +const donutInnerAreaSizeLabel = i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeLabel', { + defaultMessage: 'Inner area size', }); export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationState>) { @@ -66,8 +66,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat const { categoryOptions, numberOptions, - sizeRatioOptions, - hasInnerAreaSizeSetting, + donutInnerAreaSizeOptions, isDisabled: isToolbarPopoverDisabled, } = PartitionChartsMeta[state.shape].toolbarPopover; @@ -136,7 +135,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat fullWidth display="rowCompressed" > - <DebouncedValueSlider + <DecimalPlaceSlider value={layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS} setValue={(value) => { setState({ @@ -144,11 +143,10 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat layers: [{ ...layer, percentDecimals: value }], }); }} - dataTestSubj="indexPattern-dimension-formatDecimals" /> </EuiFormRow> </ToolbarPopover> - {sizeRatioOptions.length ? ( + {donutInnerAreaSizeOptions.length ? ( <ToolbarPopover title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { defaultMessage: 'Visual options', @@ -157,46 +155,25 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat groupPosition="center" buttonDataTestSubj="lnsVisualOptionsButton" > - <EuiFormRow label={sizeLabel} display="columnCompressed" fullWidth> + <EuiFormRow label={donutInnerAreaSizeLabel} display="columnCompressed" fullWidth> <EuiButtonGroup isFullWidth - name="pieSizeRatio" + name="donutInnerAreaSize" buttonSize="compressed" - legend={sizeLabel} - options={sizeRatioOptions} + legend={donutInnerAreaSizeLabel} + options={donutInnerAreaSizeOptions} idSelected={ - sizeRatioOptions.find(({ value }) => value === layer.pieSizeRatio)?.id || - 'pieSizeOption-large' + donutInnerAreaSizeOptions.find(({ value }) => value === layer.donutInnerAreaSize) + ?.id || 'donutInnerAreaSizeOption-medium' } onChange={(sizeId) => { - const pieSizeRatio = sizeRatioOptions.find(({ id }) => id === sizeId)?.value; - setState({ ...state, layers: [{ ...layer, pieSizeRatio }] }); + const donutInnerAreaSize = donutInnerAreaSizeOptions.find( + ({ id }) => id === sizeId + )?.value; + setState({ ...state, layers: [{ ...layer, donutInnerAreaSize }] }); }} /> </EuiFormRow> - {hasInnerAreaSizeSetting && ( - <EuiFormRow - label={i18n.translate('xpack.lens.pieChart.donutInnerAreaSize', { - defaultMessage: 'Size of inner empty area', - })} - fullWidth - display="rowCompressed" - > - <DebouncedValueSlider - min={20} - max={70} - step={10} - value={(layer.donutInnerAreaRatio ?? DEFAULT_DONUT_INNER_AREA_RATIO) * 100} - setValue={(value) => { - const donutInnerAreaRatio = value / 100; - setState({ - ...state, - layers: [{ ...layer, donutInnerAreaRatio }], - }); - }} - /> - </EuiFormRow> - )} </ToolbarPopover> ) : null} <LegendSettingsPopover @@ -248,20 +225,12 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat ); } -const DebouncedValueSlider = ({ +const DecimalPlaceSlider = ({ value, setValue, - dataTestSubj, - step, - min = 0, - max = 10, }: { value: number; setValue: (value: number) => void; - dataTestSubj?: string; - min?: number; - max?: number; - step?: number; }) => { const { inputValue, handleInputChange } = useDebouncedValue( { @@ -272,11 +241,10 @@ const DebouncedValueSlider = ({ ); return ( <EuiRange - data-test-subj={dataTestSubj} + data-test-subj="indexPattern-dimension-formatDecimals" value={inputValue} - min={min} - max={max} - step={step} + min={0} + max={10} showInput compressed onChange={(e) => { From d8eb0b5264631f2b9d21a92cd5cba072ca6daed5 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Mon, 6 Dec 2021 18:34:20 +0300 Subject: [PATCH 11/18] Update test and rename some constants --- .../public/__snapshots__/pie_fn.test.ts.snap | 1 + .../pie/public/editor/components/pie.tsx | 19 +++--- .../vis_types/pie/public/pie_fn.test.ts | 2 + .../partition_charts_meta.ts | 59 +++++++++---------- .../lens/public/pie_visualization/toolbar.tsx | 18 +++--- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap index fb51717d1adc0..e9881544ccf8b 100644 --- a/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap +++ b/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap @@ -47,6 +47,7 @@ Object { "splitRow": undefined, }, "distinctColors": false, + "donutInnerAreaSize": 0.3, "isDonut": true, "labels": Object { "percentDecimals": 2, diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 0d9a05cdb3ae1..9a63b063ed95a 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { METRIC_TYPE } from '@kbn/analytics'; import { EuiPanel, @@ -101,6 +101,14 @@ const PieOptions = (props: PieOptionsProps) => { fetchPalettes(); }, [props.palettes]); + const handleDonutInnerAreaSizeChange = useCallback( + (sizeId) => { + const donutInnerAreaSize = donutInnerAreaSizeOptions.find(({ id }) => id === sizeId)?.value; + setValue('donutInnerAreaSize', donutInnerAreaSize); + }, + [setValue] + ); + return ( <> <EuiPanel paddingSize="s"> @@ -132,14 +140,9 @@ const PieOptions = (props: PieOptionsProps) => { idSelected={ donutInnerAreaSizeOptions.find( ({ value }) => value === stateParams.donutInnerAreaSize - )?.id || 'donutInnerAreaSizeOption-medium' + )?.id ?? 'donutInnerAreaSizeOption-medium' } - onChange={(sizeId) => { - const donutInnerAreaSize = donutInnerAreaSizeOptions.find( - ({ id }) => id === sizeId - )?.value; - setValue('donutInnerAreaSize', donutInnerAreaSize); - }} + onChange={handleDonutInnerAreaSizeChange} /> </EuiFormRow> )} diff --git a/src/plugins/vis_types/pie/public/pie_fn.test.ts b/src/plugins/vis_types/pie/public/pie_fn.test.ts index 9ba21cdc847e5..63bbd947d2dff 100644 --- a/src/plugins/vis_types/pie/public/pie_fn.test.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.test.ts @@ -10,6 +10,7 @@ import { functionWrapper } from '../../../expressions/common/expression_function import { createPieVisFn } from './pie_fn'; import { PieVisConfig } from './types'; import { Datatable } from '../../../expressions/common/expression_types/specs'; +import { DONUT_INNER_AREA_SIZE } from './editor/constants'; describe('interpreter/functions#pie', () => { const fn = functionWrapper(createPieVisFn()); @@ -23,6 +24,7 @@ describe('interpreter/functions#pie', () => { addLegend: true, legendPosition: 'right', isDonut: true, + donutInnerAreaSize: DONUT_INNER_AREA_SIZE.MEDIUM, nestedLegend: true, truncateLegend: true, maxLegendLines: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 7b205e7a83cae..ae9158e893e57 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -38,7 +38,7 @@ interface PartitionChartMeta { value: SharedPieLayerState['numberDisplay']; inputDisplay: string; }>; - donutInnerAreaSizeOptions: Array<{ + innerAreaSizeOptions: Array<{ id: string; value: DONUT_INNER_AREA_SIZE; label: string; @@ -116,30 +116,29 @@ const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [ }, ]; -const donutInnerAreaSizeOptions: PartitionChartMeta['toolbarPopover']['donutInnerAreaSizeOptions'] = - [ - { - id: 'donutInnerAreaSizeOption-small', - value: DONUT_INNER_AREA_SIZE.SMALL, - label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.small', { - defaultMessage: 'Small', - }), - }, - { - id: 'donutInnerAreaSizeOption-medium', - value: DONUT_INNER_AREA_SIZE.MEDIUM, - label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.medium', { - defaultMessage: 'Medium', - }), - }, - { - id: 'donutInnerAreaSizeOption-large', - value: DONUT_INNER_AREA_SIZE.LARGE, - label: i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeOptions.large', { - defaultMessage: 'Large', - }), - }, - ]; +const innerAreaSizeOptions: PartitionChartMeta['toolbarPopover']['innerAreaSizeOptions'] = [ + { + id: 'innerAreaSizeOption-small', + value: DONUT_INNER_AREA_SIZE.SMALL, + label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.small', { + defaultMessage: 'Small', + }), + }, + { + id: 'innerAreaSizeOption-medium', + value: DONUT_INNER_AREA_SIZE.MEDIUM, + label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.medium', { + defaultMessage: 'Medium', + }), + }, + { + id: 'innerAreaSizeOption-large', + value: DONUT_INNER_AREA_SIZE.LARGE, + label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.large', { + defaultMessage: 'Large', + }), + }, +]; export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { donut: { @@ -153,7 +152,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - donutInnerAreaSizeOptions, + innerAreaSizeOptions, }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -170,7 +169,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - donutInnerAreaSizeOptions: [], + innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -187,7 +186,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: categoryOptionsTreemap, numberOptions, - donutInnerAreaSizeOptions: [], + innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -205,7 +204,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: [], numberOptions, - donutInnerAreaSizeOptions: [], + innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -235,7 +234,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { isDisabled: true, categoryOptions: [], numberOptions: [], - donutInnerAreaSizeOptions: [], + innerAreaSizeOptions: [], }, legend: { flat: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 6dc417920d5ea..bde5e5fe99d27 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -53,7 +53,7 @@ const legendOptions: Array<{ }, ]; -const donutInnerAreaSizeLabel = i18n.translate('xpack.lens.pieChart.donutInnerAreaSizeLabel', { +const innerAreaSizeLabel = i18n.translate('xpack.lens.pieChart.innerAreaSizeLabel', { defaultMessage: 'Inner area size', }); @@ -66,7 +66,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat const { categoryOptions, numberOptions, - donutInnerAreaSizeOptions, + innerAreaSizeOptions, isDisabled: isToolbarPopoverDisabled, } = PartitionChartsMeta[state.shape].toolbarPopover; @@ -146,7 +146,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat /> </EuiFormRow> </ToolbarPopover> - {donutInnerAreaSizeOptions.length ? ( + {innerAreaSizeOptions.length ? ( <ToolbarPopover title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { defaultMessage: 'Visual options', @@ -155,19 +155,19 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat groupPosition="center" buttonDataTestSubj="lnsVisualOptionsButton" > - <EuiFormRow label={donutInnerAreaSizeLabel} display="columnCompressed" fullWidth> + <EuiFormRow label={innerAreaSizeLabel} display="columnCompressed" fullWidth> <EuiButtonGroup isFullWidth name="donutInnerAreaSize" buttonSize="compressed" - legend={donutInnerAreaSizeLabel} - options={donutInnerAreaSizeOptions} + legend={innerAreaSizeLabel} + options={innerAreaSizeOptions} idSelected={ - donutInnerAreaSizeOptions.find(({ value }) => value === layer.donutInnerAreaSize) - ?.id || 'donutInnerAreaSizeOption-medium' + innerAreaSizeOptions.find(({ value }) => value === layer.donutInnerAreaSize)?.id ?? + 'innerAreaSizeOption-medium' } onChange={(sizeId) => { - const donutInnerAreaSize = donutInnerAreaSizeOptions.find( + const donutInnerAreaSize = innerAreaSizeOptions.find( ({ id }) => id === sizeId )?.value; setState({ ...state, layers: [{ ...layer, donutInnerAreaSize }] }); From dd5c11c077d9774cb21115b847dd7e55255affd5 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Tue, 7 Dec 2021 11:51:07 +0300 Subject: [PATCH 12/18] Rename the setting --- .../public/__snapshots__/pie_fn.test.ts.snap | 2 +- .../pie/public/editor/collections.ts | 22 ++++++------- .../pie/public/editor/components/pie.tsx | 25 +++++++-------- .../vis_types/pie/public/editor/constants.ts | 2 +- .../vis_types/pie/public/pie_fn.test.ts | 4 +-- src/plugins/vis_types/pie/public/pie_fn.ts | 4 +-- src/plugins/vis_types/pie/public/to_ast.ts | 2 +- .../vis_types/pie/public/types/types.ts | 4 +-- .../vis_types/pie/public/utils/get_config.ts | 2 +- .../vis_types/pie/public/vis_type/pie.ts | 4 +-- .../common/expressions/pie_chart/pie_chart.ts | 2 +- .../common/expressions/pie_chart/types.ts | 2 +- .../public/pie_visualization/constants.ts | 2 +- .../partition_charts_meta.ts | 32 ++++++++----------- .../pie_visualization/render_function.tsx | 4 +-- .../public/pie_visualization/to_expression.ts | 4 +-- .../lens/public/pie_visualization/toolbar.tsx | 24 +++++++------- 17 files changed, 67 insertions(+), 74 deletions(-) diff --git a/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap index e9881544ccf8b..4298654af512d 100644 --- a/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap +++ b/src/plugins/vis_types/pie/public/__snapshots__/pie_fn.test.ts.snap @@ -47,7 +47,7 @@ Object { "splitRow": undefined, }, "distinctColors": false, - "donutInnerAreaSize": 0.3, + "emptySizeRatio": 0.3, "isDonut": true, "labels": Object { "percentDecimals": 2, diff --git a/src/plugins/vis_types/pie/public/editor/collections.ts b/src/plugins/vis_types/pie/public/editor/collections.ts index 27d32f4b940aa..64e4694eb449f 100644 --- a/src/plugins/vis_types/pie/public/editor/collections.ts +++ b/src/plugins/vis_types/pie/public/editor/collections.ts @@ -7,7 +7,7 @@ */ import { i18n } from '@kbn/i18n'; -import { DONUT_INNER_AREA_SIZE } from './constants'; +import { EMPTY_SIZE_RATIOS } from './constants'; import { LabelPositions, ValueFormats } from '../types'; export const getLabelPositions = [ @@ -40,25 +40,25 @@ export const getValuesFormats = [ }, ]; -export const donutInnerAreaSizeOptions = [ +export const emptySizeRatioOptions = [ { - id: 'donutInnerAreaSizeOption-small', - value: DONUT_INNER_AREA_SIZE.SMALL, - label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.small', { + id: 'emptySizeRatioOption-small', + value: EMPTY_SIZE_RATIOS.SMALL, + label: i18n.translate('visTypePie.emptySizeRatioOptions.small', { defaultMessage: 'Small', }), }, { - id: 'donutInnerAreaSizeOption-medium', - value: DONUT_INNER_AREA_SIZE.MEDIUM, - label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.medium', { + id: 'emptySizeRatioOption-medium', + value: EMPTY_SIZE_RATIOS.MEDIUM, + label: i18n.translate('visTypePie.emptySizeRatioOptions.medium', { defaultMessage: 'Medium', }), }, { - id: 'donutInnerAreaSizeOption-large', - value: DONUT_INNER_AREA_SIZE.LARGE, - label: i18n.translate('visTypePie.donutInnerAreaSizeOptions.large', { + id: 'emptySizeRatioOption-large', + value: EMPTY_SIZE_RATIOS.LARGE, + label: i18n.translate('visTypePie.emptySizeRatioOptions.large', { defaultMessage: 'Large', }), }, diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 9a63b063ed95a..07c14db6e3d69 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -34,12 +34,12 @@ import { TruncateLabelsOption } from './truncate_labels'; import { PaletteRegistry } from '../../../../../charts/public'; import { DEFAULT_PERCENT_DECIMALS } from '../../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../../types'; -import { donutInnerAreaSizeOptions, getLabelPositions, getValuesFormats } from '../collections'; +import { emptySizeRatioOptions, getLabelPositions, getValuesFormats } from '../collections'; import { getLegendPositions } from '../positions'; export interface PieOptionsProps extends VisEditorOptionsProps<PieVisParams>, PieTypeProps {} -const donutInnerAreaSizeLabel = i18n.translate('visTypePie.editors.pie.donutInnerAreaSizeLabel', { +const emptySizeRatioLabel = i18n.translate('visTypePie.editors.pie.emptySizeRatioLabel', { defaultMessage: 'Inner area size', }); @@ -101,10 +101,10 @@ const PieOptions = (props: PieOptionsProps) => { fetchPalettes(); }, [props.palettes]); - const handleDonutInnerAreaSizeChange = useCallback( + const handleEmptySizeRatioChange = useCallback( (sizeId) => { - const donutInnerAreaSize = donutInnerAreaSizeOptions.find(({ id }) => id === sizeId)?.value; - setValue('donutInnerAreaSize', donutInnerAreaSize); + const emptySizeRatio = emptySizeRatioOptions.find(({ id }) => id === sizeId)?.value; + setValue('emptySizeRatio', emptySizeRatio); }, [setValue] ); @@ -130,19 +130,18 @@ const PieOptions = (props: PieOptionsProps) => { setValue={setValue} /> {stateParams.isDonut && ( - <EuiFormRow label={donutInnerAreaSizeLabel} fullWidth> + <EuiFormRow label={emptySizeRatioLabel} fullWidth> <EuiButtonGroup isFullWidth - name="donutInnerAreaSize" + name="emptySizeRatio" buttonSize="compressed" - legend={donutInnerAreaSizeLabel} - options={donutInnerAreaSizeOptions} + legend={emptySizeRatioLabel} + options={emptySizeRatioOptions} idSelected={ - donutInnerAreaSizeOptions.find( - ({ value }) => value === stateParams.donutInnerAreaSize - )?.id ?? 'donutInnerAreaSizeOption-medium' + emptySizeRatioOptions.find(({ value }) => value === stateParams.emptySizeRatio) + ?.id ?? 'emptySizeRatioOption-medium' } - onChange={handleDonutInnerAreaSizeChange} + onChange={handleEmptySizeRatioChange} /> </EuiFormRow> )} diff --git a/src/plugins/vis_types/pie/public/editor/constants.ts b/src/plugins/vis_types/pie/public/editor/constants.ts index 04331cd15db4e..8789d351d4e65 100644 --- a/src/plugins/vis_types/pie/public/editor/constants.ts +++ b/src/plugins/vis_types/pie/public/editor/constants.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -export enum DONUT_INNER_AREA_SIZE { +export enum EMPTY_SIZE_RATIOS { SMALL = 0.2, MEDIUM = 0.3, LARGE = 0.5, diff --git a/src/plugins/vis_types/pie/public/pie_fn.test.ts b/src/plugins/vis_types/pie/public/pie_fn.test.ts index 63bbd947d2dff..d823d59cfdb82 100644 --- a/src/plugins/vis_types/pie/public/pie_fn.test.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.test.ts @@ -10,7 +10,7 @@ import { functionWrapper } from '../../../expressions/common/expression_function import { createPieVisFn } from './pie_fn'; import { PieVisConfig } from './types'; import { Datatable } from '../../../expressions/common/expression_types/specs'; -import { DONUT_INNER_AREA_SIZE } from './editor/constants'; +import { EMPTY_SIZE_RATIOS } from './editor/constants'; describe('interpreter/functions#pie', () => { const fn = functionWrapper(createPieVisFn()); @@ -24,7 +24,7 @@ describe('interpreter/functions#pie', () => { addLegend: true, legendPosition: 'right', isDonut: true, - donutInnerAreaSize: DONUT_INNER_AREA_SIZE.MEDIUM, + emptySizeRatio: EMPTY_SIZE_RATIOS.MEDIUM, nestedLegend: true, truncateLegend: true, maxLegendLines: true, diff --git a/src/plugins/vis_types/pie/public/pie_fn.ts b/src/plugins/vis_types/pie/public/pie_fn.ts index 75a578e9db99c..041ecb5b7e6e5 100644 --- a/src/plugins/vis_types/pie/public/pie_fn.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.ts @@ -117,9 +117,9 @@ export const createPieVisFn = (): VisTypePieExpressionFunctionDefinition => ({ }), default: false, }, - donutInnerAreaSize: { + emptySizeRatio: { types: ['number'], - help: i18n.translate('visTypePie.function.args.donutInnerAreaSizeHelpText', { + help: i18n.translate('visTypePie.function.args.emptySizeRatioHelpText', { defaultMessage: 'Defines donut inner empty area size', }), }, diff --git a/src/plugins/vis_types/pie/public/to_ast.ts b/src/plugins/vis_types/pie/public/to_ast.ts index 060c6ab4f765f..531b8516464f2 100644 --- a/src/plugins/vis_types/pie/public/to_ast.ts +++ b/src/plugins/vis_types/pie/public/to_ast.ts @@ -54,7 +54,7 @@ export const toExpressionAst: VisToExpressionAst<PieVisParams> = async (vis, par maxLegendLines: vis.params.maxLegendLines, distinctColors: vis.params?.distinctColors, isDonut: vis.params.isDonut, - donutInnerAreaSize: vis.params.donutInnerAreaSize, + emptySizeRatio: vis.params.emptySizeRatio, palette: vis.params?.palette?.name, labels: prepareLabels(vis.params.labels), metric: schemas.metric.map(prepareDimension), diff --git a/src/plugins/vis_types/pie/public/types/types.ts b/src/plugins/vis_types/pie/public/types/types.ts index 25d3d24e44c3c..4745ee0f95ed5 100644 --- a/src/plugins/vis_types/pie/public/types/types.ts +++ b/src/plugins/vis_types/pie/public/types/types.ts @@ -13,7 +13,7 @@ import type { SerializedFieldFormat } from '../../../../field_formats/common'; import { ExpressionValueVisDimension } from '../../../../visualizations/public'; import { ExpressionValuePieLabels } from '../expression_functions/pie_labels'; import { PaletteOutput, ChartsPluginSetup } from '../../../../charts/public'; -import { DONUT_INNER_AREA_SIZE } from '../editor/constants'; +import { EMPTY_SIZE_RATIOS } from '../editor/constants'; export interface Dimension { accessor: number; @@ -39,7 +39,7 @@ interface PieCommonParams { maxLegendLines: number; distinctColors: boolean; isDonut: boolean; - donutInnerAreaSize?: DONUT_INNER_AREA_SIZE; + emptySizeRatio?: EMPTY_SIZE_RATIOS; } export interface LabelsParams { diff --git a/src/plugins/vis_types/pie/public/utils/get_config.ts b/src/plugins/vis_types/pie/public/utils/get_config.ts index e27954e6cb2fc..67852a773d697 100644 --- a/src/plugins/vis_types/pie/public/utils/get_config.ts +++ b/src/plugins/vis_types/pie/public/utils/get_config.ts @@ -54,7 +54,7 @@ export const getConfig = ( sectorLineStroke: chartTheme.lineSeriesStyle?.point?.fill, sectorLineWidth: 1.5, circlePadding: 4, - emptySizeRatio: visParams.isDonut ? visParams.donutInnerAreaSize : 0, + emptySizeRatio: visParams.isDonut ? visParams.emptySizeRatio : 0, ...usingMargin, }; if (!visParams.labels.show) { diff --git a/src/plugins/vis_types/pie/public/vis_type/pie.ts b/src/plugins/vis_types/pie/public/vis_type/pie.ts index b526a733d3eaa..c9129f4aedc23 100644 --- a/src/plugins/vis_types/pie/public/vis_type/pie.ts +++ b/src/plugins/vis_types/pie/public/vis_type/pie.ts @@ -14,7 +14,7 @@ import { DEFAULT_PERCENT_DECIMALS } from '../../common'; import { PieVisParams, LabelPositions, ValueFormats, PieTypeProps } from '../types'; import { toExpressionAst } from '../to_ast'; import { getPieOptions } from '../editor/components'; -import { DONUT_INNER_AREA_SIZE } from '../editor/constants'; +import { EMPTY_SIZE_RATIOS } from '../editor/constants'; export const getPieVisTypeDefinition = ({ showElasticChartsOptions = false, @@ -40,7 +40,7 @@ export const getPieVisTypeDefinition = ({ maxLegendLines: 1, distinctColors: false, isDonut: true, - donutInnerAreaSize: DONUT_INNER_AREA_SIZE.MEDIUM, + emptySizeRatio: EMPTY_SIZE_RATIOS.MEDIUM, palette: { type: 'palette', name: 'default', diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts index 8eddc48ca4535..e66228267bed5 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts @@ -97,7 +97,7 @@ export const pie: ExpressionFunctionDefinition< help: '', types: ['palette'], }, - donutInnerAreaSize: { + emptySizeRatio: { types: ['number'], help: '', }, diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts index 423819e3c8593..a93dfaa845c7b 100644 --- a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts +++ b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts @@ -19,7 +19,7 @@ export interface SharedPieLayerState { legendPosition?: 'left' | 'right' | 'top' | 'bottom'; nestedLegend?: boolean; percentDecimals?: number; - donutInnerAreaSize?: number; + emptySizeRatio?: number; legendMaxLines?: number; truncateLegend?: boolean; } diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index b9d0954b17bce..17d2990522ba4 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -7,7 +7,7 @@ export const DEFAULT_PERCENT_DECIMALS = 2; -export enum DONUT_INNER_AREA_SIZE { +export enum EMPTY_SIZE_RATIOS { SMALL = 0.2, MEDIUM = 0.3, LARGE = 0.5, diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index ae9158e893e57..2bafa5a1ff8e0 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -14,7 +14,7 @@ import { LensIconChartPie } from '../assets/chart_pie'; import { LensIconChartTreemap } from '../assets/chart_treemap'; import { LensIconChartMosaic } from '../assets/chart_mosaic'; import { LensIconChartWaffle } from '../assets/chart_waffle'; -import { DONUT_INNER_AREA_SIZE } from './constants'; +import { EMPTY_SIZE_RATIOS } from './constants'; import type { SharedPieLayerState } from '../../common/expressions'; import type { PieChartTypes } from '../../common/expressions/pie_chart/types'; @@ -38,9 +38,9 @@ interface PartitionChartMeta { value: SharedPieLayerState['numberDisplay']; inputDisplay: string; }>; - innerAreaSizeOptions: Array<{ + emptySizeRatioOptions?: Array<{ id: string; - value: DONUT_INNER_AREA_SIZE; + value: EMPTY_SIZE_RATIOS; label: string; }>; }; @@ -116,25 +116,25 @@ const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [ }, ]; -const innerAreaSizeOptions: PartitionChartMeta['toolbarPopover']['innerAreaSizeOptions'] = [ +const emptySizeRatioOptions: PartitionChartMeta['toolbarPopover']['emptySizeRatioOptions'] = [ { - id: 'innerAreaSizeOption-small', - value: DONUT_INNER_AREA_SIZE.SMALL, - label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.small', { + id: 'emptySizeRatioOption-small', + value: EMPTY_SIZE_RATIOS.SMALL, + label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.small', { defaultMessage: 'Small', }), }, { - id: 'innerAreaSizeOption-medium', - value: DONUT_INNER_AREA_SIZE.MEDIUM, - label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.medium', { + id: 'emptySizeRatioOption-medium', + value: EMPTY_SIZE_RATIOS.MEDIUM, + label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.medium', { defaultMessage: 'Medium', }), }, { - id: 'innerAreaSizeOption-large', - value: DONUT_INNER_AREA_SIZE.LARGE, - label: i18n.translate('xpack.lens.pieChart.innerAreaSizeOptions.large', { + id: 'emptySizeRatioOption-large', + value: EMPTY_SIZE_RATIOS.LARGE, + label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.large', { defaultMessage: 'Large', }), }, @@ -152,7 +152,7 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - innerAreaSizeOptions, + emptySizeRatioOptions, }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -169,7 +169,6 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions, numberOptions, - innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1, @@ -186,7 +185,6 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: categoryOptionsTreemap, numberOptions, - innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -204,7 +202,6 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { toolbarPopover: { categoryOptions: [], numberOptions, - innerAreaSizeOptions: [], }, legend: { getShowLegendDefault: () => false, @@ -234,7 +231,6 @@ export const PartitionChartsMeta: Record<PieChartTypes, PartitionChartMeta> = { isDisabled: true, categoryOptions: [], numberOptions: [], - innerAreaSizeOptions: [], }, legend: { flat: true, diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 5c6ea7b3f1ce4..d65d430115158 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -82,7 +82,7 @@ export function PieComponent( legendPosition, nestedLegend, percentDecimals, - donutInnerAreaSize, + emptySizeRatio, legendMaxLines, truncateLegend, hideLabels, @@ -229,7 +229,7 @@ export function PieComponent( config.fillLabel = { textColor: 'rgba(0,0,0,0)' }; } } else { - config.emptySizeRatio = shape === 'donut' ? donutInnerAreaSize : 0; + config.emptySizeRatio = shape === 'donut' ? emptySizeRatio : 0; if (hideLabels || categoryDisplay === 'hide') { // Force all labels to be linked, then prevent links from showing diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index af71fccc9cde3..9f87d2e18c267 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -8,7 +8,7 @@ import { Ast } from '@kbn/interpreter/common'; import { PaletteRegistry } from 'src/plugins/charts/public'; import { Operation, DatasourcePublicAPI } from '../types'; -import { DEFAULT_PERCENT_DECIMALS, DONUT_INNER_AREA_SIZE } from './constants'; +import { DEFAULT_PERCENT_DECIMALS, EMPTY_SIZE_RATIOS } from './constants'; import type { PieVisualizationState } from '../../common/expressions'; export function toExpression( @@ -55,7 +55,7 @@ function expressionHelper( categoryDisplay: [layer.categoryDisplay], legendDisplay: [layer.legendDisplay], legendPosition: [layer.legendPosition || 'right'], - donutInnerAreaSize: [layer.donutInnerAreaSize ?? DONUT_INNER_AREA_SIZE.MEDIUM], + emptySizeRatio: [layer.emptySizeRatio ?? EMPTY_SIZE_RATIOS.MEDIUM], percentDecimals: [ state.shape === 'waffle' ? DEFAULT_PERCENT_DECIMALS diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index bde5e5fe99d27..0842d591b5de7 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -53,7 +53,7 @@ const legendOptions: Array<{ }, ]; -const innerAreaSizeLabel = i18n.translate('xpack.lens.pieChart.innerAreaSizeLabel', { +const emptySizeRatioLabel = i18n.translate('xpack.lens.pieChart.emptySizeRatioLabel', { defaultMessage: 'Inner area size', }); @@ -66,7 +66,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat const { categoryOptions, numberOptions, - innerAreaSizeOptions, + emptySizeRatioOptions, isDisabled: isToolbarPopoverDisabled, } = PartitionChartsMeta[state.shape].toolbarPopover; @@ -146,7 +146,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat /> </EuiFormRow> </ToolbarPopover> - {innerAreaSizeOptions.length ? ( + {emptySizeRatioOptions?.length ? ( <ToolbarPopover title={i18n.translate('xpack.lens.pieChart.visualOptionsLabel', { defaultMessage: 'Visual options', @@ -155,22 +155,20 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat groupPosition="center" buttonDataTestSubj="lnsVisualOptionsButton" > - <EuiFormRow label={innerAreaSizeLabel} display="columnCompressed" fullWidth> + <EuiFormRow label={emptySizeRatioLabel} display="columnCompressed" fullWidth> <EuiButtonGroup isFullWidth - name="donutInnerAreaSize" + name="emptySizeRatio" buttonSize="compressed" - legend={innerAreaSizeLabel} - options={innerAreaSizeOptions} + legend={emptySizeRatioLabel} + options={emptySizeRatioOptions} idSelected={ - innerAreaSizeOptions.find(({ value }) => value === layer.donutInnerAreaSize)?.id ?? - 'innerAreaSizeOption-medium' + emptySizeRatioOptions.find(({ value }) => value === layer.emptySizeRatio)?.id ?? + 'emptySizeRatioOption-medium' } onChange={(sizeId) => { - const donutInnerAreaSize = innerAreaSizeOptions.find( - ({ id }) => id === sizeId - )?.value; - setState({ ...state, layers: [{ ...layer, donutInnerAreaSize }] }); + const emptySizeRatio = emptySizeRatioOptions.find(({ id }) => id === sizeId)?.value; + setState({ ...state, layers: [{ ...layer, emptySizeRatio }] }); }} /> </EuiFormRow> From dae7adadb5572c4ab2f67e7f95e83c852c2a32ce Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Tue, 7 Dec 2021 14:03:22 +0300 Subject: [PATCH 13/18] Move handler to a separate useCallback function --- .../lens/public/pie_visualization/toolbar.tsx | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 0842d591b5de7..c2604a176417d 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -6,7 +6,7 @@ */ import './toolbar.scss'; -import React from 'react'; +import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, @@ -60,9 +60,17 @@ const emptySizeRatioLabel = i18n.translate('xpack.lens.pieChart.emptySizeRatioLa export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationState>) { const { state, setState } = props; const layer = state.layers[0]; - if (!layer) { - return null; - } + + const onStateChange = useCallback( + (part: Record<string, unknown>) => { + setState({ + ...state, + layers: [{ ...layer, ...part }], + }); + }, + [layer, state, setState] + ); + const { categoryOptions, numberOptions, @@ -70,6 +78,18 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat isDisabled: isToolbarPopoverDisabled, } = PartitionChartsMeta[state.shape].toolbarPopover; + const onEmptySizeRatioChange = useCallback( + (sizeId) => { + const emptySizeRatio = emptySizeRatioOptions?.find(({ id }) => id === sizeId)?.value; + onStateChange({ emptySizeRatio }); + }, + [emptySizeRatioOptions, onStateChange] + ); + + if (!layer) { + return null; + } + return ( <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" responsive={false}> <ToolbarPopover @@ -166,10 +186,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat emptySizeRatioOptions.find(({ value }) => value === layer.emptySizeRatio)?.id ?? 'emptySizeRatioOption-medium' } - onChange={(sizeId) => { - const emptySizeRatio = emptySizeRatioOptions.find(({ id }) => id === sizeId)?.value; - setState({ ...state, layers: [{ ...layer, emptySizeRatio }] }); - }} + onChange={onEmptySizeRatioChange} /> </EuiFormRow> </ToolbarPopover> From 3c62dedb8871d7f1732fe296117ff328fac2a0f7 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Tue, 7 Dec 2021 15:32:44 +0300 Subject: [PATCH 14/18] Update size ratios and add condition for legacy charts --- src/plugins/vis_types/pie/public/editor/components/pie.tsx | 2 +- src/plugins/vis_types/pie/public/editor/constants.ts | 2 +- x-pack/plugins/lens/public/pie_visualization/constants.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 07c14db6e3d69..41c0ac2717011 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -129,7 +129,7 @@ const PieOptions = (props: PieOptionsProps) => { value={stateParams.isDonut} setValue={setValue} /> - {stateParams.isDonut && ( + {props.showElasticChartsOptions && stateParams.isDonut && ( <EuiFormRow label={emptySizeRatioLabel} fullWidth> <EuiButtonGroup isFullWidth diff --git a/src/plugins/vis_types/pie/public/editor/constants.ts b/src/plugins/vis_types/pie/public/editor/constants.ts index 8789d351d4e65..f1a1fdf21e07e 100644 --- a/src/plugins/vis_types/pie/public/editor/constants.ts +++ b/src/plugins/vis_types/pie/public/editor/constants.ts @@ -9,5 +9,5 @@ export enum EMPTY_SIZE_RATIOS { SMALL = 0.2, MEDIUM = 0.3, - LARGE = 0.5, + LARGE = 0.7, } diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index 17d2990522ba4..22fb90c4d870f 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -10,5 +10,5 @@ export const DEFAULT_PERCENT_DECIMALS = 2; export enum EMPTY_SIZE_RATIOS { SMALL = 0.2, MEDIUM = 0.3, - LARGE = 0.5, + LARGE = 0.7, } From 65e6f66a23dd640fbebe6394492fa379302e1d2d Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Wed, 8 Dec 2021 12:17:11 +0300 Subject: [PATCH 15/18] Fix merge conflict issue --- x-pack/plugins/lens/public/pie_visualization/toolbar.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 4723d46b088c9..0926250d4f812 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -122,9 +122,6 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat }); }, [layer, state.shape, onStateChange]); - if (!layer) { - return null; - } const { categoryOptions, numberOptions, From 0bdd7da3f631e5f630b00eb6765bffd306848b8c Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Wed, 8 Dec 2021 14:57:24 +0300 Subject: [PATCH 16/18] Change constants order --- .../lens/public/pie_visualization/toolbar.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 0926250d4f812..7b87831e08113 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -61,6 +61,12 @@ const emptySizeRatioLabel = i18n.translate('xpack.lens.pieChart.emptySizeRatioLa export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationState>) { const { state, setState } = props; const layer = state.layers[0]; + const { + categoryOptions, + numberOptions, + emptySizeRatioOptions, + isDisabled: isToolbarPopoverDisabled, + } = PartitionChartsMeta[state.shape].toolbarPopover; const onStateChange = useCallback( (part: Record<string, unknown>) => { @@ -122,13 +128,6 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat }); }, [layer, state.shape, onStateChange]); - const { - categoryOptions, - numberOptions, - emptySizeRatioOptions, - isDisabled: isToolbarPopoverDisabled, - } = PartitionChartsMeta[state.shape].toolbarPopover; - const onEmptySizeRatioChange = useCallback( (sizeId) => { const emptySizeRatio = emptySizeRatioOptions?.find(({ id }) => id === sizeId)?.value; From a9cb5ab89f88de6f23f09c34011a913c60472e89 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Thu, 9 Dec 2021 15:19:04 +0300 Subject: [PATCH 17/18] Add a couple of tests to check if the setting is displayed --- .../pie/public/editor/components/pie.test.tsx | 14 +++++++++++ .../pie/public/editor/components/pie.tsx | 1 + .../lens/public/pie_visualization/toolbar.tsx | 1 + .../test/functional/apps/lens/smokescreen.ts | 24 +++++++++++++++++++ .../test/functional/page_objects/lens_page.ts | 7 ++++++ 5 files changed, 47 insertions(+) diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx index ac02b33b92add..d6dc4c0734e42 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.test.tsx @@ -135,4 +135,18 @@ describe('PalettePicker', function () { expect(findTestSubject(component, 'visTypePieValueDecimals').length).toBe(1); }); }); + + it('renders the donut size button group for the elastic charts implementation', async () => { + component = mountWithIntl(<PieOptions {...props} />); + await act(async () => { + expect(findTestSubject(component, 'visTypePieEmptySizeRatioButtonGroup').length).toBe(1); + }); + }); + + it('not renders the donut size button group for the vislib implementation', async () => { + component = mountWithIntl(<PieOptions {...props} showElasticChartsOptions={false} />); + await act(async () => { + expect(findTestSubject(component, 'visTypePieEmptySizeRatioButtonGroup').length).toBe(0); + }); + }); }); diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 41c0ac2717011..1a46bb01411d0 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -142,6 +142,7 @@ const PieOptions = (props: PieOptionsProps) => { ?.id ?? 'emptySizeRatioOption-medium' } onChange={handleEmptySizeRatioChange} + data-test-subj="visTypePieEmptySizeRatioButtonGroup" /> </EuiFormRow> )} diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 4a0c4652b9330..c9cbe63c98d8c 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -228,6 +228,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat 'emptySizeRatioOption-medium' } onChange={onEmptySizeRatioChange} + data-test-subj="lnsEmptySizeRatioButtonGroup" /> </EuiFormRow> </ToolbarPopover> diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index 7cacee6446723..34449f2d77307 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -16,6 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const elasticChart = getService('elasticChart'); const filterBar = getService('filterBar'); + const retry = getService('retry'); describe('lens smokescreen tests', () => { it('should allow creation of lens xy chart', async () => { @@ -766,5 +767,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await filterBar.removeFilter('extension.raw'); }); + + it('should show visual options button group for a donut chart', async () => { + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.switchToVisualization('donut'); + + const hasVisualOptionsButton = await PageObjects.lens.hasVisualOptionsButton(); + expect(hasVisualOptionsButton).to.be(true); + + await PageObjects.lens.openVisualOptions(); + await retry.try(async () => { + expect(await PageObjects.lens.hasEmptySizeRatioButtonGroup()).to.be(true); + }); + }); + + it('should not show visual options button group for a pie chart', async () => { + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.switchToVisualization('pie'); + + const hasVisualOptionsButton = await PageObjects.lens.hasVisualOptionsButton(); + expect(hasVisualOptionsButton).to.be(false); + }); }); } diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index ed83e16e587ee..ef5a4e6b79c89 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -590,6 +590,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await colorPickerInput.type(color); await PageObjects.common.sleep(1000); // give time for debounced components to rerender }, + hasVisualOptionsButton() { + return testSubjects.exists('lnsVisualOptionsButton'); + }, async openVisualOptions() { await retry.try(async () => { await testSubjects.click('lnsVisualOptionsButton'); @@ -1223,5 +1226,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont const filterIn = await testSubjects.find(`legend-${value}-filterIn`); await filterIn.click(); }, + + hasEmptySizeRatioButtonGroup() { + return testSubjects.exists('lnsEmptySizeRatioButtonGroup'); + }, }); } From af1899d272ed7c6cc941244d9d12d2bc52b1f71c Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <dziyana_dzeraviankina@epam.com> Date: Fri, 17 Dec 2021 18:25:30 +0300 Subject: [PATCH 18/18] Update ratio sizes --- src/plugins/vis_types/pie/public/editor/components/pie.tsx | 2 +- src/plugins/vis_types/pie/public/editor/constants.ts | 4 ++-- src/plugins/vis_types/pie/public/pie_fn.test.ts | 2 +- src/plugins/vis_types/pie/public/vis_type/pie.ts | 2 +- x-pack/plugins/lens/public/pie_visualization/constants.ts | 4 ++-- x-pack/plugins/lens/public/pie_visualization/to_expression.ts | 2 +- x-pack/plugins/lens/public/pie_visualization/toolbar.tsx | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/vis_types/pie/public/editor/components/pie.tsx b/src/plugins/vis_types/pie/public/editor/components/pie.tsx index 1a46bb01411d0..97f427d7b91b7 100644 --- a/src/plugins/vis_types/pie/public/editor/components/pie.tsx +++ b/src/plugins/vis_types/pie/public/editor/components/pie.tsx @@ -139,7 +139,7 @@ const PieOptions = (props: PieOptionsProps) => { options={emptySizeRatioOptions} idSelected={ emptySizeRatioOptions.find(({ value }) => value === stateParams.emptySizeRatio) - ?.id ?? 'emptySizeRatioOption-medium' + ?.id ?? 'emptySizeRatioOption-small' } onChange={handleEmptySizeRatioChange} data-test-subj="visTypePieEmptySizeRatioButtonGroup" diff --git a/src/plugins/vis_types/pie/public/editor/constants.ts b/src/plugins/vis_types/pie/public/editor/constants.ts index f1a1fdf21e07e..6fd0c7ab0a4a6 100644 --- a/src/plugins/vis_types/pie/public/editor/constants.ts +++ b/src/plugins/vis_types/pie/public/editor/constants.ts @@ -7,7 +7,7 @@ */ export enum EMPTY_SIZE_RATIOS { - SMALL = 0.2, - MEDIUM = 0.3, + SMALL = 0.3, + MEDIUM = 0.54, LARGE = 0.7, } diff --git a/src/plugins/vis_types/pie/public/pie_fn.test.ts b/src/plugins/vis_types/pie/public/pie_fn.test.ts index d823d59cfdb82..9a9c2410481bd 100644 --- a/src/plugins/vis_types/pie/public/pie_fn.test.ts +++ b/src/plugins/vis_types/pie/public/pie_fn.test.ts @@ -24,7 +24,7 @@ describe('interpreter/functions#pie', () => { addLegend: true, legendPosition: 'right', isDonut: true, - emptySizeRatio: EMPTY_SIZE_RATIOS.MEDIUM, + emptySizeRatio: EMPTY_SIZE_RATIOS.SMALL, nestedLegend: true, truncateLegend: true, maxLegendLines: true, diff --git a/src/plugins/vis_types/pie/public/vis_type/pie.ts b/src/plugins/vis_types/pie/public/vis_type/pie.ts index 6ef0e5ec83e40..845b2bae1c89d 100644 --- a/src/plugins/vis_types/pie/public/vis_type/pie.ts +++ b/src/plugins/vis_types/pie/public/vis_type/pie.ts @@ -40,7 +40,7 @@ export const getPieVisTypeDefinition = ({ maxLegendLines: 1, distinctColors: false, isDonut: true, - emptySizeRatio: EMPTY_SIZE_RATIOS.MEDIUM, + emptySizeRatio: EMPTY_SIZE_RATIOS.SMALL, palette: { type: 'palette', name: 'default', diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index 22fb90c4d870f..e32320bb75ff0 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -8,7 +8,7 @@ export const DEFAULT_PERCENT_DECIMALS = 2; export enum EMPTY_SIZE_RATIOS { - SMALL = 0.2, - MEDIUM = 0.3, + SMALL = 0.3, + MEDIUM = 0.54, LARGE = 0.7, } diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts index 9005136621b07..f7e76567743e4 100644 --- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts @@ -58,7 +58,7 @@ function expressionHelper( categoryDisplay: [layer.categoryDisplay], legendDisplay: [layer.legendDisplay], legendPosition: [layer.legendPosition || 'right'], - emptySizeRatio: [layer.emptySizeRatio ?? EMPTY_SIZE_RATIOS.MEDIUM], + emptySizeRatio: [layer.emptySizeRatio ?? EMPTY_SIZE_RATIOS.SMALL], showValuesInLegend: [shouldShowValuesInLegend(layer, state.shape)], percentDecimals: [ state.shape === 'waffle' diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index c9cbe63c98d8c..6910a3ea0966c 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -225,7 +225,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat options={emptySizeRatioOptions} idSelected={ emptySizeRatioOptions.find(({ value }) => value === layer.emptySizeRatio)?.id ?? - 'emptySizeRatioOption-medium' + 'emptySizeRatioOption-small' } onChange={onEmptySizeRatioChange} data-test-subj="lnsEmptySizeRatioButtonGroup"