mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Lens] improve metric palette behavior (#139596)
* handle single-value case * match continuity between metric types * fix collapse-by handling, polish logic * update snapshot Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
50c0077aba
commit
e11e6e6b30
5 changed files with 94 additions and 10 deletions
|
@ -954,7 +954,7 @@ describe('MetricVisComponent', function () {
|
|||
"stops": Array [],
|
||||
},
|
||||
Object {
|
||||
"max": 28.984375,
|
||||
"max": 57.96875,
|
||||
"min": 0,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 { Datatable, DatatableRow } from '@kbn/expressions-plugin/common';
|
||||
import { getDataBoundsForPalette } from './palette_data_bounds';
|
||||
|
||||
describe('palette data bounds', () => {
|
||||
const buildTableWithRows = (rows: DatatableRow[]) => {
|
||||
const table: Datatable = {
|
||||
type: 'datatable',
|
||||
columns: Object.keys(rows).map((key) => ({
|
||||
id: key,
|
||||
name: key,
|
||||
meta: { type: 'number' },
|
||||
})),
|
||||
rows,
|
||||
};
|
||||
|
||||
return table;
|
||||
};
|
||||
|
||||
describe('single value scenarios', () => {
|
||||
it('creates a range with the metric value in the middle', () => {
|
||||
const accessors = {
|
||||
metric: 'first',
|
||||
};
|
||||
expect(getDataBoundsForPalette(accessors, buildTableWithRows([{ first: 100 }]))).toEqual({
|
||||
min: 0,
|
||||
max: 200,
|
||||
});
|
||||
expect(getDataBoundsForPalette(accessors, buildTableWithRows([{ first: -100 }]))).toEqual({
|
||||
min: -200,
|
||||
max: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('uses maximum dimension when available', () => {
|
||||
expect(
|
||||
getDataBoundsForPalette(
|
||||
{ metric: 'metric', max: 'max' },
|
||||
buildTableWithRows([{ metric: 200, max: 100 }])
|
||||
)
|
||||
).toEqual({ min: 0, max: 100 });
|
||||
|
||||
expect(
|
||||
getDataBoundsForPalette(
|
||||
{ metric: 'metric', max: 'max' },
|
||||
buildTableWithRows([
|
||||
{ metric: 200, max: 100 },
|
||||
{ metric: 400, max: 150 },
|
||||
]),
|
||||
1
|
||||
)
|
||||
).toEqual({ min: 0, max: 150 });
|
||||
});
|
||||
});
|
||||
|
||||
it('uses minimum and maximum metric when breakdown but no max', () => {
|
||||
expect(
|
||||
getDataBoundsForPalette(
|
||||
{ metric: 'metric', breakdownBy: 'breakdown' },
|
||||
buildTableWithRows([{ metric: -100 }, { metric: 100 }, { metric: 200 }, { metric: 300 }])
|
||||
)
|
||||
).toEqual({ min: -100, max: 300 });
|
||||
});
|
||||
});
|
|
@ -19,6 +19,17 @@ export const getDataBoundsForPalette = (
|
|||
|
||||
const smallestMetric = Math.min(...data.rows.map((row) => row[accessors.metric]));
|
||||
const greatestMetric = Math.max(...data.rows.map((row) => row[accessors.metric]));
|
||||
|
||||
if (
|
||||
!accessors.max &&
|
||||
!accessors.breakdownBy &&
|
||||
(typeof rowNumber !== 'undefined' || data.rows.length === 1)
|
||||
) {
|
||||
// dealing with a single metric and no max
|
||||
const metricValue = greatestMetric;
|
||||
return metricValue < 0 ? { min: metricValue * 2, max: 0 } : { min: 0, max: metricValue * 2 };
|
||||
}
|
||||
|
||||
const greatestMaximum = accessors.max
|
||||
? rowNumber
|
||||
? data.rows[rowNumber][accessors.max]
|
||||
|
|
|
@ -15,6 +15,7 @@ export const defaultPaletteParams: RequiredPaletteParamTypes = {
|
|||
...sharedDefaultParams,
|
||||
maxSteps: 5,
|
||||
name: DEFAULT_PALETTE_NAME,
|
||||
continuity: 'all',
|
||||
rangeType: 'number',
|
||||
steps: DEFAULT_COLOR_STEPS,
|
||||
};
|
||||
|
|
|
@ -267,14 +267,18 @@ function PrimaryMetricEditor(props: SubProps) {
|
|||
|
||||
const hasDynamicColoring = Boolean(state?.palette);
|
||||
|
||||
const startWithPercentPalette = Boolean(state.maxAccessor || state.breakdownByAccessor);
|
||||
const supportsPercentPalette = Boolean(
|
||||
state.maxAccessor ||
|
||||
(state.breakdownByAccessor && !state.collapseFn) ||
|
||||
state?.palette?.params?.rangeType === 'percent'
|
||||
);
|
||||
|
||||
const activePalette = state?.palette || {
|
||||
type: 'palette',
|
||||
name: (startWithPercentPalette ? defaultPercentagePaletteParams : defaultNumberPaletteParams)
|
||||
name: (supportsPercentPalette ? defaultPercentagePaletteParams : defaultNumberPaletteParams)
|
||||
.name,
|
||||
params: {
|
||||
...(startWithPercentPalette ? defaultPercentagePaletteParams : defaultNumberPaletteParams),
|
||||
...(supportsPercentPalette ? defaultPercentagePaletteParams : defaultNumberPaletteParams),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -282,7 +286,8 @@ function PrimaryMetricEditor(props: SubProps) {
|
|||
{
|
||||
metric: state.metricAccessor!,
|
||||
max: state.maxAccessor,
|
||||
breakdownBy: state.breakdownByAccessor,
|
||||
// if we're collapsing, pretend like there's no breakdown to match the activeData
|
||||
breakdownBy: !state.collapseFn ? state.breakdownByAccessor : undefined,
|
||||
},
|
||||
frame.activeData?.[state.layerId]
|
||||
);
|
||||
|
@ -401,11 +406,7 @@ function PrimaryMetricEditor(props: SubProps) {
|
|||
activePalette={activePalette}
|
||||
dataBounds={currentMinMax}
|
||||
displayInfinity={true}
|
||||
showRangeTypeSelector={Boolean(
|
||||
state.breakdownByAccessor ||
|
||||
state.maxAccessor ||
|
||||
activePalette.params?.rangeType === 'percent'
|
||||
)}
|
||||
showRangeTypeSelector={supportsPercentPalette}
|
||||
setPalette={(newPalette) => {
|
||||
setState({
|
||||
...state,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue