|
@@ -1,21 +1,21 @@
|
|
|
-import { ValueMapping, Threshold } from '../types';
|
|
|
|
|
|
|
+// Libraries
|
|
|
import _ from 'lodash';
|
|
import _ from 'lodash';
|
|
|
-import { getValueFormat, DecimalCount } from './valueFormats/valueFormats';
|
|
|
|
|
|
|
+import moment from 'moment';
|
|
|
|
|
+
|
|
|
|
|
+// Utils
|
|
|
|
|
+import { getValueFormat } from './valueFormats/valueFormats';
|
|
|
import { getMappedValue } from './valueMappings';
|
|
import { getMappedValue } from './valueMappings';
|
|
|
-import { GrafanaTheme, GrafanaThemeType } from '../types';
|
|
|
|
|
import { getColorFromHexRgbOrName } from './namedColorsPalette';
|
|
import { getColorFromHexRgbOrName } from './namedColorsPalette';
|
|
|
-import moment from 'moment';
|
|
|
|
|
|
|
|
|
|
-export interface DisplayValue {
|
|
|
|
|
- text: string; // Show in the UI
|
|
|
|
|
- numeric: number; // Use isNaN to check if it is a real number
|
|
|
|
|
- color?: string; // color based on configs or Threshold
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// Types
|
|
|
|
|
+import { Threshold, ValueMapping, DecimalInfo, DisplayValue, GrafanaTheme, GrafanaThemeType } from '../types';
|
|
|
|
|
+import { DecimalCount } from './valueFormats/valueFormats';
|
|
|
|
|
+
|
|
|
|
|
+export type DisplayProcessor = (value: any) => DisplayValue;
|
|
|
|
|
|
|
|
export interface DisplayValueOptions {
|
|
export interface DisplayValueOptions {
|
|
|
unit?: string;
|
|
unit?: string;
|
|
|
decimals?: DecimalCount;
|
|
decimals?: DecimalCount;
|
|
|
- scaledDecimals?: DecimalCount;
|
|
|
|
|
dateFormat?: string; // If set try to convert numbers to date
|
|
dateFormat?: string; // If set try to convert numbers to date
|
|
|
|
|
|
|
|
color?: string;
|
|
color?: string;
|
|
@@ -32,11 +32,10 @@ export interface DisplayValueOptions {
|
|
|
theme?: GrafanaTheme; // Will pick 'dark' if not defined
|
|
theme?: GrafanaTheme; // Will pick 'dark' if not defined
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export type DisplayProcessor = (value: any) => DisplayValue;
|
|
|
|
|
-
|
|
|
|
|
export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProcessor {
|
|
export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProcessor {
|
|
|
if (options && !_.isEmpty(options)) {
|
|
if (options && !_.isEmpty(options)) {
|
|
|
const formatFunc = getValueFormat(options.unit || 'none');
|
|
const formatFunc = getValueFormat(options.unit || 'none');
|
|
|
|
|
+
|
|
|
return (value: any) => {
|
|
return (value: any) => {
|
|
|
const { prefix, suffix, mappings, thresholds, theme } = options;
|
|
const { prefix, suffix, mappings, thresholds, theme } = options;
|
|
|
let color = options.color;
|
|
let color = options.color;
|
|
@@ -47,12 +46,15 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce
|
|
|
let shouldFormat = true;
|
|
let shouldFormat = true;
|
|
|
if (mappings && mappings.length > 0) {
|
|
if (mappings && mappings.length > 0) {
|
|
|
const mappedValue = getMappedValue(mappings, value);
|
|
const mappedValue = getMappedValue(mappings, value);
|
|
|
|
|
+
|
|
|
if (mappedValue) {
|
|
if (mappedValue) {
|
|
|
text = mappedValue.text;
|
|
text = mappedValue.text;
|
|
|
const v = toNumber(text);
|
|
const v = toNumber(text);
|
|
|
|
|
+
|
|
|
if (!isNaN(v)) {
|
|
if (!isNaN(v)) {
|
|
|
numeric = v;
|
|
numeric = v;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
shouldFormat = false;
|
|
shouldFormat = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -67,7 +69,19 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce
|
|
|
|
|
|
|
|
if (!isNaN(numeric)) {
|
|
if (!isNaN(numeric)) {
|
|
|
if (shouldFormat && !_.isBoolean(value)) {
|
|
if (shouldFormat && !_.isBoolean(value)) {
|
|
|
- text = formatFunc(numeric, options.decimals, options.scaledDecimals, options.isUtc);
|
|
|
|
|
|
|
+ let decimals;
|
|
|
|
|
+ let scaledDecimals = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!options.decimals) {
|
|
|
|
|
+ const decimalInfo = getDecimalsForValue(value);
|
|
|
|
|
+
|
|
|
|
|
+ decimals = decimalInfo.decimals;
|
|
|
|
|
+ scaledDecimals = decimalInfo.scaledDecimals;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ decimals = options.decimals;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ text = formatFunc(numeric, decimals, scaledDecimals, options.isUtc);
|
|
|
}
|
|
}
|
|
|
if (thresholds && thresholds.length > 0) {
|
|
if (thresholds && thresholds.length > 0) {
|
|
|
color = getColorFromThreshold(numeric, thresholds, theme);
|
|
color = getColorFromThreshold(numeric, thresholds, theme);
|
|
@@ -143,3 +157,39 @@ export function getColorFromThreshold(value: number, thresholds: Threshold[], th
|
|
|
// Use the first threshold as the default color
|
|
// Use the first threshold as the default color
|
|
|
return getColorFromHexRgbOrName(thresholds[0].color, themeType);
|
|
return getColorFromHexRgbOrName(thresholds[0].color, themeType);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+export function getDecimalsForValue(value: number): DecimalInfo {
|
|
|
|
|
+ const delta = value / 2;
|
|
|
|
|
+ let dec = -Math.floor(Math.log(delta) / Math.LN10);
|
|
|
|
|
+
|
|
|
|
|
+ const magn = Math.pow(10, -dec);
|
|
|
|
|
+ const norm = delta / magn; // norm is between 1.0 and 10.0
|
|
|
|
|
+ let size;
|
|
|
|
|
+
|
|
|
|
|
+ if (norm < 1.5) {
|
|
|
|
|
+ size = 1;
|
|
|
|
|
+ } else if (norm < 3) {
|
|
|
|
|
+ size = 2;
|
|
|
|
|
+ // special case for 2.5, requires an extra decimal
|
|
|
|
|
+ if (norm > 2.25) {
|
|
|
|
|
+ size = 2.5;
|
|
|
|
|
+ ++dec;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (norm < 7.5) {
|
|
|
|
|
+ size = 5;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ size = 10;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size *= magn;
|
|
|
|
|
+
|
|
|
|
|
+ // reduce starting decimals if not needed
|
|
|
|
|
+ if (Math.floor(value) === value) {
|
|
|
|
|
+ dec = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const decimals = Math.max(0, dec);
|
|
|
|
|
+ const scaledDecimals = decimals - Math.floor(Math.log(size) / Math.LN10) + 2;
|
|
|
|
|
+
|
|
|
|
|
+ return { decimals, scaledDecimals };
|
|
|
|
|
+}
|