UNPKG

virool-pivot

Version:

A web-based exploratory visualization UI for Druid.io

211 lines (173 loc) 7.84 kB
import * as d3 from 'd3'; import { Timezone, Duration, WallTime, month, day, hour, minute } from 'chronoshift'; import { TimeRange, TimeBucketAction } from 'plywood'; import { getBestBucketUnitForRange } from '../../models/granularity/granularity'; const FORMAT_WITH_YEAR = d3.time.format('%b %-d, %Y'); const FORMAT_WITHOUT_YEAR = d3.time.format('%b %-d'); const FORMAT_TIME_OF_DAY_WITHOUT_MINUTES = d3.time.format('%-I%p'); const FORMAT_TIME_OF_DAY_WITH_MINUTES = d3.time.format('%-I:%M%p'); const FORMAT_FULL_MONTH_WITH_YEAR = d3.time.format('%B %Y'); function formatTimeOfDay(d: Date): string { return d.getMinutes() ? FORMAT_TIME_OF_DAY_WITH_MINUTES(d) : FORMAT_TIME_OF_DAY_WITHOUT_MINUTES(d); } function isCurrentYear(year: number, timezone: Timezone): boolean { var nowWallTime = WallTime.UTCToWallTime(new Date(), timezone.toString()); return nowWallTime.getFullYear() === year; } export interface Locale { shortDays: string[]; shortMonths: string[]; weekStart: number; } export enum DisplayYear { ALWAYS, NEVER, IF_DIFF } export function getEndWallTimeInclusive(exclusiveEnd: Date, timezone: Timezone) { return WallTime.UTCToWallTime(exclusiveToInclusiveEnd(exclusiveEnd), timezone.toString()); } export function exclusiveToInclusiveEnd(exclusiveEnd: Date): Date { return new Date(exclusiveEnd.valueOf() - 1); } export function formatTimeRange(timeRange: TimeRange, timezone: Timezone, displayYear: DisplayYear): string { var { start, end } = timeRange; var startWallTime = WallTime.UTCToWallTime(start, timezone.toString()); var endWallTime = WallTime.UTCToWallTime(end, timezone.toString()); var endWallTimeInclusive = getEndWallTimeInclusive(end, timezone); var showingYear = true; var formatted: string; if (startWallTime.getFullYear() !== endWallTimeInclusive.getFullYear()) { formatted = [FORMAT_WITH_YEAR(startWallTime), FORMAT_WITH_YEAR(endWallTimeInclusive)].join(' - '); } else { showingYear = displayYear === DisplayYear.ALWAYS || (displayYear === DisplayYear.IF_DIFF && !isCurrentYear(endWallTimeInclusive.getFullYear(), timezone)); var fmt = showingYear ? FORMAT_WITH_YEAR : FORMAT_WITHOUT_YEAR; if (startWallTime.getMonth() !== endWallTimeInclusive.getMonth() || startWallTime.getDate() !== endWallTimeInclusive.getDate()) { formatted = [FORMAT_WITHOUT_YEAR(startWallTime), fmt(endWallTimeInclusive)].join(' - '); } else { formatted = fmt(startWallTime); } } if (startWallTime.getHours() || startWallTime.getMinutes() || endWallTime.getHours() || endWallTime.getMinutes()) { formatted += (showingYear ? ' ' : ', '); var startTimeStr = formatTimeOfDay(startWallTime).toLowerCase(); var endTimeStr = formatTimeOfDay(endWallTime).toLowerCase(); if (startTimeStr === endTimeStr) { formatted += startTimeStr; } else { if (startTimeStr.substr(-2) === endTimeStr.substr(-2)) { startTimeStr = startTimeStr.substr(0, startTimeStr.length - 2); } formatted += [startTimeStr, endTimeStr].join('-'); } } return formatted; } // calendar utils export function monthToWeeks(firstDayOfMonth: Date, timezone: Timezone, locale: Locale): Date[][] { const weeks: Date[][] = []; const firstDayNextMonth = month.shift(firstDayOfMonth, timezone, 1); let week: Date[] = []; let currentPointer = day.floor(firstDayOfMonth, timezone); while (currentPointer < firstDayNextMonth) { var wallTime = WallTime.UTCToWallTime(currentPointer, timezone.toString()); if ((wallTime.getDay() === locale.weekStart || 0) && week.length > 0) { weeks.push(week); week = []; } week.push(currentPointer); currentPointer = day.shift(currentPointer, timezone, 1); } // push last week if (week.length > 0) weeks.push(week); return weeks; } export function prependDays(timezone: Timezone, weekPrependTo: Date[], countPrepend: number): Date[] { for (var i = 0; i < countPrepend; i++) { var firstDate = weekPrependTo[0]; var shiftedDate = day.shift(firstDate, timezone, -1); weekPrependTo.unshift(shiftedDate); } return weekPrependTo; } export function appendDays(timezone: Timezone, weekAppendTo: Date[], countAppend: number): Date[] { for (var i = 0; i < countAppend; i++) { var lastDate = weekAppendTo[weekAppendTo.length - 1]; var shiftedDate = day.shift(lastDate, timezone, 1); weekAppendTo.push(shiftedDate); } return weekAppendTo; } export function shiftOneDay(floored: Date, timezone: Timezone) { return day.shift(floored, timezone, 1); } export function datesEqual(d1: Date, d2: Date): boolean { if (!Boolean(d1) === Boolean(d2)) return false; if (d1 === d2 ) return true; return d1.valueOf() === d2.valueOf(); } export function getWallTimeDay(date: Date, timezone: Timezone) { return WallTime.UTCToWallTime(date, timezone.toString()).getDate(); } export function getWallTimeMonthWithYear(date: Date, timezone: Timezone) { return FORMAT_FULL_MONTH_WITH_YEAR(WallTime.UTCToWallTime(date, timezone.toString())); } export function wallTimeInclusiveEndEqual(d1: Date, d2: Date, timezone: Timezone): boolean { if (!Boolean(d1) === Boolean(d2)) return false; if (d1 === d2 ) return true; const d1InclusiveEnd = wallTimeHelper(getEndWallTimeInclusive(d1, timezone)); const d2InclusiveEnd = wallTimeHelper(getEndWallTimeInclusive(d2, timezone)); return datesEqual(d1InclusiveEnd, d2InclusiveEnd); } export function getWallTimeString(date: Date, timezone: Timezone, includeTime?: boolean, delimiter?: string): string { const wallTimeISOString = cleanISOString(wallTimeHelper(WallTime.UTCToWallTime(date, timezone.toString())).toISOString()); if (includeTime) { return wallTimeISOString.replace('T', delimiter || ', '); } return wallTimeISOString.replace( /:\d\d/, '').split('T')[0]; } function wallTimeHelper(wallTime: any) { return wallTime['wallTime']; } function cleanISOString(input: string) { return input.replace(/(\.\d\d\d)?Z?$/, ''); } export function getTimeTicks(timeRange: TimeRange, timezone: Timezone): Date[] { const { start, end } = timeRange; const tickDuration = getBestBucketUnitForRange(timeRange, true) as Duration; return tickDuration.materialize(start, end, timezone); } function pad(input: number) { if (input < 10) return `0${input}`; return String(input); } export function formatTimeBasedOnGranularity(range: TimeRange, granularity: Duration, timezone: Timezone, locale: Locale): string { const wallTimeStart = WallTime.UTCToWallTime(range.start, timezone.toString()); const year = wallTimeStart.getFullYear(); const month = wallTimeStart.getMonth(); const day = wallTimeStart.getDate(); const hour = wallTimeStart.getHours(); const minute = wallTimeStart.getMinutes(); const second = wallTimeStart.getSeconds(); const monthString = locale.shortMonths[month]; const hourToTwelve = hour % 12 === 0 ? 12 : hour % 12; const amPm = (hour / 12) >= 1 ? 'pm' : 'am'; var granularityString = granularity.toJS(); var unit = granularityString.substring(granularityString.length - 1); switch (unit) { case 'S': return `${monthString} ${day}, ${pad(hour)}:${pad(minute)}:${pad(second)}`; case 'M': var prefix = granularityString.substring(0, 2); return prefix === "PT" ? `${monthString} ${day}, ${hourToTwelve}:${pad(minute)}${amPm}` : `${monthString}, ${year}`; case 'H': return `${monthString} ${day}, ${year}, ${hourToTwelve}${amPm}`; case 'D': return `${monthString} ${day}, ${year}`; case 'W': return `${formatTimeRange(range, timezone, DisplayYear.ALWAYS)}`; default: return cleanISOString(wallTimeHelper(wallTimeStart).toISOString()); } } export function formatGranularity(granularity: string): string { return granularity.replace(/^PT?/, ''); }