import { Optional } from 'utility-types' ; import { ScaleType } from '../../../scales/constants' ; import { compareByValueAsc } from '../../../utils/common' ; import { computeContinuousDataDomain , computeOrdinalDataDomain } from '../../../utils/domain' ; import { Logger } from '../../../utils/logger' ; import { getXNiceFromSpec , getXScaleTypeFromSpec } from '../scales/get_api_scales' ; import { ScaleConfigs } from '../state/selectors/get_api_scale_configs' ; import { BasicSeriesSpec , SeriesType , XScaleType } from '../utils/specs' ; import { XDomain } from './types' ; internal export function mergeXDomain ( { type , nice , isBandScale , timeZone , desiredTickCount , customDomain } , xValues , fallbackScale ? ) { let seriesXComputedDomains ; let minInterval = 0 ; if ( type === ScaleType . Ordinal || fallbackScale === ScaleType . Ordinal ) { if ( type !== ScaleType . Ordinal ) { Logger . warn ( `Each X value in a ${ type } x scale needs be be a number. Using ordinal x scale as fallback.` ) ; } seriesXComputedDomains = computeOrdinalDataDomain ( [ ... xValues ] , false , true ) ; if ( customDomain ) { if ( Array . isArray ( customDomain ) ) { seriesXComputedDomains = [ ... customDomain ] ; } else { if ( fallbackScale === ScaleType . Ordinal ) { Logger . warn ( `xDomain ignored for fallback ordinal scale. Options to resolve:
1) Correct data to match ${ type } scale type (see previous warning)
2) Change xScaleType to ordinal and set xDomain to Domain array` ) ; } else { Logger . warn ( 'xDomain for ordinal scale should be an array of values, not a DomainRange object. xDomain is ignored.' ) ; } } } } else { const domainOptions = { min : NaN , max : NaN , fit : true } ; seriesXComputedDomains = computeContinuousDataDomain ( [ ... xValues ] as number [ ] , type , domainOptions ) ; let customMinInterval ; if ( customDomain ) { if ( Array . isArray ( customDomain ) ) { Logger . warn ( 'xDomain for continuous scale should be a DomainRange object, not an array' ) ; } else { customMinInterval = customDomain . minInterval ; const [ computedDomainMin , computedDomainMax ] = seriesXComputedDomains ; if ( Number . isFinite ( customDomain . min ) && Number . isFinite ( customDomain . max ) ) { if ( customDomain . min > customDomain . max ) { Logger . warn ( 'Custom xDomain is invalid: min is greater than max. Custom domain is ignored.' ) ; } else { seriesXComputedDomains = [ customDomain . min , customDomain . max ] ; } } else if ( Number . isFinite ( customDomain . min ) ) { if ( customDomain . min > computedDomainMax ) { Logger . warn ( 'Custom xDomain is invalid: custom min is greater than computed max. Custom domain is ignored.' ) ; } else { seriesXComputedDomains = [ customDomain . min , computedDomainMax ] ; } } else if ( Number . isFinite ( customDomain . max ) ) { if ( computedDomainMin > customDomain . max ) { Logger . warn ( 'Custom xDomain is invalid: computed min is greater than custom max. Custom domain is ignored.' ) ; } else { seriesXComputedDomains = [ computedDomainMin , customDomain . max ] ; } } } } const computedMinInterval = findMinInterval ( [ ... xValues . values ( ) ] as number [ ] ) ; minInterval = getMinInterval ( computedMinInterval , xValues . size , customMinInterval ) ; } const validatedTimeZone = timeZone === 'local' || ! timeZone ? Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone : timeZone ; return { type : fallbackScale ?? type , nice , isBandScale , domain : seriesXComputedDomains , minInterval , timeZone : validatedTimeZone , logBase : customDomain && 'logBase' in customDomain ? customDomain . logBase : 10 , desiredTickCount , } ; } function getMinInterval ( computedMinInterval , size , customMinInterval ? ) { if ( customMinInterval === undefined ) { return computedMinInterval ; } if ( size > 1 && customMinInterval > computedMinInterval ) { Logger . warn ( 'Custom xDomain is invalid: custom minInterval is greater than computed minInterval. Using computed minInterval.' ) ; return computedMinInterval ; } if ( customMinInterval < 0 ) { Logger . warn ( 'Custom xDomain is invalid: custom minInterval is less than 0. Using computed minInterval.' ) ; return computedMinInterval ; } return customMinInterval ; } internal export function findMinInterval ( xValues ) { return xValues . length < 2 ? xValues . length : [ ... xValues ] . sort ( compareByValueAsc ) . reduce ( ( minInterval , current , i , sortedValues ) => { return i < xValues . length - 1 ? Math . min ( minInterval , Math . abs ( sortedValues [ i + 1 ] - current ) ) : minInterval ; } , Infinity ) ; } returns internal export function convertXScaleTypes ( specs ) { const seriesTypes = new Set < string | undefined > ( specs . map ( ( s ) => s . seriesType ) ) ; const scaleTypes = new Set ( specs . map ( ( s ) => getXScaleTypeFromSpec ( s . xScaleType ) ) ) ; const timeZones = new Set ( specs . filter ( ( s ) => s . timeZone ) . map ( ( s ) => s . timeZone ! . toLowerCase ( ) ) ) ; const niceDomains = specs . map ( ( s ) => getXNiceFromSpec ( s . xNice ) ) ; const type = scaleTypes . size === 1 ? scaleTypes . values ( ) . next ( ) . value : scaleTypes . has ( ScaleType . Ordinal ) ? ScaleType . Ordinal : ScaleType . Linear ; const nice = ! niceDomains . includes ( false ) ; const isBandScale = seriesTypes . has ( SeriesType . Bar ) ; const timeZone = timeZones . size === 1 ? timeZones . values ( ) . next ( ) . value : 'local' ; return { type , nice , isBandScale , timeZone } ; }