import { slidingWindow , zipper } from "@react-financial-charts/core" ; import { timeFormat , timeFormatDefaultLocale } from "d3-time-format" ; import financeDiscontinuousScale from "./financeDiscontinuousScale" ; import { defaultFormatters , levelDefinition , IFormatters } from "./levels" ; const evaluateLevel = ( row , date , i , formatters ) => { return levelDefinition . map ( ( eachLevel , idx ) => { return { level : levelDefinition . length - idx - 1 , format : formatters [ eachLevel ( row , date , i ) ] , } ; } ) . find ( ( level ) => ! ! level . format ) ; } ; const discontinuousIndexCalculator = slidingWindow ( ) . windowSize ( 2 ) . undefinedValue ( ( d , idx , { initialIndex , formatters } ) => { const i = initialIndex ; const row = { date : d . getTime ( ) , startOfSecond : false , startOf5Seconds : false , startOf15Seconds : false , startOf30Seconds : false , startOfMinute : false , startOf5Minutes : false , startOf15Minutes : false , startOf30Minutes : false , startOfHour : false , startOfEighthOfADay : false , startOfQuarterDay : false , startOfHalfDay : false , startOfDay : true , startOfWeek : false , startOfMonth : false , startOfQuarter : false , startOfYear : false , } ; const level = evaluateLevel ( row , d , i , formatters ) ; return { ... row , index : i , ... level } ; } ) ; const discontinuousIndexCalculatorLocalTime = discontinuousIndexCalculator . accumulator ( ( [ prevDate , nowDate ] , i , idx , { initialIndex , formatters } ) => { const nowSeconds = nowDate . getSeconds ( ) ; const nowMinutes = nowDate . getMinutes ( ) ; const nowHours = nowDate . getHours ( ) ; const nowDay = nowDate . getDay ( ) ; const nowMonth = nowDate . getMonth ( ) ; const startOfSecond = nowSeconds !== prevDate . getSeconds ( ) ; const startOf5Seconds = startOfSecond && nowSeconds % 5 === 0 ; const startOf15Seconds = startOfSecond && nowSeconds % 15 === 0 ; const startOf30Seconds = startOfSecond && nowSeconds % 30 === 0 ; const startOfMinute = nowMinutes !== prevDate . getMinutes ( ) ; const startOf5Minutes = startOfMinute && nowMinutes % 5 <= prevDate . getMinutes ( ) % 5 ; const startOf15Minutes = startOfMinute && nowMinutes % 15 <= prevDate . getMinutes ( ) % 15 ; const startOf30Minutes = startOfMinute && nowMinutes % 30 <= prevDate . getMinutes ( ) % 30 ; const startOfHour = nowHours !== prevDate . getHours ( ) ; const startOfEighthOfADay = startOfHour && nowHours % 3 === 0 ; const startOfQuarterDay = startOfHour && nowHours % 6 === 0 ; const startOfHalfDay = startOfHour && nowHours % 12 === 0 ; const startOfDay = nowDay !== prevDate . getDay ( ) ; const startOfWeek = nowDay < prevDate . getDay ( ) ; const startOfMonth = nowMonth !== prevDate . getMonth ( ) ; const startOfQuarter = startOfMonth && nowMonth % 3 <= prevDate . getMonth ( ) % 3 ; const startOfYear = nowDate . getFullYear ( ) !== prevDate . getFullYear ( ) ; const row = { date : nowDate . getTime ( ) , startOfSecond , startOf5Seconds , startOf15Seconds , startOf30Seconds , startOfMinute , startOf5Minutes , startOf15Minutes , startOf30Minutes , startOfHour , startOfEighthOfADay , startOfQuarterDay , startOfHalfDay , startOfDay , startOfWeek , startOfMonth , startOfQuarter , startOfYear , } ; const level = evaluateLevel ( row , nowDate , i , formatters ) ; return { ... row , index : i + initialIndex , ... level } ; } ) ; function createIndex ( realDateAccessor , inputDateAccessor , initialIndex , formatters ) { return function ( data ) { const dateAccessor = realDateAccessor ( inputDateAccessor ) ; const calculate = discontinuousIndexCalculatorLocalTime . source ( dateAccessor ) . misc ( { initialIndex , formatters } ) ; const index = calculate ( data ) . map ( ( each ) => { const { format } = each ; return { index : each . index , level : each . level , date : new Date ( each . date ) , format : timeFormat ( format ) , } ; } ) ; return { index } ; } ; } export interface DiscontinuousTimeScaleProviderBuilder { ( data ) : { data : any [ ] ; xScale : any ; xAccessor : ( data : any ) => number ; displayXAccessor : ( data : any ) => number ; } ; initialIndex ( ) : any ; initialIndex ( x ) : DiscontinuousTimeScaleProviderBuilder ; inputDateAccessor ( ) : any ; inputDateAccessor ( accessor ) : DiscontinuousTimeScaleProviderBuilder ; indexAccessor ( ) : any ; indexAccessor ( x ) : DiscontinuousTimeScaleProviderBuilder ; indexMutator ( ) : any ; indexMutator ( x ) : DiscontinuousTimeScaleProviderBuilder ; withIndex ( ) : any ; withIndex ( x ) : DiscontinuousTimeScaleProviderBuilder ; utc ( ) : DiscontinuousTimeScaleProviderBuilder ; setLocale ( locale ? , formatters ? ) : DiscontinuousTimeScaleProviderBuilder ; indexCalculator ( ) : any ; } export function discontinuousTimeScaleProviderBuilder ( ) { let initialIndex = 0 ; let realDateAccessor = ( d ) => d ; let inputDateAccessor = ( d ) => d . date ; let indexAccessor = ( d ) => d . idx ; let indexMutator = ( d , idx ) => ( { ... d , idx } ) ; let withIndex ; let currentFormatters = defaultFormatters ; const discontinuousTimeScaleProvider = function ( data ) { let index = withIndex ; if ( index === undefined ) { const response = createIndex ( realDateAccessor , inputDateAccessor , initialIndex , currentFormatters ) ( data ) ; index = response . index ; } const inputIndex = index ; const xScale = financeDiscontinuousScale ( inputIndex ) ; const mergedData = zipper ( ) . combine ( indexMutator ) ; const finalData = mergedData ( data , inputIndex ) ; return { data : finalData , xScale , xAccessor : ( d ) => d && indexAccessor ( d ) ?. index , displayXAccessor : realDateAccessor ( inputDateAccessor ) , } ; } ; discontinuousTimeScaleProvider . initialIndex = function ( x ) { if ( ! arguments . length ) { return initialIndex ; } initialIndex = x ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . inputDateAccessor = function ( x ) { if ( ! arguments . length ) { return inputDateAccessor ; } inputDateAccessor = x ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . indexAccessor = function ( x ) { if ( ! arguments . length ) { return indexAccessor ; } indexAccessor = x ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . indexMutator = function ( x ) { if ( ! arguments . length ) { return indexMutator ; } indexMutator = x ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . withIndex = function ( x ) { if ( ! arguments . length ) { return withIndex ; } withIndex = x ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . utc = ( ) => { realDateAccessor = ( dateAccessor ) => ( d ) => { const date = dateAccessor ( d ) ; const offsetInMillis = date . getTimezoneOffset ( ) * 60 * 1000 ; return new Date ( date . getTime ( ) + offsetInMillis ) ; } ; return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . setLocale = ( locale ? , formatters ? ) => { if ( locale !== undefined ) { timeFormatDefaultLocale ( locale ) ; } if ( formatters !== undefined ) { currentFormatters = formatters ; } return discontinuousTimeScaleProvider ; } ; discontinuousTimeScaleProvider . indexCalculator = function ( ) { return createIndex ( realDateAccessor , inputDateAccessor , initialIndex , currentFormatters ) ; } ; return discontinuousTimeScaleProvider as DiscontinuousTimeScaleProviderBuilder ; } export default discontinuousTimeScaleProviderBuilder ( ) ;