mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Control round and decimal places in Gauge Visualization when using aggregate functions like average (#91293) (#93014)
* Add field for providing format in percentage mode * Fix CI * Add tests * Fix ci * Fix some remarks * Fix ci * Fix some remarks * Fix ci * Fix width * Fix some remarks * Fix text * Fix i18n * Remove unneeded import * Remove unneeded code Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
9a9739453c
commit
0772e207a2
27 changed files with 280 additions and 52 deletions
|
@ -15,3 +15,4 @@ export { NumberInputOption } from './number_input';
|
||||||
export { RangeOption } from './range';
|
export { RangeOption } from './range';
|
||||||
export { RequiredNumberInputOption } from './required_number_input';
|
export { RequiredNumberInputOption } from './required_number_input';
|
||||||
export { TextInputOption } from './text_input';
|
export { TextInputOption } from './text_input';
|
||||||
|
export { PercentageModeOption } from './percentage_mode';
|
||||||
|
|
|
@ -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 { PercentageModeOption, PercentageModeOptionProps } from './percentage_mode';
|
||||||
|
import { EuiFieldText } from '@elastic/eui';
|
||||||
|
|
||||||
|
describe('PercentageModeOption', () => {
|
||||||
|
let props: PercentageModeOptionProps;
|
||||||
|
let component;
|
||||||
|
beforeAll(() => {
|
||||||
|
props = {
|
||||||
|
percentageMode: true,
|
||||||
|
setValue: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the EuiFieldText', () => {
|
||||||
|
component = mountWithIntl(<PercentageModeOption {...props} />);
|
||||||
|
expect(component.find(EuiFieldText).length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setValue when value was putted in fieldText', () => {
|
||||||
|
component = mountWithIntl(<PercentageModeOption {...props} />);
|
||||||
|
const fieldText = component.find(EuiFieldText);
|
||||||
|
fieldText.props().onChange!({
|
||||||
|
target: {
|
||||||
|
value: '0.0%',
|
||||||
|
},
|
||||||
|
} as React.ChangeEvent<HTMLInputElement>);
|
||||||
|
|
||||||
|
expect(props.setValue).toHaveBeenCalledWith('percentageFormatPattern', '0.0%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fieldText should be disabled when percentageMode is false', () => {
|
||||||
|
props.percentageMode = false;
|
||||||
|
component = mountWithIntl(<PercentageModeOption {...props} />);
|
||||||
|
const fieldText = component.find(EuiFieldText);
|
||||||
|
|
||||||
|
expect(fieldText.props().disabled).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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 { EuiFieldText, EuiFormRow, EuiLink } from '@elastic/eui';
|
||||||
|
import { SwitchOption } from './switch';
|
||||||
|
import { useKibana } from '../../../../kibana_react/public';
|
||||||
|
import { UI_SETTINGS } from '../../../../data/public';
|
||||||
|
|
||||||
|
export interface PercentageModeOptionProps {
|
||||||
|
setValue: (
|
||||||
|
paramName: 'percentageMode' | 'percentageFormatPattern',
|
||||||
|
value: boolean | string | undefined
|
||||||
|
) => void;
|
||||||
|
percentageMode: boolean;
|
||||||
|
formatPattern?: string;
|
||||||
|
'data-test-subj'?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PercentageModeOption({
|
||||||
|
'data-test-subj': dataTestSubj,
|
||||||
|
setValue,
|
||||||
|
percentageMode,
|
||||||
|
formatPattern,
|
||||||
|
}: PercentageModeOptionProps) {
|
||||||
|
const { services } = useKibana();
|
||||||
|
const defaultPattern = services.uiSettings?.get(UI_SETTINGS.FORMAT_PERCENT_DEFAULT_PATTERN);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SwitchOption
|
||||||
|
data-test-subj={dataTestSubj}
|
||||||
|
label={i18n.translate('visDefaultEditor.options.percentageMode.percentageModeLabel', {
|
||||||
|
defaultMessage: 'Percentage mode',
|
||||||
|
})}
|
||||||
|
paramName="percentageMode"
|
||||||
|
value={percentageMode}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
<EuiFormRow
|
||||||
|
fullWidth
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id="visDefaultEditor.options.percentageMode.numeralLabel"
|
||||||
|
defaultMessage="Format pattern"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
helpText={
|
||||||
|
<EuiLink target="_blank" href="https://adamwdraper.github.io/Numeral-js/">
|
||||||
|
<FormattedMessage
|
||||||
|
id="visDefaultEditor.options.percentageMode.documentationLabel"
|
||||||
|
defaultMessage="Numeral.js documentation"
|
||||||
|
/>
|
||||||
|
</EuiLink>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<EuiFieldText
|
||||||
|
fullWidth
|
||||||
|
compressed
|
||||||
|
data-test-subj={`${dataTestSubj}FormatPattern`}
|
||||||
|
value={formatPattern || ''}
|
||||||
|
placeholder={defaultPattern}
|
||||||
|
onChange={(e) => {
|
||||||
|
setValue('percentageFormatPattern', e.target.value ? e.target.value : undefined);
|
||||||
|
}}
|
||||||
|
disabled={!percentageMode}
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PercentageModeOption };
|
|
@ -26,6 +26,7 @@ import {
|
||||||
SetColorSchemaOptionsValue,
|
SetColorSchemaOptionsValue,
|
||||||
ColorSchemaOptions,
|
ColorSchemaOptions,
|
||||||
RangeOption,
|
RangeOption,
|
||||||
|
PercentageModeOption,
|
||||||
} from '../../../vis_default_editor/public';
|
} from '../../../vis_default_editor/public';
|
||||||
import { ColorMode, colorSchemas } from '../../../charts/public';
|
import { ColorMode, colorSchemas } from '../../../charts/public';
|
||||||
import { MetricVisParam, VisParams } from '../types';
|
import { MetricVisParam, VisParams } from '../types';
|
||||||
|
@ -113,12 +114,10 @@ function MetricVisOptions({
|
||||||
</EuiTitle>
|
</EuiTitle>
|
||||||
<EuiSpacer size="s" />
|
<EuiSpacer size="s" />
|
||||||
|
|
||||||
<SwitchOption
|
<PercentageModeOption
|
||||||
label={i18n.translate('visTypeMetric.params.percentageModeLabel', {
|
data-test-subj="metricPercentageMode"
|
||||||
defaultMessage: 'Percentage mode',
|
percentageMode={stateParams.metric.percentageMode}
|
||||||
})}
|
formatPattern={stateParams.metric.percentageFormatPattern}
|
||||||
paramName="percentageMode"
|
|
||||||
value={stateParams.metric.percentageMode}
|
|
||||||
setValue={setMetricValue}
|
setValue={setMetricValue}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ export const toExpressionAst: VisToExpressionAst<VisParams> = (vis, params) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
percentageMode,
|
percentageMode,
|
||||||
|
percentageFormatPattern,
|
||||||
useRanges,
|
useRanges,
|
||||||
colorSchema,
|
colorSchema,
|
||||||
metricColorMode,
|
metricColorMode,
|
||||||
|
@ -55,7 +56,10 @@ export const toExpressionAst: VisToExpressionAst<VisParams> = (vis, params) => {
|
||||||
// fix formatter for percentage mode
|
// fix formatter for percentage mode
|
||||||
if (get(vis.params, 'metric.percentageMode') === true) {
|
if (get(vis.params, 'metric.percentageMode') === true) {
|
||||||
schemas.metric.forEach((metric: SchemaConfig) => {
|
schemas.metric.forEach((metric: SchemaConfig) => {
|
||||||
metric.format = { id: 'percent' };
|
metric.format = {
|
||||||
|
id: 'percent',
|
||||||
|
params: { pattern: percentageFormatPattern },
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface DimensionsVisParam {
|
||||||
|
|
||||||
export interface MetricVisParam {
|
export interface MetricVisParam {
|
||||||
percentageMode: boolean;
|
percentageMode: boolean;
|
||||||
|
percentageFormatPattern?: string;
|
||||||
useRanges: boolean;
|
useRanges: boolean;
|
||||||
colorSchema: ColorSchemas;
|
colorSchema: ColorSchemas;
|
||||||
metricColorMode: ColorMode;
|
metricColorMode: ColorMode;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
SetColorRangeValue,
|
SetColorRangeValue,
|
||||||
SwitchOption,
|
SwitchOption,
|
||||||
ColorSchemaOptions,
|
ColorSchemaOptions,
|
||||||
|
PercentageModeOption,
|
||||||
} from '../../../../../vis_default_editor/public';
|
} from '../../../../../vis_default_editor/public';
|
||||||
import { ColorSchemaParams, ColorSchemas, colorSchemas } from '../../../../../charts/public';
|
import { ColorSchemaParams, ColorSchemas, colorSchemas } from '../../../../../charts/public';
|
||||||
import { GaugeOptionsInternalProps } from '../gauge';
|
import { GaugeOptionsInternalProps } from '../gauge';
|
||||||
|
@ -77,13 +78,10 @@ function RangesPanel({
|
||||||
setValue={setGaugeValue}
|
setValue={setGaugeValue}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SwitchOption
|
<PercentageModeOption
|
||||||
data-test-subj="gaugePercentageMode"
|
data-test-subj="gaugePercentageMode"
|
||||||
label={i18n.translate('visTypeVislib.controls.gaugeOptions.percentageModeLabel', {
|
percentageMode={stateParams.gauge.percentageMode}
|
||||||
defaultMessage: 'Percentage mode',
|
formatPattern={stateParams.gauge.percentageFormatPattern}
|
||||||
})}
|
|
||||||
paramName="percentageMode"
|
|
||||||
value={stateParams.gauge.percentageMode}
|
|
||||||
setValue={setGaugeValue}
|
setValue={setGaugeValue}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
SetColorSchemaOptionsValue,
|
SetColorSchemaOptionsValue,
|
||||||
ColorSchemaOptions,
|
ColorSchemaOptions,
|
||||||
NumberInputOption,
|
NumberInputOption,
|
||||||
|
PercentageModeOption,
|
||||||
} from '../../../../../vis_default_editor/public';
|
} from '../../../../../vis_default_editor/public';
|
||||||
|
|
||||||
import { HeatmapVisParams } from '../../../heatmap';
|
import { HeatmapVisParams } from '../../../heatmap';
|
||||||
|
@ -125,13 +126,10 @@ function HeatmapOptions(props: VisEditorOptionsProps<HeatmapVisParams>) {
|
||||||
setValue={setValueAxisScale}
|
setValue={setValueAxisScale}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SwitchOption
|
<PercentageModeOption
|
||||||
disabled={stateParams.setColorRange}
|
data-test-subj="metricPercentageMode"
|
||||||
label={i18n.translate('visTypeVislib.controls.heatmapOptions.percentageModeLabel', {
|
percentageMode={stateParams.setColorRange ? false : stateParams.percentageMode}
|
||||||
defaultMessage: 'Percentage mode',
|
formatPattern={stateParams.percentageFormatPattern}
|
||||||
})}
|
|
||||||
paramName="percentageMode"
|
|
||||||
value={stateParams.setColorRange ? false : stateParams.percentageMode}
|
|
||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
/>
|
/>
|
||||||
<EuiSpacer size="s" />
|
<EuiSpacer size="s" />
|
||||||
|
|
|
@ -12,6 +12,9 @@ setFormatService({
|
||||||
deserialize: () => ({
|
deserialize: () => ({
|
||||||
convert: (v) => v,
|
convert: (v) => v,
|
||||||
}),
|
}),
|
||||||
|
getInstance: () => ({
|
||||||
|
convert: (v) => v,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getMockUiState = () => {
|
export const getMockUiState = () => {
|
||||||
|
|
|
@ -28,6 +28,7 @@ export interface Gauge extends ColorSchemaParams {
|
||||||
gaugeType: GaugeType;
|
gaugeType: GaugeType;
|
||||||
labels: Labels;
|
labels: Labels;
|
||||||
percentageMode: boolean;
|
percentageMode: boolean;
|
||||||
|
percentageFormatPattern?: string;
|
||||||
outline?: boolean;
|
outline?: boolean;
|
||||||
scale: {
|
scale: {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
|
|
@ -29,6 +29,7 @@ export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams
|
||||||
valueAxes: ValueAxis[];
|
valueAxes: ValueAxis[];
|
||||||
setColorRange: boolean;
|
setColorRange: boolean;
|
||||||
percentageMode: boolean;
|
percentageMode: boolean;
|
||||||
|
percentageFormatPattern?: string;
|
||||||
times: TimeMarker[];
|
times: TimeMarker[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,10 @@ export const toExpressionAst = async <TVisParams extends VisParams>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (visConfig?.gauge?.percentageMode === true) {
|
if (visConfig?.gauge?.percentageMode === true) {
|
||||||
yDimension.format = { id: 'percent' };
|
yDimension.format = {
|
||||||
|
id: 'percent',
|
||||||
|
params: { pattern: visConfig?.gauge?.percentageFormatPattern },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,33 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { last } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { renderToStaticMarkup } from 'react-dom/server';
|
import { renderToStaticMarkup } from 'react-dom/server';
|
||||||
|
import { UI_SETTINGS } from '../../../../../../plugins/data/public';
|
||||||
|
import { getValueForPercentageMode } from '../../percentage_mode_transform';
|
||||||
|
|
||||||
|
function getMax(handler, config, isGauge) {
|
||||||
|
let max;
|
||||||
|
if (handler.pointSeries) {
|
||||||
|
const series = handler.pointSeries.getSeries();
|
||||||
|
const scale = series.getValueAxis().getScale();
|
||||||
|
max = scale.domain()[1];
|
||||||
|
} else {
|
||||||
|
max = last(config.get(isGauge ? 'gauge.colorsRange' : 'colorsRange', [{}])).to;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
export function pointSeriesTooltipFormatter() {
|
export function pointSeriesTooltipFormatter() {
|
||||||
return function tooltipFormatter({ datum, data }) {
|
return function tooltipFormatter({ datum, data, config, handler }, uiSettings) {
|
||||||
if (!datum) return '';
|
if (!datum) return '';
|
||||||
|
|
||||||
const details = [];
|
const details = [];
|
||||||
|
const isGauge = config.get('gauge', false);
|
||||||
|
const isPercentageMode = config.get(isGauge ? 'gauge.percentageMode' : 'percentageMode', false);
|
||||||
|
const isSetColorRange = config.get('setColorRange', false);
|
||||||
|
|
||||||
const currentSeries =
|
const currentSeries =
|
||||||
data.series && data.series.find((serie) => serie.rawId === datum.seriesId);
|
data.series && data.series.find((serie) => serie.rawId === datum.seriesId);
|
||||||
|
@ -30,9 +49,21 @@ export function pointSeriesTooltipFormatter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datum.y !== null && datum.y !== undefined) {
|
if (datum.y !== null && datum.y !== undefined) {
|
||||||
const value = datum.yScale ? datum.yScale * datum.y : datum.y;
|
let value = datum.yScale ? datum.yScale * datum.y : datum.y;
|
||||||
|
if (isPercentageMode && !isSetColorRange) {
|
||||||
|
const percentageFormatPattern = config.get(
|
||||||
|
isGauge ? 'gauge.percentageFormatPattern' : 'percentageFormatPattern',
|
||||||
|
uiSettings.get(UI_SETTINGS.FORMAT_PERCENT_DEFAULT_PATTERN)
|
||||||
|
);
|
||||||
|
value = getValueForPercentageMode(
|
||||||
|
value / getMax(handler, config, isGauge),
|
||||||
|
percentageFormatPattern
|
||||||
|
);
|
||||||
|
addDetail(currentSeries.label, value);
|
||||||
|
} else {
|
||||||
addDetail(currentSeries.label, currentSeries.yAxisFormatter(value));
|
addDetail(currentSeries.label, currentSeries.yAxisFormatter(value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (datum.z !== null && datum.z !== undefined) {
|
if (datum.z !== null && datum.z !== undefined) {
|
||||||
addDetail(currentSeries.zLabel, currentSeries.zAxisFormatter(datum.z));
|
addDetail(currentSeries.zLabel, currentSeries.zAxisFormatter(datum.z));
|
||||||
|
|
|
@ -43,11 +43,36 @@ describe('tooltipFormatter', function () {
|
||||||
extraMetrics: [],
|
extraMetrics: [],
|
||||||
seriesId: '1',
|
seriesId: '1',
|
||||||
},
|
},
|
||||||
|
config: {
|
||||||
|
get: (name) => {
|
||||||
|
const config = {
|
||||||
|
setColorRange: false,
|
||||||
|
gauge: false,
|
||||||
|
percentageMode: false,
|
||||||
|
};
|
||||||
|
return config[name];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler: {
|
||||||
|
pointSeries: {
|
||||||
|
getSeries: () => ({
|
||||||
|
getValueAxis: () => ({
|
||||||
|
getScale: () => ({
|
||||||
|
domain: () => [0, 10],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const uiSettings = {
|
||||||
|
get: () => '',
|
||||||
};
|
};
|
||||||
|
|
||||||
it('returns html based on the mouse event', function () {
|
it('returns html based on the mouse event', function () {
|
||||||
const event = _.cloneDeep(baseEvent);
|
const event = _.cloneDeep(baseEvent);
|
||||||
const $el = $(tooltipFormatter(event));
|
const $el = $(tooltipFormatter(event, uiSettings));
|
||||||
const $rows = $el.find('tr');
|
const $rows = $el.find('tr');
|
||||||
expect($rows.length).toBe(3);
|
expect($rows.length).toBe(3);
|
||||||
|
|
||||||
|
@ -67,7 +92,7 @@ describe('tooltipFormatter', function () {
|
||||||
it('renders correctly on missing extraMetrics in datum', function () {
|
it('renders correctly on missing extraMetrics in datum', function () {
|
||||||
const event = _.cloneDeep(baseEvent);
|
const event = _.cloneDeep(baseEvent);
|
||||||
delete event.datum.extraMetrics;
|
delete event.datum.extraMetrics;
|
||||||
const $el = $(tooltipFormatter(event));
|
const $el = $(tooltipFormatter(event, uiSettings));
|
||||||
const $rows = $el.find('tr');
|
const $rows = $el.find('tr');
|
||||||
expect($rows.length).toBe(3);
|
expect($rows.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,9 +29,9 @@ const tooltipMaxWidth = parseInt(theme.euiSizeXL || 0, 10) * 10;
|
||||||
* @param formatter {Function} Tooltip formatter
|
* @param formatter {Function} Tooltip formatter
|
||||||
* @param events {Constructor} Allows tooltip to return event response data
|
* @param events {Constructor} Allows tooltip to return event response data
|
||||||
*/
|
*/
|
||||||
export function Tooltip(id, el, formatter, events) {
|
export function Tooltip(id, el, formatter, events, uiSettings) {
|
||||||
if (!(this instanceof Tooltip)) {
|
if (!(this instanceof Tooltip)) {
|
||||||
return new Tooltip(id, el, formatter, events);
|
return new Tooltip(id, el, formatter, events, uiSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.id = id; // unique id for this tooltip type
|
this.id = id; // unique id for this tooltip type
|
||||||
|
@ -39,6 +39,7 @@ export function Tooltip(id, el, formatter, events) {
|
||||||
this.order = 100; // higher ordered contents are rendered below the others
|
this.order = 100; // higher ordered contents are rendered below the others
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
this.events = events;
|
this.events = events;
|
||||||
|
this.uiSettings = uiSettings;
|
||||||
this.containerClass = 'visWrapper';
|
this.containerClass = 'visWrapper';
|
||||||
this.tooltipClass = 'visTooltip';
|
this.tooltipClass = 'visTooltip';
|
||||||
this.tooltipSizerClass = 'visTooltip__sizingClone';
|
this.tooltipSizerClass = 'visTooltip__sizingClone';
|
||||||
|
@ -223,7 +224,7 @@ Tooltip.prototype.render = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = self.events ? self.events.eventResponse(d, i) : d;
|
const events = self.events ? self.events.eventResponse(d, i) : d;
|
||||||
return render(self.formatter(events));
|
return render(self.formatter(events, self.uiSettings));
|
||||||
});
|
});
|
||||||
|
|
||||||
self.binder.fakeD3Bind(this, 'mouseleave', function () {
|
self.binder.fakeD3Bind(this, 'mouseleave', function () {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import numeral from '@elastic/numeral';
|
||||||
|
import { getFormatService } from '../services';
|
||||||
|
|
||||||
|
export function getValueForPercentageMode(value: string | number, percentageFormatPattern: string) {
|
||||||
|
const formatServices = getFormatService();
|
||||||
|
const percentFormatter = formatServices.getInstance('percent', {
|
||||||
|
pattern: percentageFormatPattern,
|
||||||
|
});
|
||||||
|
|
||||||
|
return percentFormatter.convert(value);
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ export class Chart {
|
||||||
const element = this.handler.el;
|
const element = this.handler.el;
|
||||||
|
|
||||||
// Add tooltip
|
// Add tooltip
|
||||||
this.tooltip = new Tooltip('chart', element, tooltipFormatter, events);
|
this.tooltip = new Tooltip('chart', element, tooltipFormatter, events, uiSettings);
|
||||||
this.tooltips.push(this.tooltip);
|
this.tooltips.push(this.tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class GaugeChart extends Chart {
|
||||||
constructor(handler, chartEl, chartData, uiSettings) {
|
constructor(handler, chartEl, chartData, uiSettings) {
|
||||||
super(handler, chartEl, chartData, uiSettings);
|
super(handler, chartEl, chartData, uiSettings);
|
||||||
this.gaugeConfig = handler.visConfig.get('gauge', {});
|
this.gaugeConfig = handler.visConfig.get('gauge', {});
|
||||||
this.gauge = new gaugeTypes[this.gaugeConfig.type](this);
|
this.gauge = new gaugeTypes[this.gaugeConfig.type](this, uiSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEvents(element) {
|
addEvents(element) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import d3 from 'd3';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { getHeatmapColors } from '../../../../../charts/public';
|
import { getHeatmapColors } from '../../../../../charts/public';
|
||||||
|
import { UI_SETTINGS } from '../../../../../data/public';
|
||||||
|
import { getValueForPercentageMode } from '../../percentage_mode_transform';
|
||||||
|
|
||||||
const arcAngles = {
|
const arcAngles = {
|
||||||
angleFactor: 0.75,
|
angleFactor: 0.75,
|
||||||
|
@ -47,9 +49,10 @@ const defaultConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export class MeterGauge {
|
export class MeterGauge {
|
||||||
constructor(gaugeChart) {
|
constructor(gaugeChart, uiSettings) {
|
||||||
this.gaugeChart = gaugeChart;
|
this.gaugeChart = gaugeChart;
|
||||||
this.gaugeConfig = gaugeChart.gaugeConfig;
|
this.gaugeConfig = gaugeChart.gaugeConfig;
|
||||||
|
this.uiSettings = uiSettings;
|
||||||
this.gaugeConfig = _.defaultsDeep(this.gaugeConfig, defaultConfig);
|
this.gaugeConfig = _.defaultsDeep(this.gaugeConfig, defaultConfig);
|
||||||
|
|
||||||
this.gaugeChart.handler.visConfig.set('legend', {
|
this.gaugeChart.handler.visConfig.set('legend', {
|
||||||
|
@ -68,12 +71,19 @@ export class MeterGauge {
|
||||||
|
|
||||||
getLabels() {
|
getLabels() {
|
||||||
const isPercentageMode = this.gaugeConfig.percentageMode;
|
const isPercentageMode = this.gaugeConfig.percentageMode;
|
||||||
|
const percentageFormatPattern =
|
||||||
|
this.gaugeConfig.percentageFormatPattern ||
|
||||||
|
this.uiSettings.get(UI_SETTINGS.FORMAT_PERCENT_DEFAULT_PATTERN);
|
||||||
const colorsRange = this.gaugeConfig.colorsRange;
|
const colorsRange = this.gaugeConfig.colorsRange;
|
||||||
const max = _.last(colorsRange).to;
|
const max = _.last(colorsRange).to;
|
||||||
const labels = [];
|
const labels = [];
|
||||||
colorsRange.forEach((range) => {
|
colorsRange.forEach((range) => {
|
||||||
const from = isPercentageMode ? Math.round((100 * range.from) / max) : range.from;
|
const from = isPercentageMode
|
||||||
const to = isPercentageMode ? Math.round((100 * range.to) / max) : range.to;
|
? getValueForPercentageMode(range.from / max, percentageFormatPattern)
|
||||||
|
: range.from;
|
||||||
|
const to = isPercentageMode
|
||||||
|
? getValueForPercentageMode(range.to / max, percentageFormatPattern)
|
||||||
|
: range.to;
|
||||||
labels.push(`${from} - ${to}`);
|
labels.push(`${from} - ${to}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ const defaults = {
|
||||||
* chart
|
* chart
|
||||||
*/
|
*/
|
||||||
export class AreaChart extends PointSeries {
|
export class AreaChart extends PointSeries {
|
||||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
constructor(handler, chartEl, chartData, seriesConfigArgs, uiSettings) {
|
||||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
super(handler, chartEl, chartData, seriesConfigArgs, uiSettings);
|
||||||
|
|
||||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||||
this.isOverlapping = this.seriesConfig.mode !== 'stacked';
|
this.isOverlapping = this.seriesConfig.mode !== 'stacked';
|
||||||
|
|
|
@ -46,8 +46,8 @@ function datumWidth(defaultWidth, datum, nextDatum, scale, gutterWidth, groupCou
|
||||||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||||
*/
|
*/
|
||||||
export class ColumnChart extends PointSeries {
|
export class ColumnChart extends PointSeries {
|
||||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
constructor(handler, chartEl, chartData, seriesConfigArgs, uiSettings) {
|
||||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
super(handler, chartEl, chartData, seriesConfigArgs, uiSettings);
|
||||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||||
this.labelOptions = _.defaults(handler.visConfig.get('labels', {}), defaults.showLabel);
|
this.labelOptions = _.defaults(handler.visConfig.get('labels', {}), defaults.showLabel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { isColorDark } from '@elastic/eui';
|
||||||
|
|
||||||
import { PointSeries } from './_point_series';
|
import { PointSeries } from './_point_series';
|
||||||
import { getHeatmapColors } from '../../../../../../plugins/charts/public';
|
import { getHeatmapColors } from '../../../../../../plugins/charts/public';
|
||||||
|
import { UI_SETTINGS } from '../../../../../../plugins/data/public';
|
||||||
|
import { getValueForPercentageMode } from '../../percentage_mode_transform';
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
color: undefined, // todo
|
color: undefined, // todo
|
||||||
|
@ -29,8 +31,10 @@ const defaults = {
|
||||||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||||
*/
|
*/
|
||||||
export class HeatmapChart extends PointSeries {
|
export class HeatmapChart extends PointSeries {
|
||||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
constructor(handler, chartEl, chartData, seriesConfigArgs, uiSettings) {
|
||||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
super(handler, chartEl, chartData, seriesConfigArgs, uiSettings);
|
||||||
|
|
||||||
|
this.uiSettings = uiSettings;
|
||||||
|
|
||||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||||
|
|
||||||
|
@ -48,6 +52,10 @@ export class HeatmapChart extends PointSeries {
|
||||||
|
|
||||||
getHeatmapLabels(cfg) {
|
getHeatmapLabels(cfg) {
|
||||||
const percentageMode = cfg.get('percentageMode');
|
const percentageMode = cfg.get('percentageMode');
|
||||||
|
const percentageFormatPattern = cfg.get(
|
||||||
|
'percentageFormatPattern',
|
||||||
|
this.uiSettings.get(UI_SETTINGS.FORMAT_PERCENT_DEFAULT_PATTERN)
|
||||||
|
);
|
||||||
const colorsNumber = cfg.get('colorsNumber');
|
const colorsNumber = cfg.get('colorsNumber');
|
||||||
const colorsRange = cfg.get('colorsRange');
|
const colorsRange = cfg.get('colorsRange');
|
||||||
const zAxisConfig = this.getValueAxis().axisConfig;
|
const zAxisConfig = this.getValueAxis().axisConfig;
|
||||||
|
@ -71,9 +79,9 @@ export class HeatmapChart extends PointSeries {
|
||||||
let val = i / colorsNumber;
|
let val = i / colorsNumber;
|
||||||
let nextVal = (i + 1) / colorsNumber;
|
let nextVal = (i + 1) / colorsNumber;
|
||||||
if (percentageMode) {
|
if (percentageMode) {
|
||||||
val = Math.ceil(val * 100);
|
val = getValueForPercentageMode(val, percentageFormatPattern);
|
||||||
nextVal = Math.ceil(nextVal * 100);
|
nextVal = getValueForPercentageMode(nextVal, percentageFormatPattern);
|
||||||
label = `${val}% - ${nextVal}%`;
|
label = `${val} - ${nextVal}`;
|
||||||
} else {
|
} else {
|
||||||
val = val * (max - min) + min;
|
val = val * (max - min) + min;
|
||||||
nextVal = nextVal * (max - min) + min;
|
nextVal = nextVal * (max - min) + min;
|
||||||
|
|
|
@ -68,6 +68,7 @@ describe('Vislib Heatmap Chart Test Suite', function () {
|
||||||
colorSchema: 'Greens',
|
colorSchema: 'Greens',
|
||||||
setColorRange: false,
|
setColorRange: false,
|
||||||
percentageMode: true,
|
percentageMode: true,
|
||||||
|
percentageFormatPattern: '0.0%',
|
||||||
invertColors: false,
|
invertColors: false,
|
||||||
colorsRange: [],
|
colorsRange: [],
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,8 +31,8 @@ const defaults = {
|
||||||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||||
*/
|
*/
|
||||||
export class LineChart extends PointSeries {
|
export class LineChart extends PointSeries {
|
||||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
constructor(handler, chartEl, chartData, seriesConfigArgs, uiSettings) {
|
||||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
super(handler, chartEl, chartData, seriesConfigArgs, uiSettings);
|
||||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||||
await PageObjects.visEditor.clickOptionsTab();
|
await PageObjects.visEditor.clickOptionsTab();
|
||||||
await testSubjects.setValue('gaugeColorRange2__to', '10000');
|
await testSubjects.setValue('gaugeColorRange2__to', '10000');
|
||||||
await testSubjects.click('gaugePercentageMode');
|
await testSubjects.click('gaugePercentageMode');
|
||||||
|
await testSubjects.setValue('gaugePercentageModeFormatPattern', '0.0%');
|
||||||
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
|
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
|
||||||
await PageObjects.visEditor.clickGo();
|
await PageObjects.visEditor.clickGo();
|
||||||
|
|
||||||
await retry.try(async function tryingForTime() {
|
await retry.try(async function tryingForTime() {
|
||||||
const expectedTexts = ['57.273%', 'Average bytes'];
|
const expectedTexts = ['57.3%', 'Average bytes'];
|
||||||
const metricValue = await PageObjects.visChart.getGaugeValue();
|
const metricValue = await PageObjects.visChart.getGaugeValue();
|
||||||
expect(expectedTexts).to.eql(metricValue);
|
expect(expectedTexts).to.eql(metricValue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3885,7 +3885,6 @@
|
||||||
"visTypeMetric.metricDescription": "計算結果を単独の数字として表示します。",
|
"visTypeMetric.metricDescription": "計算結果を単独の数字として表示します。",
|
||||||
"visTypeMetric.metricTitle": "メトリック",
|
"visTypeMetric.metricTitle": "メトリック",
|
||||||
"visTypeMetric.params.color.useForLabel": "使用する色",
|
"visTypeMetric.params.color.useForLabel": "使用する色",
|
||||||
"visTypeMetric.params.percentageModeLabel": "百分率モード",
|
|
||||||
"visTypeMetric.params.rangesTitle": "範囲",
|
"visTypeMetric.params.rangesTitle": "範囲",
|
||||||
"visTypeMetric.params.settingsTitle": "設定",
|
"visTypeMetric.params.settingsTitle": "設定",
|
||||||
"visTypeMetric.params.showTitleLabel": "タイトルを表示",
|
"visTypeMetric.params.showTitleLabel": "タイトルを表示",
|
||||||
|
@ -4570,7 +4569,6 @@
|
||||||
"visTypeVislib.controls.gaugeOptions.extendRangeTooltip": "範囲をデータの最高値に広げます。",
|
"visTypeVislib.controls.gaugeOptions.extendRangeTooltip": "範囲をデータの最高値に広げます。",
|
||||||
"visTypeVislib.controls.gaugeOptions.gaugeTypeLabel": "ゲージタイプ",
|
"visTypeVislib.controls.gaugeOptions.gaugeTypeLabel": "ゲージタイプ",
|
||||||
"visTypeVislib.controls.gaugeOptions.labelsTitle": "ラベル",
|
"visTypeVislib.controls.gaugeOptions.labelsTitle": "ラベル",
|
||||||
"visTypeVislib.controls.gaugeOptions.percentageModeLabel": "百分率モード",
|
|
||||||
"visTypeVislib.controls.gaugeOptions.rangesTitle": "範囲",
|
"visTypeVislib.controls.gaugeOptions.rangesTitle": "範囲",
|
||||||
"visTypeVislib.controls.gaugeOptions.showLabelsLabel": "ラベルを表示",
|
"visTypeVislib.controls.gaugeOptions.showLabelsLabel": "ラベルを表示",
|
||||||
"visTypeVislib.controls.gaugeOptions.showLegendLabel": "凡例を表示",
|
"visTypeVislib.controls.gaugeOptions.showLegendLabel": "凡例を表示",
|
||||||
|
@ -4584,7 +4582,6 @@
|
||||||
"visTypeVislib.controls.heatmapOptions.colorsNumberLabel": "色の数",
|
"visTypeVislib.controls.heatmapOptions.colorsNumberLabel": "色の数",
|
||||||
"visTypeVislib.controls.heatmapOptions.labelsTitle": "ラベル",
|
"visTypeVislib.controls.heatmapOptions.labelsTitle": "ラベル",
|
||||||
"visTypeVislib.controls.heatmapOptions.overwriteAutomaticColorLabel": "自動からーを上書きする",
|
"visTypeVislib.controls.heatmapOptions.overwriteAutomaticColorLabel": "自動からーを上書きする",
|
||||||
"visTypeVislib.controls.heatmapOptions.percentageModeLabel": "百分率モード",
|
|
||||||
"visTypeVislib.controls.heatmapOptions.rotateLabel": "回転",
|
"visTypeVislib.controls.heatmapOptions.rotateLabel": "回転",
|
||||||
"visTypeVislib.controls.heatmapOptions.scaleToDataBoundsLabel": "データバウンドに合わせる",
|
"visTypeVislib.controls.heatmapOptions.scaleToDataBoundsLabel": "データバウンドに合わせる",
|
||||||
"visTypeVislib.controls.heatmapOptions.showLabelsTitle": "ラベルを表示",
|
"visTypeVislib.controls.heatmapOptions.showLabelsTitle": "ラベルを表示",
|
||||||
|
|
|
@ -3889,7 +3889,6 @@
|
||||||
"visTypeMetric.metricDescription": "将计算结果显示为单个数字。",
|
"visTypeMetric.metricDescription": "将计算结果显示为单个数字。",
|
||||||
"visTypeMetric.metricTitle": "指标",
|
"visTypeMetric.metricTitle": "指标",
|
||||||
"visTypeMetric.params.color.useForLabel": "将颜色用于",
|
"visTypeMetric.params.color.useForLabel": "将颜色用于",
|
||||||
"visTypeMetric.params.percentageModeLabel": "百分比模式",
|
|
||||||
"visTypeMetric.params.rangesTitle": "范围",
|
"visTypeMetric.params.rangesTitle": "范围",
|
||||||
"visTypeMetric.params.settingsTitle": "设置",
|
"visTypeMetric.params.settingsTitle": "设置",
|
||||||
"visTypeMetric.params.showTitleLabel": "显示标题",
|
"visTypeMetric.params.showTitleLabel": "显示标题",
|
||||||
|
@ -4575,7 +4574,6 @@
|
||||||
"visTypeVislib.controls.gaugeOptions.extendRangeTooltip": "将数据范围扩展到数据中的最大值。",
|
"visTypeVislib.controls.gaugeOptions.extendRangeTooltip": "将数据范围扩展到数据中的最大值。",
|
||||||
"visTypeVislib.controls.gaugeOptions.gaugeTypeLabel": "仪表类型",
|
"visTypeVislib.controls.gaugeOptions.gaugeTypeLabel": "仪表类型",
|
||||||
"visTypeVislib.controls.gaugeOptions.labelsTitle": "标签",
|
"visTypeVislib.controls.gaugeOptions.labelsTitle": "标签",
|
||||||
"visTypeVislib.controls.gaugeOptions.percentageModeLabel": "百分比模式",
|
|
||||||
"visTypeVislib.controls.gaugeOptions.rangesTitle": "范围",
|
"visTypeVislib.controls.gaugeOptions.rangesTitle": "范围",
|
||||||
"visTypeVislib.controls.gaugeOptions.showLabelsLabel": "显示标签",
|
"visTypeVislib.controls.gaugeOptions.showLabelsLabel": "显示标签",
|
||||||
"visTypeVislib.controls.gaugeOptions.showLegendLabel": "显示图例",
|
"visTypeVislib.controls.gaugeOptions.showLegendLabel": "显示图例",
|
||||||
|
@ -4589,7 +4587,6 @@
|
||||||
"visTypeVislib.controls.heatmapOptions.colorsNumberLabel": "颜色个数",
|
"visTypeVislib.controls.heatmapOptions.colorsNumberLabel": "颜色个数",
|
||||||
"visTypeVislib.controls.heatmapOptions.labelsTitle": "标签",
|
"visTypeVislib.controls.heatmapOptions.labelsTitle": "标签",
|
||||||
"visTypeVislib.controls.heatmapOptions.overwriteAutomaticColorLabel": "覆盖自动配色",
|
"visTypeVislib.controls.heatmapOptions.overwriteAutomaticColorLabel": "覆盖自动配色",
|
||||||
"visTypeVislib.controls.heatmapOptions.percentageModeLabel": "百分比模式",
|
|
||||||
"visTypeVislib.controls.heatmapOptions.rotateLabel": "旋转",
|
"visTypeVislib.controls.heatmapOptions.rotateLabel": "旋转",
|
||||||
"visTypeVislib.controls.heatmapOptions.scaleToDataBoundsLabel": "缩放到数据边界",
|
"visTypeVislib.controls.heatmapOptions.scaleToDataBoundsLabel": "缩放到数据边界",
|
||||||
"visTypeVislib.controls.heatmapOptions.showLabelsTitle": "显示标签",
|
"visTypeVislib.controls.heatmapOptions.showLabelsTitle": "显示标签",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue