apexcharts
Version:
A JavaScript Chart Library
1,038 lines (920 loc) • 28.2 kB
JavaScript
// @ts-check
import DateTime from '../utils/DateTime'
import Dimensions from './dimensions/Dimensions'
import Graphics from './Graphics'
import Utils from '../utils/Utils'
const MINUTES_IN_DAY = 24 * 60
const SECONDS_IN_DAY = MINUTES_IN_DAY * 60
const MIN_ZOOM_DAYS = 10 / SECONDS_IN_DAY
/**
* ApexCharts TimeScale Class for generating time ticks for x-axis.
*
* @module TimeScale
**/
class TimeScale {
/**
* @param {import('../types/internal').ChartStateW} w
* @param {import('../types/internal').ChartContext} ctx
*/
constructor(w, ctx) {
this.w = w
this.ctx = ctx // needed: new Dimensions(this.ctx)
/** @type {any} */
this.timeScaleArray = []
this.utc = this.w.config.xaxis.labels.datetimeUTC
}
/**
* @param {number} minX
* @param {number} maxX
*/
calculateTimeScaleTicks(minX, maxX) {
const w = this.w
// null check when no series to show
if (w.globals.allSeriesCollapsed) {
w.labelData.labels = []
w.labelData.timescaleLabels = []
return []
}
const dt = new DateTime(this.w)
const daysDiff = (maxX - minX) / (1000 * SECONDS_IN_DAY)
this.determineInterval(daysDiff)
w.interact.disableZoomIn = false
w.interact.disableZoomOut = false
if (daysDiff < MIN_ZOOM_DAYS) {
w.interact.disableZoomIn = true
} else if (daysDiff > 50000) {
w.interact.disableZoomOut = true
}
const timeIntervals = dt.getTimeUnitsfromTimestamp(minX, maxX)
const daysWidthOnXAxis = w.layout.gridWidth / daysDiff
const hoursWidthOnXAxis = daysWidthOnXAxis / 24
const minutesWidthOnXAxis = hoursWidthOnXAxis / 60
const secondsWidthOnXAxis = minutesWidthOnXAxis / 60
const numberOfHours = Math.floor(daysDiff * 24)
const numberOfMinutes = Math.floor(daysDiff * MINUTES_IN_DAY)
const numberOfSeconds = Math.floor(daysDiff * SECONDS_IN_DAY)
const numberOfDays = Math.floor(daysDiff)
const numberOfMonths = Math.floor(daysDiff / 30)
const numberOfYears = Math.floor(daysDiff / 365)
const firstVal = {
minMillisecond: timeIntervals.minMillisecond,
minSecond: timeIntervals.minSecond,
minMinute: timeIntervals.minMinute,
minHour: timeIntervals.minHour,
minDate: timeIntervals.minDate,
minMonth: timeIntervals.minMonth,
minYear: timeIntervals.minYear,
}
const currentMillisecond = firstVal.minMillisecond
const currentSecond = firstVal.minSecond
const currentMinute = firstVal.minMinute
const currentHour = firstVal.minHour
const currentMonthDate = firstVal.minDate
const currentDate = firstVal.minDate
const currentMonth = firstVal.minMonth
const currentYear = firstVal.minYear
const params = {
firstVal,
currentMillisecond,
currentSecond,
currentMinute,
currentHour,
currentMonthDate,
currentDate,
currentMonth,
currentYear,
daysWidthOnXAxis,
hoursWidthOnXAxis,
minutesWidthOnXAxis,
secondsWidthOnXAxis,
numberOfSeconds,
numberOfMinutes,
numberOfHours,
numberOfDays,
numberOfMonths,
numberOfYears,
}
switch (this.tickInterval) {
case 'years': {
this.generateYearScale(params)
break
}
case 'months':
case 'half_year': {
this.generateMonthScale(params)
break
}
case 'months_days':
case 'months_fortnight':
case 'days':
case 'week_days': {
this.generateDayScale(params)
break
}
case 'hours': {
this.generateHourScale(params)
break
}
case 'minutes_fives':
case 'minutes':
this.generateMinuteScale(params)
break
case 'seconds_tens':
case 'seconds_fives':
case 'seconds':
this.generateSecondScale(params)
break
}
// first, we will adjust the month values index
// as in the upper function, it is starting from 0
// we will start them from 1
const adjustedMonthInTimeScaleArray = this.timeScaleArray.map(
(/** @type {any} */ ts) => {
const defaultReturn = {
position: ts.position,
unit: ts.unit,
year: ts.year,
day: ts.day ? ts.day : 1,
hour: ts.hour ? ts.hour : 0,
month: ts.month + 1,
}
if (ts.unit === 'month') {
return {
...defaultReturn,
day: 1,
value: ts.value + 1,
}
} else if (ts.unit === 'day' || ts.unit === 'hour') {
return {
...defaultReturn,
value: ts.value,
}
} else if (ts.unit === 'minute') {
return {
...defaultReturn,
value: ts.value,
minute: ts.value,
}
} else if (ts.unit === 'second') {
return {
...defaultReturn,
value: ts.value,
minute: ts.minute,
second: ts.second,
}
}
return ts
},
)
const filteredTimeScale = adjustedMonthInTimeScaleArray.filter(
(/** @type {any} */ ts) => {
let modulo = 1
let ticks = Math.ceil(w.layout.gridWidth / 120)
const value = ts.value
if (w.config.xaxis.tickAmount !== undefined) {
ticks = w.config.xaxis.tickAmount
}
if (adjustedMonthInTimeScaleArray.length > ticks) {
modulo = Math.floor(adjustedMonthInTimeScaleArray.length / ticks)
}
let shouldNotSkipUnit = false // there is a big change in unit i.e days to months
let shouldNotPrint = false // should skip these values
switch (this.tickInterval) {
case 'years':
// make years label denser
if (ts.unit === 'year') {
shouldNotSkipUnit = true
}
break
case 'half_year':
modulo = 7
if (ts.unit === 'year') {
shouldNotSkipUnit = true
}
break
case 'months':
modulo = 1
if (ts.unit === 'year') {
shouldNotSkipUnit = true
}
break
case 'months_fortnight':
modulo = 15
if (ts.unit === 'year' || ts.unit === 'month') {
shouldNotSkipUnit = true
}
if (value === 30) {
shouldNotPrint = true
}
break
case 'months_days':
modulo = 10
if (ts.unit === 'month') {
shouldNotSkipUnit = true
}
if (value === 30) {
shouldNotPrint = true
}
break
case 'week_days':
modulo = 8
if (ts.unit === 'month') {
shouldNotSkipUnit = true
}
break
case 'days':
modulo = 1
if (ts.unit === 'month') {
shouldNotSkipUnit = true
}
break
case 'hours':
if (ts.unit === 'day') {
shouldNotSkipUnit = true
}
break
case 'minutes_fives':
if (value % 5 !== 0) {
shouldNotPrint = true
}
break
case 'seconds_tens':
if (value % 10 !== 0) {
shouldNotPrint = true
}
break
case 'seconds_fives':
if (value % 5 !== 0) {
shouldNotPrint = true
}
break
}
if (
this.tickInterval === 'hours' ||
this.tickInterval === 'minutes_fives' ||
this.tickInterval === 'seconds_tens' ||
this.tickInterval === 'seconds_fives'
) {
if (!shouldNotPrint) {
return true
}
} else {
if ((value % modulo === 0 || shouldNotSkipUnit) && !shouldNotPrint) {
return true
}
}
},
)
return filteredTimeScale
}
/**
* @param {Array<Record<string, any>>} filteredTimeScale
*/
recalcDimensionsBasedOnFormat(filteredTimeScale) {
const w = this.w
const reformattedTimescaleArray = this.formatDates(filteredTimeScale)
const removedOverlappingTS = this.removeOverlappingTS(
reformattedTimescaleArray,
)
w.labelData.timescaleLabels = removedOverlappingTS.slice()
// at this stage, we need to re-calculate coords of the grid as timeline labels may have altered the xaxis labels coords
// The reason we can't do this prior to this stage is because timeline labels depends on gridWidth, and as the ticks are calculated based on available gridWidth, there can be unknown number of ticks generated for different minX and maxX
// Dependency on Dimensions(), need to refactor correctly
// TODO - find an alternate way to avoid calling this Heavy method twice
const dimensions = new Dimensions(this.w, this.ctx)
// Phase 1: return value captured; writer stub is a no-op.
const layoutState = dimensions.plotCoords()
this.ctx._writeLayoutCoords(layoutState.layout)
}
/**
* @param {number} daysDiff
*/
determineInterval(daysDiff) {
const yearsDiff = daysDiff / 365
const hoursDiff = daysDiff * 24
const minutesDiff = hoursDiff * 60
const secondsDiff = minutesDiff * 60
switch (true) {
case yearsDiff > 5:
this.tickInterval = 'years'
break
case daysDiff > 800:
this.tickInterval = 'half_year'
break
case daysDiff > 180:
this.tickInterval = 'months'
break
case daysDiff > 90:
this.tickInterval = 'months_fortnight'
break
case daysDiff > 60:
this.tickInterval = 'months_days'
break
case daysDiff > 30:
this.tickInterval = 'week_days'
break
case daysDiff > 2:
this.tickInterval = 'days'
break
case hoursDiff > 2.4:
this.tickInterval = 'hours'
break
case minutesDiff > 15:
this.tickInterval = 'minutes_fives'
break
case minutesDiff > 5:
this.tickInterval = 'minutes'
break
case minutesDiff > 1:
this.tickInterval = 'seconds_tens'
break
case secondsDiff > 20:
this.tickInterval = 'seconds_fives'
break
default:
this.tickInterval = 'seconds'
break
}
}
/** @param {{firstVal: any, currentMonth: any, currentYear: any, daysWidthOnXAxis: any, numberOfYears: any}} opts */
generateYearScale({
firstVal,
currentMonth,
currentYear,
daysWidthOnXAxis,
numberOfYears,
}) {
let firstTickValue = firstVal.minYear
let firstTickPosition = 0
const dt = new DateTime(this.w)
const unit = 'year'
if (firstVal.minDate > 1 || firstVal.minMonth > 0) {
const remainingDays = dt.determineRemainingDaysOfYear(
firstVal.minYear,
firstVal.minMonth,
firstVal.minDate,
)
// remainingDaysofFirstMonth is used to reacht the 2nd tick position
const remainingDaysOfFirstYear =
dt.determineDaysOfYear(firstVal.minYear) - remainingDays + 1
// calculate the first tick position
firstTickPosition = remainingDaysOfFirstYear * daysWidthOnXAxis
firstTickValue = firstVal.minYear + 1
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value: firstTickValue,
unit,
year: firstTickValue,
month: 1,
})
} else if (firstVal.minDate === 1 && firstVal.minMonth === 0) {
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value: firstTickValue,
unit,
year: currentYear,
month: Utils.monthMod(currentMonth + 1),
})
}
let year = firstTickValue
let pos = firstTickPosition
// keep drawing rest of the ticks
for (let i = 0; i < numberOfYears; i++) {
year++
pos = dt.determineDaysOfYear(year - 1) * daysWidthOnXAxis + pos
this.timeScaleArray.push({
position: pos,
value: year,
unit,
year,
month: 1,
})
}
}
/** @param {{firstVal: any, currentMonthDate: any, currentMonth: any, currentYear: any, daysWidthOnXAxis: any, numberOfMonths: any}} opts */
generateMonthScale({
firstVal,
currentMonthDate,
currentMonth,
currentYear,
daysWidthOnXAxis,
numberOfMonths,
}) {
let firstTickValue = currentMonth
let firstTickPosition = 0
const dt = new DateTime(this.w)
let unit = 'month'
let yrCounter = 0
if (firstVal.minDate > 1) {
// remainingDaysofFirstMonth is used to reacht the 2nd tick position
const remainingDaysOfFirstMonth =
dt.determineDaysOfMonths(currentMonth + 1, firstVal.minYear) -
currentMonthDate +
1
// calculate the first tick position
firstTickPosition = remainingDaysOfFirstMonth * daysWidthOnXAxis
firstTickValue = Utils.monthMod(currentMonth + 1)
let year = currentYear + yrCounter
let month = Utils.monthMod(firstTickValue)
let value = firstTickValue
// it's Jan, so update the year
if (firstTickValue === 0) {
unit = 'year'
value = year
month = 1
yrCounter += 1
year = year + yrCounter
}
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value,
unit,
year,
month,
})
} else {
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value: firstTickValue,
unit,
year: currentYear,
month: Utils.monthMod(currentMonth),
})
}
let month = firstTickValue + 1
let pos = firstTickPosition
// keep drawing rest of the ticks
for (let i = 0, j = 1; i < numberOfMonths; i++, j++) {
month = Utils.monthMod(month)
if (month === 0) {
unit = 'year'
yrCounter += 1
} else {
unit = 'month'
}
const year = this._getYear(currentYear, month, yrCounter)
pos = dt.determineDaysOfMonths(month, year) * daysWidthOnXAxis + pos
const monthVal = month === 0 ? year : month
this.timeScaleArray.push({
position: pos,
value: monthVal,
unit,
year,
month: month === 0 ? 1 : month,
})
month++
}
}
/** @param {{firstVal: any, currentMonth: any, currentYear: any, hoursWidthOnXAxis: any, numberOfDays: any}} opts */
generateDayScale({
firstVal,
currentMonth,
currentYear,
hoursWidthOnXAxis,
numberOfDays,
}) {
const dt = new DateTime(this.w)
let unit = 'day'
let firstTickValue = firstVal.minDate + 1
let date = firstTickValue
/**
* @param {number} dateVal
* @param {number} month
* @param {number} year
*/
const changeMonth = (dateVal, month, year) => {
const monthdays = dt.determineDaysOfMonths(month + 1, year)
if (dateVal > monthdays) {
month = month + 1
date = 1
unit = 'month'
val = month
return month
}
return month
}
const remainingHours = 24 - firstVal.minHour
const yrCounter = 0
// calculate the first tick position
let firstTickPosition = remainingHours * hoursWidthOnXAxis
let val = firstTickValue
let month = changeMonth(date, currentMonth, currentYear)
if (firstVal.minHour === 0 && firstVal.minDate === 1) {
// the first value is the first day of month
firstTickPosition = 0
val = Utils.monthMod(firstVal.minMonth)
unit = 'month'
date = firstVal.minDate
// numberOfDays++
// removed the above line to fix https://github.com/apexcharts/apexcharts.js/issues/305#issuecomment-1019520513
} else if (
firstVal.minDate !== 1 &&
firstVal.minHour === 0 &&
firstVal.minMinute === 0
) {
// fixes apexcharts/apexcharts.js/issues/1730
firstTickPosition = 0
firstTickValue = firstVal.minDate
date = firstTickValue
val = firstTickValue
// in case it's the last date of month, we need to check it
month = changeMonth(date, currentMonth, currentYear)
if (val !== 1) {
unit = 'day'
}
}
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value: val,
unit,
year: this._getYear(currentYear, month, yrCounter),
month: Utils.monthMod(month),
day: date,
})
let pos = firstTickPosition
// keep drawing rest of the ticks
for (let i = 0; i < numberOfDays; i++) {
date += 1
unit = 'day'
month = changeMonth(
date,
month,
this._getYear(currentYear, month, yrCounter),
)
const year = this._getYear(currentYear, month, yrCounter)
pos = 24 * hoursWidthOnXAxis + pos
const value = date === 1 ? Utils.monthMod(month) : date
this.timeScaleArray.push({
position: pos,
value,
unit,
year,
month: Utils.monthMod(month),
day: value,
})
}
}
/** @param {{firstVal: any, currentDate: any, currentMonth: any, currentYear: any, minutesWidthOnXAxis: any, numberOfHours: any}} opts */
generateHourScale({
firstVal,
currentDate,
currentMonth,
currentYear,
minutesWidthOnXAxis,
numberOfHours,
}) {
const dt = new DateTime(this.w)
const yrCounter = 0
let unit = 'hour'
/**
* @param {number} dateVal
* @param {number} month
*/
const changeDate = (dateVal, month) => {
const monthdays = dt.determineDaysOfMonths(month + 1, currentYear)
if (dateVal > monthdays) {
date = 1
month = month + 1
}
return { month, date }
}
/**
* @param {number} dateVal
* @param {number} month
*/
const changeMonth = (dateVal, month) => {
const monthdays = dt.determineDaysOfMonths(month + 1, currentYear)
if (dateVal > monthdays) {
month = month + 1
return month
}
return month
}
// factor in minSeconds as well
const remainingMins = 60 - (firstVal.minMinute + firstVal.minSecond / 60.0)
let firstTickPosition = remainingMins * minutesWidthOnXAxis
let firstTickValue = firstVal.minHour + 1
let hour = firstTickValue
if (remainingMins === 60) {
firstTickPosition = 0
firstTickValue = firstVal.minHour
hour = firstTickValue
}
let date = currentDate
// we need to apply date switching logic here as well, to avoid duplicated labels
if (hour >= 24) {
hour = 0
date += 1
unit = 'day'
// Unit changed to day , Value should align unit
firstTickValue = date
}
const checkNextMonth = changeDate(date, currentMonth)
let month = checkNextMonth.month
month = changeMonth(date, month)
// Sync firstTickValue with date after potential month rollover
// (changeDate may have reset date to 1 for months shorter than 31 days)
if (unit === 'day') {
firstTickValue = date
}
// push the first tick in the array
this.timeScaleArray.push({
position: firstTickPosition,
value: firstTickValue,
unit,
day: date,
hour,
year: currentYear,
month: Utils.monthMod(month),
})
hour++
let pos = firstTickPosition
// keep drawing rest of the ticks
for (let i = 0; i < numberOfHours; i++) {
unit = 'hour'
if (hour >= 24) {
hour = 0
date += 1
unit = 'day'
const checkNextMonth = changeDate(date, month)
month = checkNextMonth.month
month = changeMonth(date, month)
}
const year = this._getYear(currentYear, month, yrCounter)
pos = 60 * minutesWidthOnXAxis + pos
const val = hour === 0 ? date : hour
this.timeScaleArray.push({
position: pos,
value: val,
unit,
hour,
day: date,
year,
month: Utils.monthMod(month),
})
hour++
}
}
/** @param {{currentMillisecond: any, currentSecond: any, currentMinute: any, currentHour: any, currentDate: any, currentMonth: any, currentYear: any, minutesWidthOnXAxis: any, secondsWidthOnXAxis: any, numberOfMinutes: any}} opts */
generateMinuteScale({
currentMillisecond,
currentSecond,
currentMinute,
currentHour,
currentDate,
currentMonth,
currentYear,
minutesWidthOnXAxis,
secondsWidthOnXAxis,
numberOfMinutes,
}) {
const dt = new DateTime(this.w)
const yrCounter = 0
const unit = 'minute'
const remainingSecs = 60 - currentSecond
let firstTickPosition =
(remainingSecs - currentMillisecond / 1000) * secondsWidthOnXAxis
let minute = currentMinute + 1
if (currentSecond === 0 && currentMillisecond === 0) {
firstTickPosition = 0
minute = currentMinute
}
let date = currentDate
let month = currentMonth
const year = currentYear
let hour = currentHour
let pos = firstTickPosition
for (let i = 0; i < numberOfMinutes; i++) {
if (minute >= 60) {
minute = 0
hour += 1
if (hour === 24) {
hour = 0
date += 1
const monthDays = dt.determineDaysOfMonths(
month + 1,
this._getYear(year, month, yrCounter),
)
if (date > monthDays) {
date = 1
month += 1
}
}
}
this.timeScaleArray.push({
position: pos,
value: minute,
unit,
hour,
minute,
day: date,
year: this._getYear(year, month, yrCounter),
month: Utils.monthMod(month),
})
pos += minutesWidthOnXAxis
minute++
}
}
/** @param {{currentMillisecond: any, currentSecond: any, currentMinute: any, currentHour: any, currentDate: any, currentMonth: any, currentYear: any, secondsWidthOnXAxis: any, numberOfSeconds: any}} opts */
generateSecondScale({
currentMillisecond,
currentSecond,
currentMinute,
currentHour,
currentDate,
currentMonth,
currentYear,
secondsWidthOnXAxis,
numberOfSeconds,
}) {
const yrCounter = 0
const unit = 'second'
const remainingMillisecs = 1000 - currentMillisecond
let firstTickPosition = (remainingMillisecs / 1000) * secondsWidthOnXAxis
let second = currentSecond + 1
if (currentMillisecond === 0) {
firstTickPosition = 0
second = currentSecond
}
let minute = currentMinute
const date = currentDate
const month = currentMonth
const year = currentYear
let hour = currentHour
let pos = firstTickPosition
for (let i = 0; i < numberOfSeconds; i++) {
if (second >= 60) {
minute++
second = 0
if (minute >= 60) {
hour++
minute = 0
if (hour === 24) {
hour = 0
}
}
}
this.timeScaleArray.push({
position: pos,
value: second,
unit,
hour,
minute,
second,
day: date,
year: this._getYear(year, month, yrCounter),
month: Utils.monthMod(month),
})
pos += secondsWidthOnXAxis
second++
}
}
/**
* @param {Record<string, any>} ts
* @param {string | number} value
*/
createRawDateString(ts, value) {
let raw = ts.year
if (ts.month === 0) {
// invalid month, correct it
ts.month = 1
}
raw += '-' + ('0' + ts.month.toString()).slice(-2)
// unit is day
if (ts.unit === 'day') {
raw += '-' + ('0' + value).slice(-2)
} else {
raw += '-' + ('0' + (ts.day ? ts.day : '1')).slice(-2)
}
// unit is hour
if (ts.unit === 'hour') {
raw += 'T' + ('0' + value).slice(-2)
} else {
raw += 'T' + ('0' + (ts.hour ? ts.hour : '0')).slice(-2)
}
if (ts.unit === 'minute') {
raw += ':' + ('0' + value).slice(-2)
} else {
raw += ':' + (ts.minute ? ('0' + ts.minute).slice(-2) : '00')
}
if (ts.unit === 'second') {
raw += ':' + ('0' + value).slice(-2)
} else {
raw += ':00'
}
if (this.utc) {
raw += '.000Z'
}
return raw
}
/**
* @param {Array<Record<string, any>>} filteredTimeScale
*/
formatDates(filteredTimeScale) {
const w = this.w
/**
* @param {Record<string, any>} ts
*/
const reformattedTimescaleArray = filteredTimeScale.map(
(/** @type {any} */ ts) => {
let value = ts.value.toString()
const dt = new DateTime(this.w)
const raw = this.createRawDateString(ts, value)
let dateToFormat = dt.getDate(dt.parseDate(raw))
if (!this.utc) {
// Fixes #1726, #1544, #1485, #1255
dateToFormat = dt.getDate(dt.parseDateWithTimezone(raw))
}
if (w.config.xaxis.labels.format === undefined) {
let customFormat = 'dd MMM'
const dtFormatter = w.config.xaxis.labels.datetimeFormatter
if (ts.unit === 'year') customFormat = dtFormatter.year
if (ts.unit === 'month') customFormat = dtFormatter.month
if (ts.unit === 'day') customFormat = dtFormatter.day
if (ts.unit === 'hour') customFormat = dtFormatter.hour
if (ts.unit === 'minute') customFormat = dtFormatter.minute
if (ts.unit === 'second') customFormat = dtFormatter.second
value = dt.formatDate(dateToFormat, customFormat)
} else {
value = dt.formatDate(dateToFormat, w.config.xaxis.labels.format)
}
return {
dateString: raw,
position: ts.position,
value,
unit: ts.unit,
year: ts.year,
month: ts.month,
}
},
)
return reformattedTimescaleArray
}
/**
* @param {any[]} arr
*/
removeOverlappingTS(arr) {
const graphics = new Graphics(this.w)
let equalLabelLengthFlag = false // These labels got same length?
/** @type {number | undefined} */
let constantLabelWidth // If true, what is the constant length to use
if (
arr.length > 0 && // check arr length
arr[0].value && // check arr[0] contains value
/**
* @param {Record<string, any>} lb
*/
arr.every((lb) => lb.value.length === arr[0].value.length) // check every arr label value is the same as the first one
) {
equalLabelLengthFlag = true // These labels got same length
constantLabelWidth = graphics.getTextRects(
arr[0].value,
this.w.config.xaxis.labels.style.fontSize,
).width // The constant label width to use
}
let lastDrawnIndex = 0
/**
* @param {Record<string, any>} item
* @param {number} index
*/
let filteredArray = arr.map((item, index) => {
if (index > 0 && this.w.config.xaxis.labels.hideOverlappingLabels) {
const prevLabelWidth = !equalLabelLengthFlag // if vary in label length
? graphics.getTextRects(
/** @type {any} */ (arr[lastDrawnIndex]).value,
this.w.config.xaxis.labels.style.fontSize,
).width // get individual length
: constantLabelWidth // else: use constant length
const prevPos = arr[lastDrawnIndex].position
const pos = item.position
if (pos > prevPos + prevLabelWidth + 10) {
lastDrawnIndex = index
return item
} else {
return null
}
} else {
return item
}
})
/**
* @param {any} f
*/
filteredArray = filteredArray.filter((/** @type {any} */ f) => f !== null)
return filteredArray
}
/**
* @param {number} currentYear
* @param {number} month
* @param {number} yrCounter
*/
_getYear(currentYear, month, yrCounter) {
return currentYear + Math.floor(month / 12) + yrCounter
}
}
export default TimeScale