@gooddata/react-components
Version:
GoodData.UI - A powerful JavaScript library for building analytical applications
100 lines (89 loc) • 3.36 kB
text/typescript
// (C) 2007-2019 GoodData Corporation
import { colors2Object, ISeparators, numberFormat } from "@gooddata/numberjs";
import isEmpty = require("lodash/isEmpty");
import isNaN = require("lodash/isNaN");
import { IFormattedHeadlineDataItem, IHeadlineDataItem } from "../../../../interfaces/Headlines";
import { IChartConfig } from "../../../../interfaces/Config";
const DEFAULT_VALUE_WHEN_EMPTY = "–";
const INVALID_VALUE = "NaN";
const PERCENTAGE_VALUE_LIMIT = 999;
function processStringForNumberJs(value: string | null, format: string) {
return value === null && !isEmpty(format)
? "" // return empty string for null value for number.js to apply [=null] format
: parseFloat(value as string);
}
function formatValueToLabelWithColors(value: string | null, format: string, separators?: ISeparators) {
const processedValue = processStringForNumberJs(value, format);
const formattedValue = numberFormat(processedValue, format, undefined, separators);
return colors2Object(formattedValue);
}
function buildCssStyle(color?: string, backgroundColor?: string) {
const style: any = {};
if (color !== undefined) {
style.color = color;
}
if (backgroundColor !== undefined) {
style.backgroundColor = backgroundColor;
}
return style;
}
/**
* Format {HeadlineData} value.
*
* The method processes the provided item and returns object with value that can be rendered as it is and 'cssStyle'
* object that can be passed into the react element 'style' attribute.
*
* @param item
* @returns {{cssStyle: {color, backgroundColor}, value: string, isValueEmpty: boolean}}
*/
export function formatItemValue(
item: IHeadlineDataItem,
config: IChartConfig = {},
): IFormattedHeadlineDataItem {
const { separators } = config;
const { label, color, backgroundColor } = formatValueToLabelWithColors(
item.value,
item.format,
separators,
);
const isValueEmpty = label === INVALID_VALUE || label === "";
const value = isValueEmpty ? DEFAULT_VALUE_WHEN_EMPTY : label;
return {
cssStyle: buildCssStyle(color, backgroundColor),
value,
isValueEmpty,
};
}
/**
* The method processes the provided IHeadlineDataItem and returns object with formatted value and isValueEmpty flag.
*
* Formatted value conditions:
* - value is rounded to Integer
* - shows '>999%' when value is above the limit
* - shows '<-999%' when value is below the limit
* - otherwise shows 'value%'
*
* @param item
* @returns {{value: string, isValueEmpty: boolean}}
*/
export function formatPercentageValue(item: IHeadlineDataItem): IFormattedHeadlineDataItem {
if (!item || item.value === null || isNaN(parseFloat(item.value))) {
return {
value: DEFAULT_VALUE_WHEN_EMPTY,
isValueEmpty: true,
};
}
const roundedNumber = Math.round(parseFloat(item.value));
const isOverLimit = roundedNumber > PERCENTAGE_VALUE_LIMIT;
const isUnderLimit = roundedNumber < -PERCENTAGE_VALUE_LIMIT;
let formattedValue = `${roundedNumber}%`;
if (isOverLimit) {
formattedValue = `>${PERCENTAGE_VALUE_LIMIT}%`;
} else if (isUnderLimit) {
formattedValue = `<-${PERCENTAGE_VALUE_LIMIT}%`;
}
return {
value: formattedValue,
isValueEmpty: false,
};
}