diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap index 3ca2834a54fca2..8b720568c4d2c4 100644 --- a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap @@ -8,7 +8,7 @@ Object { "area", ], "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"circlesRadius\\":5,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_type_xy/public/config/get_config.ts b/src/plugins/vis_type_xy/public/config/get_config.ts index 8ebac1b71940a1..ce01572060a408 100644 --- a/src/plugins/vis_type_xy/public/config/get_config.ts +++ b/src/plugins/vis_type_xy/public/config/get_config.ts @@ -39,6 +39,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { fittingFunction, detailedTooltip, isVislibVis, + fillOpacity, } = params; const aspects = getAspects(table.columns, params.dimensions); const xAxis = getAxis( @@ -63,6 +64,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { // NOTE: downscale ratio to match current vislib implementation markSizeRatio: radiusRatio * 0.6, fittingFunction, + fillOpacity, detailedTooltip, orderBucketsBySum, isTimeChart, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap index 40e53d88f99cfc..05e2532073eaf4 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap @@ -7,6 +7,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", @@ -79,6 +80,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap index 7b45423f5f861e..8764db1dea06ad 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap @@ -54,14 +54,5 @@ exports[`LineOptions component should init with the default set of props 1`] = ` /> - - `; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap new file mode 100644 index 00000000000000..fcd6f8d00a1385 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PointOptions component should init with the default set of props 1`] = ` + + + + + + + + +`; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx index def24d51f49f39..1d5c8be2b92464 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx @@ -12,6 +12,7 @@ import { shallow, mount } from 'enzyme'; import { ChartOptions, ChartOptionsParams } from './chart_options'; import { SeriesParam, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { valueAxis, seriesParam } from './mocks'; import { ChartType } from '../../../../../common'; @@ -41,6 +42,12 @@ describe('ChartOptions component', () => { expect(comp).toMatchSnapshot(); }); + it('should hide the PointOptions when type is bar', () => { + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeFalsy(); + }); + it('should show LineOptions when type is line', () => { chart.type = ChartType.Line; const comp = shallow(); @@ -48,6 +55,13 @@ describe('ChartOptions component', () => { expect(comp.find(LineOptions).exists()).toBeTruthy(); }); + it('should show PointOptions when type is area', () => { + chart.type = ChartType.Area; + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeTruthy(); + }); + it('should show line mode when type is area', () => { chart.type = ChartType.Area; const comp = shallow(); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx index 23452a87aae605..34ee33781f269d 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx @@ -15,6 +15,7 @@ import { SelectOption } from '../../../../../../vis_default_editor/public'; import { SeriesParam, ValueAxis, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { SetParamByIndex, ChangeValueAxis } from '.'; import { ChartType } from '../../../../../common'; import { getConfigCollections } from '../../../collections'; @@ -143,6 +144,9 @@ function ChartOptions({ )} {chart.type === ChartType.Line && } + {(chart.type === ChartType.Area || chart.type === ChartType.Line) && ( + + )} ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx index 140f190c77181e..75dfe8627d73ea 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx @@ -78,17 +78,6 @@ function LineOptions({ chart, setChart }: LineOptionsParams) { /> - - - - ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts index 7451f6dea9039b..eed224cf2a514a 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts @@ -75,6 +75,7 @@ const seriesParam: SeriesParam = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: defaultValueAxisId, }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx new file mode 100644 index 00000000000000..68ac1832d28a89 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx @@ -0,0 +1,44 @@ +/* + * 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 { shallow, mount } from 'enzyme'; +import { findTestSubject } from '@elastic/eui/lib/test'; + +import { SeriesParam } from '../../../../types'; +import { PointOptions, PointOptionsParams } from './point_options'; +import { seriesParam } from './mocks'; + +describe('PointOptions component', () => { + let setChart: jest.Mock; + let defaultProps: PointOptionsParams; + let chart: SeriesParam; + + beforeEach(() => { + setChart = jest.fn(); + chart = { ...seriesParam }; + + defaultProps = { + chart, + setChart, + }; + }); + + it('should init with the default set of props', () => { + const comp = shallow(); + + expect(comp).toMatchSnapshot(); + }); + + it('should disable the dots size range if the show dots switch is off', () => { + chart.showCircles = false; + const comp = mount(); + const range = findTestSubject(comp, 'circlesRadius'); + expect(range.at(1).props().disabled).toBeTruthy(); + }); +}); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx new file mode 100644 index 00000000000000..d35a5a2374ca34 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx @@ -0,0 +1,63 @@ +/* + * 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 { EuiRange, EuiFormRow, EuiSpacer } from '@elastic/eui'; + +import { SwitchOption } from '../../../../../../vis_default_editor/public'; + +import { SeriesParam } from '../../../../types'; +import { SetChart } from './chart_options'; + +export interface PointOptionsParams { + chart: SeriesParam; + setChart: SetChart; +} + +function PointOptions({ chart, setChart }: PointOptionsParams) { + return ( + <> + + + + + { + setChart('circlesRadius', Number(e.currentTarget.value)); + }} + /> + + + ); +} + +export { PointOptions }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts index d0d0c08060acf5..a8d53e45bc988b 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts @@ -26,6 +26,7 @@ export const makeSerie = ( type: ChartType.Line, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, lineWidth: 2, valueAxis: defaultValueAxis, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx index 5398980e268d48..271c5445a95807 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx @@ -10,7 +10,7 @@ import React, { useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE } from '@kbn/analytics'; - +import { EuiFormRow, EuiRange } from '@elastic/eui'; import { SelectOption, SwitchOption, @@ -31,10 +31,14 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps const [palettesRegistry, setPalettesRegistry] = useState(null); const { stateParams, setValue, aggs } = props; - const hasLineChart = stateParams.seriesParams.some( + const isLineChart = stateParams.seriesParams.some( + ({ type, data: { id: paramId } }) => + type === ChartType.Line && aggs.aggs.find(({ id }) => id === paramId)?.enabled + ); + + const isAreaChart = stateParams.seriesParams.some( ({ type, data: { id: paramId } }) => - (type === ChartType.Line || type === ChartType.Area) && - aggs.aggs.find(({ id }) => id === paramId)?.enabled + type === ChartType.Area && aggs.aggs.find(({ id }) => id === paramId)?.enabled ); useEffect(() => { @@ -66,7 +70,7 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps }} /> - {hasLineChart && ( + {(isLineChart || isAreaChart) && ( }} /> )} + {isAreaChart && ( + + { + setValue('fillOpacity', Number(e.currentTarget.value)); + }} + /> + + )} ); } 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 eb8d4d1c440d70..f23d9e4ada3361 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 @@ -410,6 +410,7 @@ export const getVis = (bucketType: string) => { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -838,6 +839,7 @@ export const getStateParams = (type: string, thresholdPanelOn: boolean) => { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: 'cardinal', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts index 402187cea65866..3fd62e33e257fe 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts @@ -29,6 +29,7 @@ export type ExpressionValueSeriesParam = ExpressionValueBoxed< mode: SeriesParam['mode']; show: boolean; showCircles: boolean; + circlesRadius: number; seriesParamType: SeriesParam['type']; valueAxis: string; } @@ -98,6 +99,12 @@ export const seriesParam = (): ExpressionFunctionDefinition< defaultMessage: 'Show circles', }), }, + circlesRadius: { + types: ['number'], + help: i18n.translate('visTypeXy.function.seriesParam.circlesRadius.help', { + defaultMessage: 'Defines the circles size (radius)', + }), + }, type: { types: ['string'], help: i18n.translate('visTypeXy.function.seriesParam.type.help', { @@ -121,6 +128,7 @@ export const seriesParam = (): ExpressionFunctionDefinition< mode: args.mode, show: args.show, showCircles: args.showCircles, + circlesRadius: args.circlesRadius, seriesParamType: args.type, valueAxis: args.valueAxis, }; 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 b8b8c0e8b8cca8..29403a12fdce63 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 @@ -161,6 +161,12 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ defaultMessage: 'Defines the chart palette name', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('visTypeXy.function.args.fillOpacity.help', { + defaultMessage: 'Defines the area chart fill opacity', + }), + }, xDimension: { types: ['xy_dimension', 'null'], help: i18n.translate('visTypeXy.function.args.xDimension.help', { @@ -242,6 +248,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ type: 'palette', name: args.palette, }, + fillOpacity: args.fillOpacity, fittingFunction: args.fittingFunction, dimensions: { x: args.xDimension, 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 e15f9c42077020..39370d941b52ac 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 @@ -1397,6 +1397,7 @@ export const sampleAreaVis = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -1417,6 +1418,7 @@ export const sampleAreaVis = { palette: { name: 'default', }, + fillOpacity: 0.5, }, }, editorConfig: { @@ -1562,6 +1564,7 @@ export const sampleAreaVis = { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 5, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts index c0a0ee566a4453..f473cd77c2d2b7 100644 --- a/src/plugins/vis_type_xy/public/to_ast.ts +++ b/src/plugins/vis_type_xy/public/to_ast.ts @@ -98,6 +98,7 @@ const prepareSeriesParam = (data: SeriesParam) => { mode: data.mode, show: data.show, showCircles: data.showCircles, + circlesRadius: data.circlesRadius, type: data.type, valueAxis: data.valueAxis, }); @@ -207,6 +208,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params fittingFunction: vis.params.fittingFunction, times: vis.params.times.map(prepareTimeMarker), palette: vis.params.palette.name, + fillOpacity: vis.params.fillOpacity, xDimension: dimensions.x ? prepareXYDimension(dimensions.x) : null, yDimension: dimensions.y.map(prepareXYDimension), zDimension: dimensions.z?.map(prepareXYDimension), diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_type_xy/public/types/config.ts index f025a36a82410a..e52b47366bc857 100644 --- a/src/plugins/vis_type_xy/public/types/config.ts +++ b/src/plugins/vis_type_xy/public/types/config.ts @@ -116,6 +116,7 @@ export interface VisConfig { showValueLabel: boolean; enableHistogramMode: boolean; fittingFunction?: Exclude; + fillOpacity?: number; detailedTooltip?: boolean; isVislibVis?: boolean; } diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts index f90899620126aa..7a2ff7e2402640 100644 --- a/src/plugins/vis_type_xy/public/types/param.ts +++ b/src/plugins/vis_type_xy/public/types/param.ts @@ -78,6 +78,7 @@ export interface SeriesParam { mode: ChartMode; show: boolean; showCircles: boolean; + circlesRadius: number; type: ChartType; valueAxis: string; } @@ -155,6 +156,7 @@ export interface VisParams { */ detailedTooltip?: boolean; palette: PaletteOutput; + fillOpacity?: number; fittingFunction?: Exclude; } @@ -186,6 +188,7 @@ export interface XYVisConfig { */ detailedTooltip?: boolean; fittingFunction?: Exclude; + fillOpacity?: number; xDimension: ExpressionValueXYDimension | null; yDimension: ExpressionValueXYDimension[]; zDimension?: ExpressionValueXYDimension[]; diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx index 628d3620090ca1..23dabef662d559 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx @@ -31,6 +31,7 @@ const defaultSeriesParams = [ mode: 'stacked', show: true, showCircles: true, + circlesRadius: 3, type: 'area', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx index 3bce5ddc2e85e6..e915e6d4966c50 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx @@ -51,7 +51,15 @@ const getCurveType = (type?: 'linear' | 'cardinal' | 'step-after'): CurveType => * @param getSeriesColor */ export const renderAllSeries = ( - { aspects, yAxes, xAxis, showValueLabel, enableHistogramMode, fittingFunction }: VisConfig, + { + aspects, + yAxes, + xAxis, + showValueLabel, + enableHistogramMode, + fittingFunction, + fillOpacity, + }: VisConfig, seriesParams: SeriesParam[], data: DatatableRow[], getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName, @@ -67,6 +75,7 @@ export const renderAllSeries = ( data: { id: paramId }, lineWidth: strokeWidth, showCircles, + circlesRadius, drawLinesBetweenPoints, mode, interpolate, @@ -158,7 +167,7 @@ export const renderAllSeries = ( stackMode={stackMode} areaSeriesStyle={{ area: { - ...(type === ChartType.Line && { opacity: 0 }), + ...(type === ChartType.Line ? { opacity: 0 } : { opacity: fillOpacity }), }, line: { strokeWidth, @@ -167,6 +176,7 @@ export const renderAllSeries = ( point: { visible: showCircles, fill: markSizeAccessor ? ColorVariant.Series : undefined, + radius: circlesRadius, }, }} /> diff --git a/src/plugins/vis_type_xy/public/vis_types/area.ts b/src/plugins/vis_type_xy/public/vis_types/area.ts index f22f8df1752d66..912b3d8d48e952 100644 --- a/src/plugins/vis_type_xy/public/vis_types/area.ts +++ b/src/plugins/vis_type_xy/public/vis_types/area.ts @@ -98,6 +98,7 @@ export const getAreaVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/vis_types/histogram.ts b/src/plugins/vis_type_xy/public/vis_types/histogram.ts index 732833ffecc802..9af4cfd7b43a3e 100644 --- a/src/plugins/vis_type_xy/public/vis_types/histogram.ts +++ b/src/plugins/vis_type_xy/public/vis_types/histogram.ts @@ -102,6 +102,7 @@ export const getHistogramVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], radiusRatio: 0, diff --git a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts index 791d93bb646b23..874e69b246a4d9 100644 --- a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts +++ b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts @@ -103,6 +103,7 @@ export const getHorizontalBarVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/src/plugins/vis_type_xy/public/vis_types/line.ts b/src/plugins/vis_type_xy/public/vis_types/line.ts index 6316fe44582290..2e8944f44daab8 100644 --- a/src/plugins/vis_type_xy/public/vis_types/line.ts +++ b/src/plugins/vis_type_xy/public/vis_types/line.ts @@ -100,6 +100,7 @@ export const getLineVisTypeDefinition = ( lineWidth: 2, interpolate: InterpolationMode.Linear, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap index 339fb5a7ab68f3..08b3393fafe482 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap @@ -33,6 +33,9 @@ Object { "description": Array [ "", ], + "fillOpacity": Array [ + 0.3, + ], "fittingFunction": Array [ "Carry", ], diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 006727b05b9056..e3b4565913ad87 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -196,6 +196,12 @@ export const xyChart: ExpressionFunctionDefinition< defaultMessage: 'Define how curve type is rendered for a line chart', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('xpack.lens.xyChart.fillOpacity.help', { + defaultMessage: 'Define the area chart fill opacity', + }), + }, hideEndzones: { types: ['boolean'], default: false, @@ -812,6 +818,7 @@ export function XYChart({ visible: !xAccessor, radius: 5, }, + ...(args.fillOpacity && { area: { opacity: args.fillOpacity } }), }, lineSeriesStyle: { point: { diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index dea6b1a7be0c57..269f10159892f4 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -149,6 +149,7 @@ export const buildExpression = ( ], fittingFunction: [state.fittingFunction || 'None'], curveType: [state.curveType || 'LINEAR'], + fillOpacity: [state.fillOpacity || 0.3], yLeftExtent: [ { type: 'expression', diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index ea28b492477c18..531b034b532425 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -464,6 +464,7 @@ export interface XYArgs { tickLabelsVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_tickLabelsConfig' }; gridlinesVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_gridlinesConfig' }; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } @@ -485,6 +486,7 @@ export interface XYState { tickLabelsVisibilitySettings?: AxesSettingsConfig; gridlinesVisibilitySettings?: AxesSettingsConfig; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx new file mode 100644 index 00000000000000..3ba29e4f72c837 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx @@ -0,0 +1,35 @@ +/* + * 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 { mountWithIntl as mount, shallowWithIntl as shallow } from '@kbn/test/jest'; +import { EuiRange } from '@elastic/eui'; +import { FillOpacityOption } from './fill_opacity_option'; + +describe('Line curve option', () => { + it('should show currently selected opacity value', () => { + const component = shallow(); + + expect(component.find(EuiRange).prop('value')).toEqual(0.3); + }); + + it('should show fill opacity option when enabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(true); + }); + + it('should hide curve option when disabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(false); + }); +}); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx new file mode 100644 index 00000000000000..eb8d35c54a99b9 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx @@ -0,0 +1,59 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiFormRow, EuiRange } from '@elastic/eui'; +import { useDebouncedValue } from '../../shared_components'; + +export interface FillOpacityOptionProps { + /** + * Currently selected value + */ + value: number; + /** + * Callback on display option change + */ + onChange: (value: number) => void; + /** + * Flag for rendering or not the component + */ + isFillOpacityEnabled?: boolean; +} + +export const FillOpacityOption: React.FC = ({ + onChange, + value, + isFillOpacityEnabled = true, +}) => { + const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange }); + return isFillOpacityEnabled ? ( + <> + + { + handleInputChange(Number(e.currentTarget.value)); + }} + /> + + + ) : null; +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx index fb6ecec4d28013..a683d4fbf514c3 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx @@ -7,7 +7,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonGroup, EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { + EuiButtonGroup, + EuiFormRow, + EuiIconTip, + EuiSuperSelect, + EuiText, + EuiSpacer, +} from '@elastic/eui'; import { FittingFunction, fittingFunctionDefinitions } from '../fitting_functions'; import { ValueLabelConfig } from '../types'; @@ -133,6 +140,7 @@ export const MissingValuesOptions: React.FC = ({ /> )} + ); }; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx index e7ec395312bff4..b46ad1940491e6 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx @@ -14,6 +14,7 @@ import { State } from '../types'; import { VisualOptionsPopover } from './visual_options_popover'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; +import { FillOpacityOption } from './fill_opacity_option'; describe('Visual options popover', () => { let frame: FramePublicAPI; @@ -74,6 +75,22 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should not disable the fill opacity for percentage area charts', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(true); + }); + it('should not disable the visual options for percentage area charts', () => { const state = testState(); const component = shallow( @@ -128,6 +145,40 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should hide the fill opacity option for bar series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + + it('should hide the fill opacity option for line series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + it('should show the popover and display field enabled for bar and horizontal_bar series', () => { const state = testState(); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx index b8b89f146bdc07..b07feb85892e53 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; +import { FillOpacityOption } from './fill_opacity_option'; import { XYState } from '../types'; import { hasHistogramSeries } from '../state_helpers'; import { ValidLayer } from '../types'; @@ -61,6 +62,10 @@ export const VisualOptionsPopover: React.FC = ({ ['bar', 'bar_horizontal'].includes(seriesType) ); + const hasAreaSeries = state?.layers.some(({ seriesType }) => + ['area_stacked', 'area', 'area_percentage_stacked'].includes(seriesType) + ); + const isHistogramSeries = Boolean( hasHistogramSeries(state?.layers as ValidLayer[], datasourceLayers) ); @@ -110,6 +115,17 @@ export const VisualOptionsPopover: React.FC = ({ setState({ ...state, fittingFunction: newVal }); }} /> + + { + setState({ + ...state, + fillOpacity: newValue, + }); + }} + /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts index 4554c34b97c555..aff33778258fed 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts +++ b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts @@ -524,6 +524,7 @@ function buildSuggestion({ valueLabels: currentState?.valueLabels || 'hide', fittingFunction: currentState?.fittingFunction || 'None', curveType: currentState?.curveType, + fillOpacity: currentState?.fillOpacity, xTitle: currentState?.xTitle, yTitle: currentState?.yTitle, yRightTitle: currentState?.yRightTitle,