diff --git a/src/plugins/vis_default_editor/public/components/options/index.ts b/src/plugins/vis_default_editor/public/components/options/index.ts
index 31b09977f5c99..62ce76014f9fc 100644
--- a/src/plugins/vis_default_editor/public/components/options/index.ts
+++ b/src/plugins/vis_default_editor/public/components/options/index.ts
@@ -16,3 +16,4 @@ export { RangeOption } from './range';
export { RequiredNumberInputOption } from './required_number_input';
export { TextInputOption } from './text_input';
export { PercentageModeOption } from './percentage_mode';
+export { LongLegendOptions } from './long_legend_options';
diff --git a/src/plugins/vis_default_editor/public/components/options/long_legend_options.test.tsx b/src/plugins/vis_default_editor/public/components/options/long_legend_options.test.tsx
new file mode 100644
index 0000000000000..69994bb279278
--- /dev/null
+++ b/src/plugins/vis_default_editor/public/components/options/long_legend_options.test.tsx
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { mountWithIntl } from '@kbn/test/jest';
+import { LongLegendOptions, LongLegendOptionsProps } from './long_legend_options';
+import { EuiFieldNumber } from '@elastic/eui';
+
+describe('LongLegendOptions', () => {
+ let props: LongLegendOptionsProps;
+ let component;
+ beforeAll(() => {
+ props = {
+ truncateLegend: true,
+ setValue: jest.fn(),
+ };
+ });
+
+ it('renders the EuiFieldNumber', () => {
+ component = mountWithIntl();
+ expect(component.find(EuiFieldNumber).length).toBe(1);
+ });
+
+ it('should call setValue when value is changes in the number input', () => {
+ component = mountWithIntl();
+ const numberField = component.find(EuiFieldNumber);
+ numberField.props().onChange!(({
+ target: {
+ value: 3,
+ },
+ } as unknown) as React.ChangeEvent);
+
+ expect(props.setValue).toHaveBeenCalledWith('maxLegendLines', 3);
+ });
+
+ it('input number should be disabled when truncate is false', () => {
+ props.truncateLegend = false;
+ component = mountWithIntl();
+ const numberField = component.find(EuiFieldNumber);
+
+ expect(numberField.props().disabled).toBeTruthy();
+ });
+});
diff --git a/src/plugins/vis_default_editor/public/components/options/long_legend_options.tsx b/src/plugins/vis_default_editor/public/components/options/long_legend_options.tsx
new file mode 100644
index 0000000000000..80ea92a0b0540
--- /dev/null
+++ b/src/plugins/vis_default_editor/public/components/options/long_legend_options.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { EuiFieldNumber, EuiFormRow } from '@elastic/eui';
+import { SwitchOption } from './switch';
+
+export interface LongLegendOptionsProps {
+ setValue: (paramName: 'maxLegendLines' | 'truncateLegend', value: boolean | number) => void;
+ truncateLegend: boolean;
+ maxLegendLines?: number;
+ 'data-test-subj'?: string;
+}
+
+function LongLegendOptions({
+ 'data-test-subj': dataTestSubj,
+ setValue,
+ truncateLegend,
+ maxLegendLines,
+}: LongLegendOptionsProps) {
+ return (
+ <>
+
+
+ }
+ >
+ {
+ setValue('maxLegendLines', Number(e.target.value));
+ }}
+ />
+
+ >
+ );
+}
+
+export { LongLegendOptions };
diff --git a/src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap b/src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap
index 6c43072b97c28..fb51717d1adc0 100644
--- a/src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap
+++ b/src/plugins/vis_type_pie/public/__snapshots__/pie_fn.test.ts.snap
@@ -57,6 +57,7 @@ Object {
"valuesFormat": "percent",
},
"legendPosition": "right",
+ "maxLegendLines": true,
"metric": Object {
"accessor": 0,
"aggType": "count",
@@ -72,6 +73,7 @@ Object {
},
"splitColumn": undefined,
"splitRow": undefined,
+ "truncateLegend": true,
},
"visData": Object {
"columns": Array [
diff --git a/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx b/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx
index 524986524fd7e..d37f4c10ea9ea 100644
--- a/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx
+++ b/src/plugins/vis_type_pie/public/editor/components/pie.test.tsx
@@ -73,6 +73,20 @@ describe('PalettePicker', function () {
});
});
+ it('renders the long legend options for the elastic charts implementation', async () => {
+ component = mountWithIntl();
+ await act(async () => {
+ expect(findTestSubject(component, 'pieLongLegendsOptions').length).toBe(1);
+ });
+ });
+
+ it('not renders the long legend options for the vislib implementation', async () => {
+ component = mountWithIntl();
+ await act(async () => {
+ expect(findTestSubject(component, 'pieLongLegendsOptions').length).toBe(0);
+ });
+ });
+
it('renders the label position dropdown for the elastic charts implementation', async () => {
component = mountWithIntl();
await act(async () => {
diff --git a/src/plugins/vis_type_pie/public/editor/components/pie.tsx b/src/plugins/vis_type_pie/public/editor/components/pie.tsx
index 8ce4f4defbaed..2e64874d1b57c 100644
--- a/src/plugins/vis_type_pie/public/editor/components/pie.tsx
+++ b/src/plugins/vis_type_pie/public/editor/components/pie.tsx
@@ -26,6 +26,7 @@ import {
SwitchOption,
SelectOption,
PalettePicker,
+ LongLegendOptions,
} from '../../../../vis_default_editor/public';
import { VisEditorOptionsProps } from '../../../../visualizations/public';
import { TruncateLabelsOption } from './truncate_labels';
@@ -169,6 +170,12 @@ const PieOptions = (props: PieOptionsProps) => {
}}
data-test-subj="visTypePieNestedLegendSwitch"
/>
+
>
)}
{props.showElasticChartsOptions && palettesRegistry && (
diff --git a/src/plugins/vis_type_pie/public/mocks.ts b/src/plugins/vis_type_pie/public/mocks.ts
index 53579422e44eb..6cf291b8bf370 100644
--- a/src/plugins/vis_type_pie/public/mocks.ts
+++ b/src/plugins/vis_type_pie/public/mocks.ts
@@ -279,6 +279,8 @@ export const createMockPieParams = (): PieVisParams => {
},
legendPosition: 'right',
nestedLegend: false,
+ maxLegendLines: 1,
+ truncateLegend: true,
distinctColors: false,
palette: {
name: 'default',
diff --git a/src/plugins/vis_type_pie/public/pie_component.tsx b/src/plugins/vis_type_pie/public/pie_component.tsx
index c0f4a8a6112f8..9119f2f2ecd6c 100644
--- a/src/plugins/vis_type_pie/public/pie_component.tsx
+++ b/src/plugins/vis_type_pie/public/pie_component.tsx
@@ -320,7 +320,16 @@ const PieComponent = (props: PieComponentProps) => {
services.actions,
services.fieldFormats
)}
- theme={chartTheme}
+ theme={[
+ chartTheme,
+ {
+ legend: {
+ labelOptions: {
+ maxLines: visParams.truncateLegend ? visParams.maxLegendLines ?? 1 : 0,
+ },
+ },
+ },
+ ]}
baseTheme={chartBaseTheme}
onRenderChange={onRenderChange}
/>
diff --git a/src/plugins/vis_type_pie/public/pie_fn.test.ts b/src/plugins/vis_type_pie/public/pie_fn.test.ts
index 3dcef406379c2..33b5f38cbe630 100644
--- a/src/plugins/vis_type_pie/public/pie_fn.test.ts
+++ b/src/plugins/vis_type_pie/public/pie_fn.test.ts
@@ -23,6 +23,8 @@ describe('interpreter/functions#pie', () => {
legendPosition: 'right',
isDonut: true,
nestedLegend: true,
+ truncateLegend: true,
+ maxLegendLines: true,
distinctColors: false,
palette: 'kibana_palette',
labels: {
diff --git a/src/plugins/vis_type_pie/public/pie_fn.ts b/src/plugins/vis_type_pie/public/pie_fn.ts
index 65ac648ca2868..c5987001d4494 100644
--- a/src/plugins/vis_type_pie/public/pie_fn.ts
+++ b/src/plugins/vis_type_pie/public/pie_fn.ts
@@ -89,6 +89,19 @@ export const createPieVisFn = (): VisTypePieExpressionFunctionDefinition => ({
}),
default: false,
},
+ truncateLegend: {
+ types: ['boolean'],
+ help: i18n.translate('visTypePie.function.args.truncateLegendHelpText', {
+ defaultMessage: 'Defines if the legend items will be truncated or not',
+ }),
+ default: true,
+ },
+ maxLegendLines: {
+ types: ['number'],
+ help: i18n.translate('visTypePie.function.args.maxLegendLinesHelpText', {
+ defaultMessage: 'Defines the number of lines per legend item',
+ }),
+ },
distinctColors: {
types: ['boolean'],
help: i18n.translate('visTypePie.function.args.distinctColorsHelpText', {
diff --git a/src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts
index 3b07743e79f45..7e0bcdfd9b5c9 100644
--- a/src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts
+++ b/src/plugins/vis_type_pie/public/sample_vis.test.mocks.ts
@@ -28,6 +28,8 @@ export const samplePieVis = {
legendPosition: 'right',
isDonut: true,
nestedLegend: true,
+ truncateLegend: true,
+ maxLegendLines: 1,
distinctColors: false,
palette: 'kibana_palette',
labels: {
diff --git a/src/plugins/vis_type_pie/public/to_ast.ts b/src/plugins/vis_type_pie/public/to_ast.ts
index e8c9f301b4366..b360e375bf40d 100644
--- a/src/plugins/vis_type_pie/public/to_ast.ts
+++ b/src/plugins/vis_type_pie/public/to_ast.ts
@@ -50,6 +50,8 @@ export const toExpressionAst: VisToExpressionAst = async (vis, par
addLegend: vis.params.addLegend,
legendPosition: vis.params.legendPosition,
nestedLegend: vis.params?.nestedLegend,
+ truncateLegend: vis.params.truncateLegend,
+ maxLegendLines: vis.params.maxLegendLines,
distinctColors: vis.params?.distinctColors,
isDonut: vis.params.isDonut,
palette: vis.params?.palette?.name,
diff --git a/src/plugins/vis_type_pie/public/types/types.ts b/src/plugins/vis_type_pie/public/types/types.ts
index 4f3365545d062..94eaeb55f7242 100644
--- a/src/plugins/vis_type_pie/public/types/types.ts
+++ b/src/plugins/vis_type_pie/public/types/types.ts
@@ -33,6 +33,8 @@ interface PieCommonParams {
addLegend: boolean;
legendPosition: Position;
nestedLegend: boolean;
+ truncateLegend: boolean;
+ maxLegendLines: number;
distinctColors: boolean;
isDonut: boolean;
}
diff --git a/src/plugins/vis_type_pie/public/utils/get_columns.test.ts b/src/plugins/vis_type_pie/public/utils/get_columns.test.ts
index 3170628ec2e12..9f64266ed0e0e 100644
--- a/src/plugins/vis_type_pie/public/utils/get_columns.test.ts
+++ b/src/plugins/vis_type_pie/public/utils/get_columns.test.ts
@@ -144,6 +144,8 @@ describe('getColumns', () => {
},
legendPosition: 'right',
nestedLegend: false,
+ maxLegendLines: 1,
+ truncateLegend: false,
palette: {
name: 'default',
type: 'palette',
diff --git a/src/plugins/vis_type_pie/public/vis_type/pie.ts b/src/plugins/vis_type_pie/public/vis_type/pie.ts
index 9d1556ac33ad7..95a9d0d41481b 100644
--- a/src/plugins/vis_type_pie/public/vis_type/pie.ts
+++ b/src/plugins/vis_type_pie/public/vis_type/pie.ts
@@ -35,6 +35,8 @@ export const getPieVisTypeDefinition = ({
addLegend: !showElasticChartsOptions,
legendPosition: Position.Right,
nestedLegend: false,
+ truncateLegend: true,
+ maxLegendLines: 1,
distinctColors: false,
isDonut: true,
palette: {
diff --git a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap
index 7c21e699216bc..7ee1b0d2b2053 100644
--- a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap
+++ b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap
@@ -32,6 +32,9 @@ Object {
"legendPosition": Array [
"top",
],
+ "maxLegendLines": Array [
+ 1,
+ ],
"palette": Array [
"default",
],
@@ -51,6 +54,9 @@ Object {
},
],
"times": Array [],
+ "truncateLegend": Array [
+ true,
+ ],
"type": Array [
"area",
],
diff --git a/src/plugins/vis_type_xy/public/components/xy_settings.tsx b/src/plugins/vis_type_xy/public/components/xy_settings.tsx
index 03455bae69506..2dd7d7e0a91f9 100644
--- a/src/plugins/vis_type_xy/public/components/xy_settings.tsx
+++ b/src/plugins/vis_type_xy/public/components/xy_settings.tsx
@@ -60,6 +60,8 @@ type XYSettingsProps = Pick<
legendAction?: LegendAction;
legendColorPicker: LegendColorPicker;
legendPosition: Position;
+ truncateLegend: boolean;
+ maxLegendLines: number;
};
function getValueLabelsStyling() {
@@ -93,6 +95,8 @@ export const XYSettings: FC = ({
legendAction,
legendColorPicker,
legendPosition,
+ maxLegendLines,
+ truncateLegend,
}) => {
const themeService = getThemeService();
const theme = themeService.useChartsTheme();
@@ -113,6 +117,9 @@ export const XYSettings: FC = ({
crosshair: {
...theme.crosshair,
},
+ legend: {
+ labelOptions: { maxLines: truncateLegend ? maxLegendLines ?? 1 : 0 },
+ },
axes: {
axisTitle: {
padding: {
diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts
index f23d9e4ada336..823fc54f6c92f 100644
--- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts
+++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts
@@ -426,6 +426,8 @@ export const getVis = (bucketType: string) => {
fittingFunction: 'linear',
times: [],
addTimeMarker: false,
+ maxLegendLines: 1,
+ truncateLegend: true,
radiusRatio: 9,
thresholdLine: {
show: false,
@@ -849,6 +851,8 @@ export const getStateParams = (type: string, thresholdPanelOn: boolean) => {
legendPosition: 'right',
times: [],
addTimeMarker: false,
+ maxLegendLines: 1,
+ truncateLegend: true,
detailedTooltip: true,
palette: {
type: 'palette',
diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx
index 59c03e02ac9f4..7fedd38e4e7ec 100644
--- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx
+++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.test.tsx
@@ -105,6 +105,26 @@ describe('PointSeries Editor', function () {
});
});
+ it('not renders the long legend options if showElasticChartsOptions is false', async () => {
+ component = mountWithIntl();
+ await act(async () => {
+ expect(findTestSubject(component, 'xyLongLegendsOptions').length).toBe(0);
+ });
+ });
+
+ it('renders the long legend options if showElasticChartsOptions is true', async () => {
+ const newVisProps = ({
+ ...props,
+ extraProps: {
+ showElasticChartsOptions: true,
+ },
+ } as unknown) as PointSeriesOptionsProps;
+ component = mountWithIntl();
+ await act(async () => {
+ expect(findTestSubject(component, 'xyLongLegendsOptions').length).toBe(1);
+ });
+ });
+
it('not renders the fitting function for a bar chart', async () => {
const newVisProps = ({
...props,
diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx
index 343976651d21e..1fd9b043e87f5 100644
--- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx
+++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.tsx
@@ -11,7 +11,11 @@ import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { BasicOptions, SwitchOption } from '../../../../../../vis_default_editor/public';
+import {
+ BasicOptions,
+ SwitchOption,
+ LongLegendOptions,
+} from '../../../../../../vis_default_editor/public';
import { BUCKET_TYPES } from '../../../../../../data/public';
import { VisParams } from '../../../../types';
@@ -58,6 +62,14 @@ export function PointSeriesOptions(
+ {props.extraProps?.showElasticChartsOptions && (
+
+ )}
{vis.data.aggs!.aggs.some(
(agg) => agg.schema === 'segment' && agg.type.name === BUCKET_TYPES.DATE_HISTOGRAM
diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts
index 35f3b2d7c627d..6d2b860066b07 100644
--- a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts
+++ b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts
@@ -55,6 +55,18 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({
defaultMessage: 'Show time marker',
}),
},
+ truncateLegend: {
+ types: ['boolean'],
+ help: i18n.translate('visTypeXy.function.args.truncateLegend.help', {
+ defaultMessage: 'Defines if the legend will be truncated or not',
+ }),
+ },
+ maxLegendLines: {
+ types: ['number'],
+ help: i18n.translate('visTypeXy.function.args.args.maxLegendLines.help', {
+ defaultMessage: 'Defines the maximum lines per legend item',
+ }),
+ },
addLegend: {
types: ['boolean'],
help: i18n.translate('visTypeXy.function.args.addLegend.help', {
@@ -225,6 +237,8 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({
addTooltip: args.addTooltip,
legendPosition: args.legendPosition,
addTimeMarker: args.addTimeMarker,
+ maxLegendLines: args.maxLegendLines,
+ truncateLegend: args.truncateLegend,
categoryAxes: args.categoryAxes.map((categoryAxis) => ({
...categoryAxis,
type: categoryAxis.axisType,
diff --git a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts
index 8fafd4c723055..7fff29edfab51 100644
--- a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts
+++ b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts
@@ -88,6 +88,8 @@ export const sampleAreaVis = {
legendPosition: 'right',
times: [],
addTimeMarker: false,
+ truncateLegend: true,
+ maxLegendLines: 1,
thresholdLine: {
show: false,
value: 10,
@@ -255,6 +257,8 @@ export const sampleAreaVis = {
legendPosition: 'top',
times: [],
addTimeMarker: false,
+ truncateLegend: true,
+ maxLegendLines: 1,
thresholdLine: {
show: false,
value: 10,
diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts
index 9fec3f99ab39b..0b1eb5262d71a 100644
--- a/src/plugins/vis_type_xy/public/to_ast.ts
+++ b/src/plugins/vis_type_xy/public/to_ast.ts
@@ -194,6 +194,8 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params
type: vis.type.name as XyVisType,
chartType: vis.params.type,
addTimeMarker: vis.params.addTimeMarker,
+ truncateLegend: vis.params.truncateLegend,
+ maxLegendLines: vis.params.maxLegendLines,
addLegend: vis.params.addLegend,
addTooltip: vis.params.addTooltip,
legendPosition: vis.params.legendPosition,
diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts
index 421690f7fc6a9..0687bd2af2cd1 100644
--- a/src/plugins/vis_type_xy/public/types/param.ts
+++ b/src/plugins/vis_type_xy/public/types/param.ts
@@ -121,6 +121,8 @@ export interface VisParams {
addTooltip: boolean;
legendPosition: Position;
addTimeMarker: boolean;
+ truncateLegend: boolean;
+ maxLegendLines: number;
categoryAxes: CategoryAxis[];
orderBucketsBySum?: boolean;
labels: Labels;
@@ -158,6 +160,8 @@ export interface XYVisConfig {
addTooltip: boolean;
legendPosition: Position;
addTimeMarker: boolean;
+ truncateLegend: boolean;
+ maxLegendLines: number;
orderBucketsBySum?: boolean;
labels: ExpressionValueLabel;
thresholdLine: ExpressionValueThresholdLine;
diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_type_xy/public/vis_component.tsx
index 2dffabb2ba0b9..346f6cc74a1ac 100644
--- a/src/plugins/vis_type_xy/public/vis_component.tsx
+++ b/src/plugins/vis_type_xy/public/vis_component.tsx
@@ -345,6 +345,8 @@ const VisComponent = (props: VisComponentProps) => {
/>