/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you under the Apache License, Version 2.0 (the
|
* "License"); you may not use this file except in compliance
|
* with the License. You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing,
|
* software distributed under the License is distributed on an
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* KIND, either express or implied. See the License for the
|
* specific language governing permissions and limitations
|
* under the License.
|
*/
|
|
import * as zrUtil from 'zrender/src/core/util';
|
import {TimeAxisLabelFormatterOption} from './../coord/axisCommonTypes';
|
import * as numberUtil from './number';
|
import {TimeScaleTick} from './types';
|
import { getDefaultLocaleModel, getLocaleModel, SYSTEM_LANG, LocaleOption } from '../core/locale';
|
import Model from '../model/Model';
|
|
export const ONE_SECOND = 1000;
|
export const ONE_MINUTE = ONE_SECOND * 60;
|
export const ONE_HOUR = ONE_MINUTE * 60;
|
export const ONE_DAY = ONE_HOUR * 24;
|
export const ONE_YEAR = ONE_DAY * 365;
|
|
export const defaultLeveledFormatter = {
|
year: '{yyyy}',
|
month: '{MMM}',
|
day: '{d}',
|
hour: '{HH}:{mm}',
|
minute: '{HH}:{mm}',
|
second: '{HH}:{mm}:{ss}',
|
millisecond: '{hh}:{mm}:{ss} {SSS}',
|
none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss} {SSS}'
|
};
|
|
const fullDayFormatter = '{yyyy}-{MM}-{dd}';
|
|
export const fullLeveledFormatter = {
|
year: '{yyyy}',
|
month: '{yyyy}-{MM}',
|
day: fullDayFormatter,
|
hour: fullDayFormatter + ' ' + defaultLeveledFormatter.hour,
|
minute: fullDayFormatter + ' ' + defaultLeveledFormatter.minute,
|
second: fullDayFormatter + ' ' + defaultLeveledFormatter.second,
|
millisecond: defaultLeveledFormatter.none
|
};
|
|
export type PrimaryTimeUnit = 'millisecond' | 'second' | 'minute' | 'hour'
|
| 'day' | 'month' | 'year';
|
export type TimeUnit = PrimaryTimeUnit | 'half-year' | 'quarter' | 'week'
|
| 'half-week' | 'half-day' | 'quarter-day';
|
|
export const primaryTimeUnits: PrimaryTimeUnit[] = [
|
'year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'
|
];
|
export const timeUnits: TimeUnit[] = [
|
'year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day',
|
'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond'
|
];
|
|
export function pad(str: string | number, len: number): string {
|
str += '';
|
return '0000'.substr(0, len - (str as string).length) + str;
|
}
|
|
export function getPrimaryTimeUnit(timeUnit: TimeUnit): PrimaryTimeUnit {
|
switch (timeUnit) {
|
case 'half-year':
|
case 'quarter':
|
return 'month';
|
case 'week':
|
case 'half-week':
|
return 'day';
|
case 'half-day':
|
case 'quarter-day':
|
return 'hour';
|
default:
|
// year, minutes, second, milliseconds
|
return timeUnit;
|
}
|
}
|
|
export function isPrimaryTimeUnit(timeUnit: TimeUnit): boolean {
|
return timeUnit === getPrimaryTimeUnit(timeUnit);
|
}
|
|
export function getDefaultFormatPrecisionOfInterval(timeUnit: PrimaryTimeUnit): PrimaryTimeUnit {
|
switch (timeUnit) {
|
case 'year':
|
case 'month':
|
return 'day';
|
case 'millisecond':
|
return 'millisecond';
|
default:
|
// Also for day, hour, minute, second
|
return 'second';
|
}
|
}
|
|
export function format(
|
// Note: The result based on `isUTC` are totally different, which can not be just simply
|
// substituted by the result without `isUTC`. So we make the param `isUTC` mandatory.
|
time: unknown, template: string, isUTC: boolean, lang?: string | Model<LocaleOption>
|
): string {
|
const date = numberUtil.parseDate(time);
|
const y = date[fullYearGetterName(isUTC)]();
|
const M = date[monthGetterName(isUTC)]() + 1;
|
const q = Math.floor((M - 1) / 4) + 1;
|
const d = date[dateGetterName(isUTC)]();
|
const e = date['get' + (isUTC ? 'UTC' : '') + 'Day' as 'getDay' | 'getUTCDay']();
|
const H = date[hoursGetterName(isUTC)]();
|
const h = (H - 1) % 12 + 1;
|
const m = date[minutesGetterName(isUTC)]();
|
const s = date[secondsGetterName(isUTC)]();
|
const S = date[millisecondsGetterName(isUTC)]();
|
|
|
const localeModel = lang instanceof Model ? lang
|
: getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel();
|
const timeModel = localeModel.getModel('time');
|
const month = timeModel.get('month');
|
const monthAbbr = timeModel.get('monthAbbr');
|
const dayOfWeek = timeModel.get('dayOfWeek');
|
const dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr');
|
|
return (template || '')
|
.replace(/{yyyy}/g, y + '')
|
.replace(/{yy}/g, y % 100 + '')
|
.replace(/{Q}/g, q + '')
|
.replace(/{MMMM}/g, month[M - 1])
|
.replace(/{MMM}/g, monthAbbr[M - 1])
|
.replace(/{MM}/g, pad(M, 2))
|
.replace(/{M}/g, M + '')
|
.replace(/{dd}/g, pad(d, 2))
|
.replace(/{d}/g, d + '')
|
.replace(/{eeee}/g, dayOfWeek[e])
|
.replace(/{ee}/g, dayOfWeekAbbr[e])
|
.replace(/{e}/g, e + '')
|
.replace(/{HH}/g, pad(H, 2))
|
.replace(/{H}/g, H + '')
|
.replace(/{hh}/g, pad(h + '', 2))
|
.replace(/{h}/g, h + '')
|
.replace(/{mm}/g, pad(m, 2))
|
.replace(/{m}/g, m + '')
|
.replace(/{ss}/g, pad(s, 2))
|
.replace(/{s}/g, s + '')
|
.replace(/{SSS}/g, pad(S, 3))
|
.replace(/{S}/g, S + '');
|
}
|
|
export function leveledFormat(
|
tick: TimeScaleTick,
|
idx: number,
|
formatter: TimeAxisLabelFormatterOption,
|
lang: string | Model<LocaleOption>,
|
isUTC: boolean
|
) {
|
let template = null;
|
if (typeof formatter === 'string') {
|
// Single formatter for all units at all levels
|
template = formatter;
|
}
|
else if (typeof formatter === 'function') {
|
// Callback formatter
|
template = formatter(tick.value, idx, {
|
level: tick.level
|
});
|
}
|
else {
|
const defaults = zrUtil.extend({}, defaultLeveledFormatter);
|
if (tick.level > 0) {
|
for (let i = 0; i < primaryTimeUnits.length; ++i) {
|
defaults[primaryTimeUnits[i]] = `{primary|${defaults[primaryTimeUnits[i]]}}`;
|
}
|
}
|
|
const mergedFormatter = (formatter
|
? (formatter.inherit === false
|
? formatter // Use formatter with bigger units
|
: zrUtil.defaults(formatter, defaults)
|
)
|
: defaults) as any;
|
|
const unit = getUnitFromValue(tick.value, isUTC);
|
if (mergedFormatter[unit]) {
|
template = mergedFormatter[unit];
|
}
|
else if (mergedFormatter.inherit) {
|
// Unit formatter is not defined and should inherit from bigger units
|
const targetId = timeUnits.indexOf(unit);
|
for (let i = targetId - 1; i >= 0; --i) {
|
if (mergedFormatter[unit]) {
|
template = mergedFormatter[unit];
|
break;
|
}
|
}
|
template = template || defaults.none;
|
}
|
|
if (zrUtil.isArray(template)) {
|
let levelId = tick.level == null
|
? 0
|
: (tick.level >= 0 ? tick.level : template.length + tick.level);
|
levelId = Math.min(levelId, template.length - 1);
|
template = template[levelId];
|
}
|
}
|
|
return format(new Date(tick.value), template, isUTC, lang);
|
}
|
|
export function getUnitFromValue(
|
value: number | string | Date,
|
isUTC: boolean
|
): PrimaryTimeUnit {
|
const date = numberUtil.parseDate(value);
|
const M = (date as any)[monthGetterName(isUTC)]() + 1;
|
const d = (date as any)[dateGetterName(isUTC)]();
|
const h = (date as any)[hoursGetterName(isUTC)]();
|
const m = (date as any)[minutesGetterName(isUTC)]();
|
const s = (date as any)[secondsGetterName(isUTC)]();
|
const S = (date as any)[millisecondsGetterName(isUTC)]();
|
|
const isSecond = S === 0;
|
const isMinute = isSecond && s === 0;
|
const isHour = isMinute && m === 0;
|
const isDay = isHour && h === 0;
|
const isMonth = isDay && d === 1;
|
const isYear = isMonth && M === 1;
|
|
if (isYear) {
|
return 'year';
|
}
|
else if (isMonth) {
|
return 'month';
|
}
|
else if (isDay) {
|
return 'day';
|
}
|
else if (isHour) {
|
return 'hour';
|
}
|
else if (isMinute) {
|
return 'minute';
|
}
|
else if (isSecond) {
|
return 'second';
|
}
|
else {
|
return 'millisecond';
|
}
|
}
|
|
export function getUnitValue(
|
value: number | Date,
|
unit: TimeUnit,
|
isUTC: boolean
|
) : number {
|
const date = typeof value === 'number'
|
? numberUtil.parseDate(value)
|
: value;
|
unit = unit || getUnitFromValue(value, isUTC);
|
|
switch (unit) {
|
case 'year':
|
return date[fullYearGetterName(isUTC)]();
|
case 'half-year':
|
return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;
|
case 'quarter':
|
return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);
|
case 'month':
|
return date[monthGetterName(isUTC)]();
|
case 'day':
|
return date[dateGetterName(isUTC)]();
|
case 'half-day':
|
return date[hoursGetterName(isUTC)]() / 24;
|
case 'hour':
|
return date[hoursGetterName(isUTC)]();
|
case 'minute':
|
return date[minutesGetterName(isUTC)]();
|
case 'second':
|
return date[secondsGetterName(isUTC)]();
|
case 'millisecond':
|
return date[millisecondsGetterName(isUTC)]();
|
}
|
}
|
|
export function fullYearGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCFullYear' : 'getFullYear';
|
}
|
|
export function monthGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCMonth' : 'getMonth';
|
}
|
|
export function dateGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCDate' : 'getDate';
|
}
|
|
export function hoursGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCHours' : 'getHours';
|
}
|
|
export function minutesGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCMinutes' : 'getMinutes';
|
}
|
|
export function secondsGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCSeconds' : 'getSeconds';
|
}
|
|
export function millisecondsGetterName(isUTC: boolean) {
|
return isUTC ? 'getUTCSeconds' : 'getSeconds';
|
}
|
|
export function fullYearSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCFullYear' : 'setFullYear';
|
}
|
|
export function monthSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCMonth' : 'setMonth';
|
}
|
|
export function dateSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCDate' : 'setDate';
|
}
|
|
export function hoursSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCHours' : 'setHours';
|
}
|
|
export function minutesSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCMinutes' : 'setMinutes';
|
}
|
|
export function secondsSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCSeconds' : 'setSeconds';
|
}
|
|
export function millisecondsSetterName(isUTC: boolean) {
|
return isUTC ? 'setUTCSeconds' : 'setSeconds';
|
}
|