highcharts
Version:
JavaScript charting framework
173 lines (172 loc) • 7.19 kB
JavaScript
/* *
*
* (c) 2010-2025 Torstein Honsi
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
;
import TimeBase from '../Shared/TimeBase.js';
import U from '../Core/Utilities.js';
const { defined, extend, timeUnits } = U;
/* *
*
* Constants
*
* */
class Time extends TimeBase {
/**
* Return an array with time positions distributed on round time values
* right and right after min and max. Used in datetime axes as well as for
* grouping data on a datetime axis.
*
* @function Highcharts.Time#getTimeTicks
*
* @param {Highcharts.TimeNormalizedObject} normalizedInterval
* The interval in axis values (ms) and the count
*
* @param {number} [min]
* The minimum in axis values
*
* @param {number} [max]
* The maximum in axis values
*
* @param {number} [startOfWeek=1]
*
* @return {Highcharts.AxisTickPositionsArray}
* Time positions
*/
getTimeTicks(normalizedInterval, min, max, startOfWeek) {
const time = this, tickPositions = [], higherRanks = {}, { count = 1, unitRange } = normalizedInterval;
let [year, month, dayOfMonth, hours, minutes, seconds] = time.toParts(min), milliseconds = (min || 0) % 1000, variableDayLength;
startOfWeek ?? (startOfWeek = 1);
if (defined(min)) { // #1300
milliseconds = unitRange >= timeUnits.second ?
0 : // #3935
count * Math.floor(milliseconds / count);
if (unitRange >= timeUnits.second) { // Second
seconds = unitRange >= timeUnits.minute ?
0 : // #3935
count * Math.floor(seconds / count);
}
if (unitRange >= timeUnits.minute) { // Minute
minutes = unitRange >= timeUnits.hour ?
0 :
count * Math.floor(minutes / count);
}
if (unitRange >= timeUnits.hour) { // Hour
hours = unitRange >= timeUnits.day ?
0 :
count * Math.floor(hours / count);
}
if (unitRange >= timeUnits.day) { // Day
dayOfMonth = unitRange >= timeUnits.month ?
1 :
Math.max(1, count * Math.floor(dayOfMonth / count));
}
if (unitRange >= timeUnits.month) { // Month
month = unitRange >= timeUnits.year ? 0 :
count * Math.floor(month / count);
}
if (unitRange >= timeUnits.year) { // Year
year -= year % count;
}
// Week is a special case that runs outside the hierarchy
if (unitRange === timeUnits.week) {
if (count) {
min = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
}
// Get start of current week, independent of count
const weekday = this.dateTimeFormat({
timeZone: this.timezone,
weekday: 'narrow'
}, min, 'es'),
// Spanish weekday index
weekdayNo = 'DLMXJVS'.indexOf(weekday);
dayOfMonth += -weekdayNo + startOfWeek +
// We don't want to skip days that are before
// startOfWeek (#7051)
(weekdayNo < startOfWeek ? -7 : 0);
}
min = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
// Handle local timezone offset
if (time.variableTimezone && defined(max)) {
// Detect whether we need to take the DST crossover into
// consideration. If we're crossing over DST, the day length may
// be 23h or 25h and we need to compute the exact clock time for
// each tick instead of just adding hours. This comes at a cost,
// so first we find out if it is needed (#4951).
variableDayLength = (
// Long range, assume we're crossing over.
max - min > 4 * timeUnits.month ||
// Short range, check if min and max are in different time
// zones.
time.getTimezoneOffset(min) !==
time.getTimezoneOffset(max));
}
// Iterate and add tick positions at appropriate values
let t = min, i = 1;
while (t < max) {
tickPositions.push(t);
// Increase the years
if (unitRange === timeUnits.year) {
t = time.makeTime(year + i * count, 0);
// Increase the months
}
else if (unitRange === timeUnits.month) {
t = time.makeTime(year, month + i * count);
// If we're using local time, the interval is not fixed as it
// jumps one hour at the DST crossover
}
else if (variableDayLength && (unitRange === timeUnits.day ||
unitRange === timeUnits.week)) {
t = time.makeTime(year, month, dayOfMonth +
i * count * (unitRange === timeUnits.day ? 1 : 7));
}
else if (variableDayLength &&
unitRange === timeUnits.hour &&
count > 1) {
// Make sure higher ranks are preserved across DST (#6797,
// #7621)
t = time.makeTime(year, month, dayOfMonth, hours + i * count);
// Else, the interval is fixed and we use simple addition
}
else {
t += unitRange * count;
}
i++;
}
// Push the last time
tickPositions.push(t);
// Handle higher ranks. Mark new days if the time is on midnight
// (#950, #1649, #1760, #3349). Use a reasonable dropout threshold
// to prevent looping over dense data grouping (#6156).
if (unitRange <= timeUnits.hour && tickPositions.length < 10000) {
tickPositions.forEach((t) => {
if (
// Speed optimization, no need to run dateFormat unless
// we're on a full or half hour
t % 1800000 === 0 &&
// Check for local or global midnight
time.dateFormat('%H%M%S%L', t) === '000000000') {
higherRanks[t] = 'day';
}
});
}
}
// Record information on the chosen unit - for dynamic label formatter
tickPositions.info = extend(normalizedInterval, {
higherRanks,
totalRange: unitRange * count
});
return tickPositions;
}
}
/* *
*
* Default export
*
* */
export default Time;