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 value = 1200; | ||||||
|     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); |     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); | ||||||
|     const disp = instance(value); |     const disp = instance(value); | ||||||
|     expect(disp.text).toEqual('1.2'); |     expect(disp.text).toEqual('1.20'); | ||||||
|     expect(disp.suffix).toEqual(' K'); |     expect(disp.suffix).toEqual(' K'); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  | @ -329,7 +329,7 @@ describe('Format value', () => { | ||||||
|     const value = 1500000; |     const value = 1500000; | ||||||
|     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); |     const instance = getDisplayProcessorFromConfig({ decimals: null, unit: 'short' }); | ||||||
|     const disp = instance(value); |     const disp = instance(value); | ||||||
|     expect(disp.text).toEqual('1.5'); |     expect(disp.text).toEqual('1.50'); | ||||||
|     expect(disp.suffix).toEqual(' Mil'); |     expect(disp.suffix).toEqual(' Mil'); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  | @ -376,6 +376,53 @@ describe('Format value', () => { | ||||||
|       expect(disp.text).toEqual(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', () => { | describe('Date display options', () => { | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import { Field, FieldType } from '../types/dataFrame'; | ||||||
| import { DecimalCount, DisplayProcessor, DisplayValue } from '../types/displayValue'; | import { DecimalCount, DisplayProcessor, DisplayValue } from '../types/displayValue'; | ||||||
| import { anyToNumber } from '../utils/anyToNumber'; | import { anyToNumber } from '../utils/anyToNumber'; | ||||||
| import { getValueMappingResult } from '../utils/valueMappings'; | import { getValueMappingResult } from '../utils/valueMappings'; | ||||||
| import { getValueFormat, isBooleanUnit } from '../valueFormats/valueFormats'; | import { FormattedValue, getValueFormat, isBooleanUnit } from '../valueFormats/valueFormats'; | ||||||
| 
 | 
 | ||||||
| import { getScaleCalculator } from './scale'; | import { getScaleCalculator } from './scale'; | ||||||
| 
 | 
 | ||||||
|  | @ -72,16 +72,17 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP | ||||||
|     unit = 'string'; |     unit = 'string'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   const hasCurrencyUnit = unit?.startsWith('currency'); | ||||||
|   const hasBoolUnit = unit === 'bool'; |   const hasBoolUnit = unit === 'bool'; | ||||||
|   const isNumType = field.type === FieldType.number; |   const isNumType = field.type === FieldType.number; | ||||||
|   const isLocaleFormat = unit === 'locale'; |   const isLocaleFormat = unit === 'locale'; | ||||||
|   const shouldTrimTrailingDecimalZeros = |   const canTrimTrailingDecimalZeros = | ||||||
|     !hasDateUnit && !hasBoolUnit && !isLocaleFormat && isNumType && config.decimals == null; |     !hasDateUnit && !hasCurrencyUnit && !hasBoolUnit && !isLocaleFormat && isNumType && config.decimals == null; | ||||||
| 
 | 
 | ||||||
|   const formatFunc = getValueFormat(unit || 'none'); |   const formatFunc = getValueFormat(unit || 'none'); | ||||||
|   const scaleFunc = getScaleCalculator(field, options.theme); |   const scaleFunc = getScaleCalculator(field, options.theme); | ||||||
| 
 | 
 | ||||||
|   return (value: any, decimals?: DecimalCount) => { |   return (value: any, adjacentDecimals?: DecimalCount) => { | ||||||
|     const { mappings } = config; |     const { mappings } = config; | ||||||
|     const isStringUnit = unit === 'string'; |     const isStringUnit = unit === 'string'; | ||||||
| 
 | 
 | ||||||
|  | @ -117,14 +118,18 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP | ||||||
| 
 | 
 | ||||||
|     if (!Number.isNaN(numeric)) { |     if (!Number.isNaN(numeric)) { | ||||||
|       if (text == null && !isBoolean(value)) { |       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
 |           // 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)
 |           // 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
 |           // so we end up with excess precision: 150.00, 200.00, 250.00
 | ||||||
|         if (shouldTrimTrailingDecimalZeros) { |  | ||||||
|           v.text = +v.text + ''; |           v.text = +v.text + ''; | ||||||
|  |         } else { | ||||||
|  |           v = formatFunc(numeric, config.decimals, null, options.timeZone, showMs); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         text = v.text; |         text = v.text; | ||||||
|  |  | ||||||
|  | @ -279,7 +279,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ | ||||||
|             label: customConfig.axisLabel, |             label: customConfig.axisLabel, | ||||||
|             size: customConfig.axisWidth, |             size: customConfig.axisWidth, | ||||||
|             placement: customConfig.axisPlacement ?? AxisPlacement.Auto, |             placement: customConfig.axisPlacement ?? AxisPlacement.Auto, | ||||||
|             formatValue: (v, decimals) => formattedValueToString(fmt(v, config.decimals ?? decimals)), |             formatValue: (v, decimals) => formattedValueToString(fmt(v, decimals)), | ||||||
|             theme, |             theme, | ||||||
|             grid: { show: customConfig.axisGridShow }, |             grid: { show: customConfig.axisGridShow }, | ||||||
|             decimals: field.config.decimals, |             decimals: field.config.decimals, | ||||||
|  |  | ||||||
|  | @ -253,7 +253,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptionsEX> = ({ | ||||||
|         label: customConfig.axisLabel, |         label: customConfig.axisLabel, | ||||||
|         size: customConfig.axisWidth, |         size: customConfig.axisWidth, | ||||||
|         placement, |         placement, | ||||||
|         formatValue: (v, decimals) => formattedValueToString(field.display!(v, field.config.decimals ?? decimals)), |         formatValue: (v, decimals) => formattedValueToString(field.display!(v, decimals)), | ||||||
|         theme, |         theme, | ||||||
|         grid: { show: customConfig.axisGridShow }, |         grid: { show: customConfig.axisGridShow }, | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  | @ -408,7 +408,7 @@ export function prepConfig(opts: PrepConfigOpts) { | ||||||
|     size: yAxisConfig.axisWidth || null, |     size: yAxisConfig.axisWidth || null, | ||||||
|     label: yAxisConfig.axisLabel, |     label: yAxisConfig.axisLabel, | ||||||
|     theme: theme, |     theme: theme, | ||||||
|     formatValue: (v, decimals) => formattedValueToString(dispY(v, yField.config.decimals ?? decimals)), |     formatValue: (v, decimals) => formattedValueToString(dispY(v, decimals)), | ||||||
|     splits: isOrdianalY |     splits: isOrdianalY | ||||||
|       ? (self: uPlot) => { |       ? (self: uPlot) => { | ||||||
|           const meta = readHeatmapRowsCustomMeta(dataRef.current?.heatmap); |           const meta = readHeatmapRowsCustomMeta(dataRef.current?.heatmap); | ||||||
|  |  | ||||||
|  | @ -153,7 +153,7 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => { | ||||||
|     scaleKey: 'y', |     scaleKey: 'y', | ||||||
|     isTime: false, |     isTime: false, | ||||||
|     placement: AxisPlacement.Left, |     placement: AxisPlacement.Left, | ||||||
|     formatValue: (v, decimals) => formattedValueToString(dispY!(v, countField.config.decimals ?? decimals)), |     formatValue: (v, decimals) => formattedValueToString(dispY!(v, decimals)), | ||||||
|     //splits: config.xSplits,
 |     //splits: config.xSplits,
 | ||||||
|     //values: config.xValues,
 |     //values: config.xValues,
 | ||||||
|     //grid: false,
 |     //grid: false,
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue