mirror of https://github.com/grafana/grafana.git
				
				
				
			Number formatting: only 0-trim decimals in y axis ticks. omit currency, locale units. (#57386)
This commit is contained in:
		
							parent
							
								
									45707ccf99
								
							
						
					
					
						commit
						0640eeef0a
					
				|  | @ -305,7 +305,7 @@ describe('Format value', () => { | |||
|     const value = 1200; | ||||
|     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); | ||||
|     const disp = instance(value); | ||||
|     expect(disp.text).toEqual('1.2'); | ||||
|     expect(disp.text).toEqual('1.20'); | ||||
|     expect(disp.suffix).toEqual(' K'); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -329,7 +329,7 @@ describe('Format value', () => { | |||
|     const value = 1500000; | ||||
|     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); | ||||
|     const disp = instance(value); | ||||
|     expect(disp.text).toEqual('1.5'); | ||||
|     expect(disp.text).toEqual('1.50'); | ||||
|     expect(disp.suffix).toEqual(' Mil'); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -376,6 +376,53 @@ describe('Format value', () => { | |||
|       expect(disp.text).toEqual(value); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('number formatting for y axis ticks (dynamic decimals with trailing 0s trimming)', () => { | ||||
|     // all these tests have non-null adjacentDecimals != null, which we only do durink axis tick formatting
 | ||||
| 
 | ||||
|     it('should trim trailing zeros after decimal from fractional seconds when formatted as millis with adjacentDecimals=2', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ unit: 's' }, FieldType.number); | ||||
|       expect(processor(0.06, 2).text).toEqual('60'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should trim trailing zeros after decimal from number', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({}, FieldType.number); | ||||
|       expect(processor(1.2, 2).text).toEqual('1.2'); | ||||
| 
 | ||||
|       // dynamic!
 | ||||
|       expect(processor(13.50008, 3).text).toEqual('13.5'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros from currency*', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ unit: 'currencyUSD' }, FieldType.number); | ||||
|       expect(processor(1.2, 2).text).toEqual('1.20'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros from bool', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ unit: 'bool' }, FieldType.number); | ||||
|       expect(processor(1, 2).text).toEqual('True'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros from time', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({}, FieldType.time); | ||||
|       expect(processor(1666402869517, 2).text).toEqual('2022-10-21 20:41:09'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros from dateTimeAsUS', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ unit: 'dateTimeAsUS' }, FieldType.number); | ||||
|       expect(processor(1666402869517, 2).text).toEqual('10/21/2022 8:41:09 pm'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros from locale', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ unit: 'locale' }, FieldType.number); | ||||
|       expect(processor(3500000, 2).text).toEqual('3,500,000'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not attempt to trim zeros when explicit decimals: 5', () => { | ||||
|       const processor = getDisplayProcessorFromConfig({ decimals: 5 }, FieldType.number); | ||||
|       expect(processor(35, 2).text).toEqual('35.00000'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| describe('Date display options', () => { | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import { Field, FieldType } from '../types/dataFrame'; | |||
| import { DecimalCount, DisplayProcessor, DisplayValue } from '../types/displayValue'; | ||||
| import { anyToNumber } from '../utils/anyToNumber'; | ||||
| import { getValueMappingResult } from '../utils/valueMappings'; | ||||
| import { getValueFormat, isBooleanUnit } from '../valueFormats/valueFormats'; | ||||
| import { FormattedValue, getValueFormat, isBooleanUnit } from '../valueFormats/valueFormats'; | ||||
| 
 | ||||
| import { getScaleCalculator } from './scale'; | ||||
| 
 | ||||
|  | @ -72,16 +72,17 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP | |||
|     unit = 'string'; | ||||
|   } | ||||
| 
 | ||||
|   const hasCurrencyUnit = unit?.startsWith('currency'); | ||||
|   const hasBoolUnit = unit === 'bool'; | ||||
|   const isNumType = field.type === FieldType.number; | ||||
|   const isLocaleFormat = unit === 'locale'; | ||||
|   const shouldTrimTrailingDecimalZeros = | ||||
|     !hasDateUnit && !hasBoolUnit && !isLocaleFormat && isNumType && config.decimals == null; | ||||
|   const canTrimTrailingDecimalZeros = | ||||
|     !hasDateUnit && !hasCurrencyUnit && !hasBoolUnit && !isLocaleFormat && isNumType && config.decimals == null; | ||||
| 
 | ||||
|   const formatFunc = getValueFormat(unit || 'none'); | ||||
|   const scaleFunc = getScaleCalculator(field, options.theme); | ||||
| 
 | ||||
|   return (value: any, decimals?: DecimalCount) => { | ||||
|   return (value: any, adjacentDecimals?: DecimalCount) => { | ||||
|     const { mappings } = config; | ||||
|     const isStringUnit = unit === 'string'; | ||||
| 
 | ||||
|  | @ -117,14 +118,18 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP | |||
| 
 | ||||
|     if (!Number.isNaN(numeric)) { | ||||
|       if (text == null && !isBoolean(value)) { | ||||
|         const v = formatFunc(numeric, decimals ?? config.decimals, null, options.timeZone, showMs); | ||||
|         let v: FormattedValue; | ||||
| 
 | ||||
|         if (canTrimTrailingDecimalZeros && adjacentDecimals != null) { | ||||
|           v = formatFunc(numeric, adjacentDecimals, null, options.timeZone, showMs); | ||||
| 
 | ||||
|           // if no explicit decimals config, we strip trailing zeros e.g. 60.00 -> 60
 | ||||
|         // this is needed because we may have determined the minimum required `decimals` for y tick increments based on
 | ||||
|           // this is needed because we may have determined the minimum determined `adjacentDecimals` for y tick increments based on
 | ||||
|           // e.g. 'seconds' field unit (0.15s, 0.20s, 0.25s), but then formatFunc decided to return milli or nanos (150, 200, 250)
 | ||||
|           // so we end up with excess precision: 150.00, 200.00, 250.00
 | ||||
|         if (shouldTrimTrailingDecimalZeros) { | ||||
|           v.text = +v.text + ''; | ||||
|         } else { | ||||
|           v = formatFunc(numeric, config.decimals, null, options.timeZone, showMs); | ||||
|         } | ||||
| 
 | ||||
|         text = v.text; | ||||
|  |  | |||
|  | @ -279,7 +279,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ | |||
|             label: customConfig.axisLabel, | ||||
|             size: customConfig.axisWidth, | ||||
|             placement: customConfig.axisPlacement ?? AxisPlacement.Auto, | ||||
|             formatValue: (v, decimals) => formattedValueToString(fmt(v, config.decimals ?? decimals)), | ||||
|             formatValue: (v, decimals) => formattedValueToString(fmt(v, decimals)), | ||||
|             theme, | ||||
|             grid: { show: customConfig.axisGridShow }, | ||||
|             decimals: field.config.decimals, | ||||
|  |  | |||
|  | @ -253,7 +253,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({ | |||
|         label: customConfig.axisLabel, | ||||
|         size: customConfig.axisWidth, | ||||
|         placement, | ||||
|         formatValue: (v, decimals) => formattedValueToString(field.display!(v, field.config.decimals ?? decimals)), | ||||
|         formatValue: (v, decimals) => formattedValueToString(field.display!(v, decimals)), | ||||
|         theme, | ||||
|         grid: { show: customConfig.axisGridShow }, | ||||
|       }); | ||||
|  |  | |||
|  | @ -408,7 +408,7 @@ export function prepConfig(opts: PrepConfigOpts) { | |||
|     size: yAxisConfig.axisWidth || null, | ||||
|     label: yAxisConfig.axisLabel, | ||||
|     theme: theme, | ||||
|     formatValue: (v, decimals) => formattedValueToString(dispY(v, yField.config.decimals ?? decimals)), | ||||
|     formatValue: (v, decimals) => formattedValueToString(dispY(v, decimals)), | ||||
|     splits: isOrdianalY | ||||
|       ? (self: uPlot) => { | ||||
|           const meta = readHeatmapRowsCustomMeta(dataRef.current?.heatmap); | ||||
|  |  | |||
|  | @ -153,7 +153,7 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => { | |||
|     scaleKey: 'y', | ||||
|     isTime: false, | ||||
|     placement: AxisPlacement.Left, | ||||
|     formatValue: (v, decimals) => formattedValueToString(dispY!(v, countField.config.decimals ?? decimals)), | ||||
|     formatValue: (v, decimals) => formattedValueToString(dispY!(v, decimals)), | ||||
|     //splits: config.xSplits,
 | ||||
|     //values: config.xValues,
 | ||||
|     //grid: false,
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue