Skip to content

Commit

Permalink
[Lens] Waffle visualization type (#119339)
Browse files Browse the repository at this point in the history
* [WIP][Lens] Waffle visualization type

Closes:  #107059

* add showExtraLegend for waffle

* add tests

* resolved 1 and 5

* resolved 6

* add sortPredicate for waffle chart type

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
alexwizp and kibanamachine authored Dec 2, 2021
1 parent 54c4df0 commit 3cd176f
Show file tree
Hide file tree
Showing 12 changed files with 641 additions and 239 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/lens/common/expressions/pie_chart/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
31 changes: 31 additions & 0 deletions x-pack/plugins/lens/public/assets/chart_waffle.tsx
Original file line number Diff line number Diff line change
@@ -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>
);
97 changes: 0 additions & 97 deletions x-pack/plugins/lens/public/pie_visualization/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
214 changes: 214 additions & 0 deletions x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* 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 { ArrayEntry, 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';
import type { DatatableColumn } from '../../../../../src/plugins/expressions';

interface PartitionChartMeta {
icon: ({ title, titleId, ...props }: Omit<EuiIconProps, 'type'>) => JSX.Element;
label: string;
partitionType: PartitionLayout;
groupLabel: 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;
getShowLegendDefault?: (bucketColumns: DatatableColumn[]) => boolean;
};
sortPredicate?: (
bucketColumns: DatatableColumn[],
sortingMap: Record<string, number>
) => (node1: ArrayEntry, node2: ArrayEntry) => number;
}

const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', {
defaultMessage: 'Proportion',
});

const categoryOptions: PartitionChartMeta['toolbarPopover']['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['toolbarPopover']['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['toolbarPopover']['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,
maxBuckets: 3,
toolbarPopover: {
categoryOptions,
numberOptions,
},
legend: {
getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1,
},
},
pie: {
icon: LensIconChartPie,
label: i18n.translate('xpack.lens.pie.pielabel', {
defaultMessage: 'Pie',
}),
partitionType: PartitionLayout.sunburst,
groupLabel,
maxBuckets: 3,
toolbarPopover: {
categoryOptions,
numberOptions,
},
legend: {
getShowLegendDefault: (bucketColumns) => bucketColumns.length > 1,
},
},
treemap: {
icon: LensIconChartTreemap,
label: i18n.translate('xpack.lens.pie.treemaplabel', {
defaultMessage: 'Treemap',
}),
partitionType: PartitionLayout.treemap,
groupLabel,
maxBuckets: 2,
toolbarPopover: {
categoryOptions: categoryOptionsTreemap,
numberOptions,
},
legend: {
getShowLegendDefault: () => false,
},
},
mosaic: {
icon: LensIconChartMosaic,
label: i18n.translate('xpack.lens.pie.mosaiclabel', {
defaultMessage: 'Mosaic',
}),
partitionType: PartitionLayout.mosaic,
groupLabel,
maxBuckets: 2,
isExperimental: true,
toolbarPopover: {
categoryOptions: [],
numberOptions,
},
legend: {
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,
label: i18n.translate('xpack.lens.pie.wafflelabel', {
defaultMessage: 'Waffle',
}),
partitionType: PartitionLayout.waffle,
groupLabel,
maxBuckets: 1,
isExperimental: true,
toolbarPopover: {
isDisabled: true,
categoryOptions: [],
numberOptions: [],
},
legend: {
flat: true,
showValues: true,
getShowLegendDefault: () => true,
},
sortPredicate:
() =>
([, node1], [, node2]) =>
node2.value - node1.value,
},
};
Loading

0 comments on commit 3cd176f

Please sign in to comment.