UNPKG

@antv/scale

Version:

Toolkit for mapping abstract data into visual representation.

185 lines (166 loc) 4.17 kB
export type TimeTransform = (d: Date, ...rest: any[]) => Date; type TimeRange = (start: Date, stop: Date, step: number, shouldAdjust?: boolean) => Date[]; type TimeProcess = (d: Date, ...rest: any[]) => void; type TimeField = (d: Date) => number; export const DURATION_SECOND = 1000; export const DURATION_MINUTE = DURATION_SECOND * 60; export const DURATION_HOUR = DURATION_MINUTE * 60; export const DURATION_DAY = DURATION_HOUR * 24; export const DURATION_WEEK = DURATION_DAY * 7; export const DURATION_MONTH = DURATION_DAY * 30; export const DURATION_YEAR = DURATION_DAY * 365; export type Interval = { floor: TimeTransform; ceil: TimeTransform; range: TimeRange; duration: number; }; export type IntervalMap = { millisecond: Interval; second: Interval; minute: Interval; hour: Interval; day: Interval; week: Interval; month: Interval; year: Interval; }; export function createInterval(duration: number, floorish: TimeProcess, offseti: TimeProcess, field?: TimeField) { const adjust: TimeTransform = (date, step) => { const test = (date: Date) => field(date) % step === 0; let i = step; while (i && !test(date)) { offseti(date, -1); i -= 1; } return date; }; const floori: TimeProcess = (date, step?: number) => { if (step) adjust(date, step); floorish(date); }; const floor: TimeTransform = (date, step?: number) => { const d = new Date(+date); floori(d, step); return d; }; const ceil: TimeTransform = (date, step?: number) => { const d = new Date(+date - 1); floori(d, step); offseti(d, step); floori(d); return d; }; const range = (start: Date, stop: Date, step: number, shouldAdjust?: boolean) => { const ticks = []; const roundStep = Math.floor(step); const t = shouldAdjust ? ceil(start, step) : ceil(start); for (let i = t; i < stop; offseti(i, roundStep), floori(i)) { ticks.push(new Date(+i)); } return ticks; }; return { ceil, floor, range, duration, }; } export const millisecond: Interval = createInterval( 1, (date) => date, (date, step = 1) => { date.setTime(+date + step); }, (date) => date.getTime() ); export const second: Interval = createInterval( DURATION_SECOND, (date) => { date.setMilliseconds(0); }, (date, step = 1) => { date.setTime(+date + DURATION_SECOND * step); }, (date) => date.getSeconds() ); export const minute: Interval = createInterval( DURATION_MINUTE, (date) => { date.setSeconds(0, 0); }, (date, step = 1) => { date.setTime(+date + DURATION_MINUTE * step); }, (date) => date.getMinutes() ); export const hour: Interval = createInterval( DURATION_HOUR, (date) => { date.setMinutes(0, 0, 0); }, (date, step = 1) => { date.setTime(+date + DURATION_HOUR * step); }, (date) => date.getHours() ); export const day: Interval = createInterval( DURATION_DAY, (date) => { date.setHours(0, 0, 0, 0); }, (date, step = 1) => { date.setTime(+date + DURATION_DAY * step); }, (date) => date.getDate() - 1 ); export const month: Interval = createInterval( DURATION_MONTH, (date) => { date.setDate(1); date.setHours(0, 0, 0, 0); }, (date, step = 1) => { const month = date.getMonth(); date.setMonth(month + step); }, (date) => date.getMonth() ); export const week: Interval = createInterval( DURATION_WEEK, (date) => { date.setDate(date.getDate() - (date.getDay() % 7)); date.setHours(0, 0, 0, 0); }, (date, step = 1) => { date.setDate(date.getDate() + 7 * step); }, (date) => { const start = month.floor(date); const end = new Date(+date); return Math.floor((+end - +start) / DURATION_WEEK); } ); export const year: Interval = createInterval( DURATION_YEAR, (date) => { date.setMonth(0, 1); date.setHours(0, 0, 0, 0); }, (date, step = 1) => { const year = date.getFullYear(); date.setFullYear(year + step); }, (date) => date.getFullYear() ); export const localIntervalMap: IntervalMap = { millisecond, second, minute, hour, day, week, month, year, };