|   | 
| /* | 
| * 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. | 
| */ | 
|   | 
|   | 
| /** | 
|  * AUTO-GENERATED FILE. DO NOT MODIFY. | 
|  */ | 
|   | 
| /* | 
| * 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 { __extends } from "tslib"; | 
| /* | 
| * A third-party license is embedded for some of the code in this file: | 
| * The "scaleLevels" was originally copied from "d3.js" with some | 
| * modifications made for this project. | 
| * (See more details in the comment on the definition of "scaleLevels" below.) | 
| * The use of the source code of this file is also subject to the terms | 
| * and consitions of the license of "d3.js" (BSD-3Clause, see | 
| * </licenses/LICENSE-d3>). | 
| */ | 
| // [About UTC and local time zone]: | 
| // In most cases, `number.parseDate` will treat input data string as local time | 
| // (except time zone is specified in time string). And `format.formateTime` returns | 
| // local time by default. option.useUTC is false by default. This design has | 
| // considered these common cases: | 
| // (1) Time that is persistent in server is in UTC, but it is needed to be displayed | 
| // in local time by default. | 
| // (2) By default, the input data string (e.g., '2011-01-02') should be displayed | 
| // as its original time, without any time difference. | 
| import * as numberUtil from '../util/number.js'; | 
| import { ONE_SECOND, ONE_MINUTE, ONE_HOUR, ONE_DAY, ONE_YEAR, format, leveledFormat, getUnitValue, timeUnits, fullLeveledFormatter, getPrimaryTimeUnit, isPrimaryTimeUnit, getDefaultFormatPrecisionOfInterval, fullYearGetterName, monthSetterName, fullYearSetterName, dateSetterName, hoursGetterName, hoursSetterName, minutesSetterName, secondsSetterName, millisecondsSetterName, monthGetterName, dateGetterName, minutesGetterName, secondsGetterName, millisecondsGetterName } from '../util/time.js'; | 
| import * as scaleHelper from './helper.js'; | 
| import IntervalScale from './Interval.js'; | 
| import Scale from './Scale.js'; | 
| import { warn } from '../util/log.js'; | 
| import { filter, isNumber, map } from 'zrender/lib/core/util.js'; | 
| // FIXME 公用? | 
| var bisect = function (a, x, lo, hi) { | 
|   while (lo < hi) { | 
|     var mid = lo + hi >>> 1; | 
|     if (a[mid][1] < x) { | 
|       lo = mid + 1; | 
|     } else { | 
|       hi = mid; | 
|     } | 
|   } | 
|   return lo; | 
| }; | 
| var TimeScale = /** @class */function (_super) { | 
|   __extends(TimeScale, _super); | 
|   function TimeScale(settings) { | 
|     var _this = _super.call(this, settings) || this; | 
|     _this.type = 'time'; | 
|     return _this; | 
|   } | 
|   /** | 
|    * Get label is mainly for other components like dataZoom, tooltip. | 
|    */ | 
|   TimeScale.prototype.getLabel = function (tick) { | 
|     var useUTC = this.getSetting('useUTC'); | 
|     return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale')); | 
|   }; | 
|   TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) { | 
|     var isUTC = this.getSetting('useUTC'); | 
|     var lang = this.getSetting('locale'); | 
|     return leveledFormat(tick, idx, labelFormatter, lang, isUTC); | 
|   }; | 
|   /** | 
|    * @override | 
|    */ | 
|   TimeScale.prototype.getTicks = function () { | 
|     var interval = this._interval; | 
|     var extent = this._extent; | 
|     var ticks = []; | 
|     // If interval is 0, return []; | 
|     if (!interval) { | 
|       return ticks; | 
|     } | 
|     ticks.push({ | 
|       value: extent[0], | 
|       level: 0 | 
|     }); | 
|     var useUTC = this.getSetting('useUTC'); | 
|     var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent); | 
|     ticks = ticks.concat(innerTicks); | 
|     ticks.push({ | 
|       value: extent[1], | 
|       level: 0 | 
|     }); | 
|     return ticks; | 
|   }; | 
|   TimeScale.prototype.calcNiceExtent = function (opt) { | 
|     var extent = this._extent; | 
|     // If extent start and end are same, expand them | 
|     if (extent[0] === extent[1]) { | 
|       // Expand extent | 
|       extent[0] -= ONE_DAY; | 
|       extent[1] += ONE_DAY; | 
|     } | 
|     // If there are no data and extent are [Infinity, -Infinity] | 
|     if (extent[1] === -Infinity && extent[0] === Infinity) { | 
|       var d = new Date(); | 
|       extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate()); | 
|       extent[0] = extent[1] - ONE_DAY; | 
|     } | 
|     this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); | 
|   }; | 
|   TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) { | 
|     approxTickNum = approxTickNum || 10; | 
|     var extent = this._extent; | 
|     var span = extent[1] - extent[0]; | 
|     this._approxInterval = span / approxTickNum; | 
|     if (minInterval != null && this._approxInterval < minInterval) { | 
|       this._approxInterval = minInterval; | 
|     } | 
|     if (maxInterval != null && this._approxInterval > maxInterval) { | 
|       this._approxInterval = maxInterval; | 
|     } | 
|     var scaleIntervalsLen = scaleIntervals.length; | 
|     var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1); | 
|     // Interval that can be used to calculate ticks | 
|     this._interval = scaleIntervals[idx][1]; | 
|     // Min level used when picking ticks from top down. | 
|     // We check one more level to avoid the ticks are to sparse in some case. | 
|     this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0]; | 
|   }; | 
|   TimeScale.prototype.parse = function (val) { | 
|     // val might be float. | 
|     return isNumber(val) ? val : +numberUtil.parseDate(val); | 
|   }; | 
|   TimeScale.prototype.contain = function (val) { | 
|     return scaleHelper.contain(this.parse(val), this._extent); | 
|   }; | 
|   TimeScale.prototype.normalize = function (val) { | 
|     return scaleHelper.normalize(this.parse(val), this._extent); | 
|   }; | 
|   TimeScale.prototype.scale = function (val) { | 
|     return scaleHelper.scale(val, this._extent); | 
|   }; | 
|   TimeScale.type = 'time'; | 
|   return TimeScale; | 
| }(IntervalScale); | 
| /** | 
|  * This implementation was originally copied from "d3.js" | 
|  * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js> | 
|  * with some modifications made for this program. | 
|  * See the license statement at the head of this file. | 
|  */ | 
| var scaleIntervals = [ | 
| // Format                           interval | 
| ['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y | 
| ]; | 
| function isUnitValueSame(unit, valueA, valueB, isUTC) { | 
|   var dateA = numberUtil.parseDate(valueA); | 
|   var dateB = numberUtil.parseDate(valueB); | 
|   var isSame = function (unit) { | 
|     return getUnitValue(dateA, unit, isUTC) === getUnitValue(dateB, unit, isUTC); | 
|   }; | 
|   var isSameYear = function () { | 
|     return isSame('year'); | 
|   }; | 
|   // const isSameHalfYear = () => isSameYear() && isSame('half-year'); | 
|   // const isSameQuater = () => isSameYear() && isSame('quarter'); | 
|   var isSameMonth = function () { | 
|     return isSameYear() && isSame('month'); | 
|   }; | 
|   var isSameDay = function () { | 
|     return isSameMonth() && isSame('day'); | 
|   }; | 
|   // const isSameHalfDay = () => isSameDay() && isSame('half-day'); | 
|   var isSameHour = function () { | 
|     return isSameDay() && isSame('hour'); | 
|   }; | 
|   var isSameMinute = function () { | 
|     return isSameHour() && isSame('minute'); | 
|   }; | 
|   var isSameSecond = function () { | 
|     return isSameMinute() && isSame('second'); | 
|   }; | 
|   var isSameMilliSecond = function () { | 
|     return isSameSecond() && isSame('millisecond'); | 
|   }; | 
|   switch (unit) { | 
|     case 'year': | 
|       return isSameYear(); | 
|     case 'month': | 
|       return isSameMonth(); | 
|     case 'day': | 
|       return isSameDay(); | 
|     case 'hour': | 
|       return isSameHour(); | 
|     case 'minute': | 
|       return isSameMinute(); | 
|     case 'second': | 
|       return isSameSecond(); | 
|     case 'millisecond': | 
|       return isSameMilliSecond(); | 
|   } | 
| } | 
| // const primaryUnitGetters = { | 
| //     year: fullYearGetterName(), | 
| //     month: monthGetterName(), | 
| //     day: dateGetterName(), | 
| //     hour: hoursGetterName(), | 
| //     minute: minutesGetterName(), | 
| //     second: secondsGetterName(), | 
| //     millisecond: millisecondsGetterName() | 
| // }; | 
| // const primaryUnitUTCGetters = { | 
| //     year: fullYearGetterName(true), | 
| //     month: monthGetterName(true), | 
| //     day: dateGetterName(true), | 
| //     hour: hoursGetterName(true), | 
| //     minute: minutesGetterName(true), | 
| //     second: secondsGetterName(true), | 
| //     millisecond: millisecondsGetterName(true) | 
| // }; | 
| // function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) { | 
| //     step = step || 1; | 
| //     switch (getPrimaryTimeUnit(unitName)) { | 
| //         case 'year': | 
| //             date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'month': | 
| //             date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'day': | 
| //             date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'hour': | 
| //             date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'minute': | 
| //             date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'second': | 
| //             date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step); | 
| //             break; | 
| //         case 'millisecond': | 
| //             date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step); | 
| //             break; | 
| //     } | 
| //     return date.getTime(); | 
| // } | 
| // const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]]; | 
| // const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]]; | 
| // const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]]; | 
| function getDateInterval(approxInterval, daysInMonth) { | 
|   approxInterval /= ONE_DAY; | 
|   return approxInterval > 16 ? 16 | 
|   // Math.floor(daysInMonth / 2) + 1  // In this case we only want one tick between two months. | 
|   : approxInterval > 7.5 ? 7 // TODO week 7 or day 8? | 
|   : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1; | 
| } | 
| function getMonthInterval(approxInterval) { | 
|   var APPROX_ONE_MONTH = 30 * ONE_DAY; | 
|   approxInterval /= APPROX_ONE_MONTH; | 
|   return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1; | 
| } | 
| function getHourInterval(approxInterval) { | 
|   approxInterval /= ONE_HOUR; | 
|   return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1; | 
| } | 
| function getMinutesAndSecondsInterval(approxInterval, isMinutes) { | 
|   approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND; | 
|   return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1; | 
| } | 
| function getMillisecondsInterval(approxInterval) { | 
|   return numberUtil.nice(approxInterval, true); | 
| } | 
| function getFirstTimestampOfUnit(date, unitName, isUTC) { | 
|   var outDate = new Date(date); | 
|   switch (getPrimaryTimeUnit(unitName)) { | 
|     case 'year': | 
|     case 'month': | 
|       outDate[monthSetterName(isUTC)](0); | 
|     case 'day': | 
|       outDate[dateSetterName(isUTC)](1); | 
|     case 'hour': | 
|       outDate[hoursSetterName(isUTC)](0); | 
|     case 'minute': | 
|       outDate[minutesSetterName(isUTC)](0); | 
|     case 'second': | 
|       outDate[secondsSetterName(isUTC)](0); | 
|       outDate[millisecondsSetterName(isUTC)](0); | 
|   } | 
|   return outDate.getTime(); | 
| } | 
| function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent) { | 
|   var safeLimit = 10000; | 
|   var unitNames = timeUnits; | 
|   var iter = 0; | 
|   function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) { | 
|     var date = new Date(minTimestamp); | 
|     var dateTime = minTimestamp; | 
|     var d = date[getMethodName](); | 
|     // if (isDate) { | 
|     //     d -= 1; // Starts with 0;   PENDING | 
|     // } | 
|     while (dateTime < maxTimestamp && dateTime <= extent[1]) { | 
|       out.push({ | 
|         value: dateTime | 
|       }); | 
|       d += interval; | 
|       date[setMethodName](d); | 
|       dateTime = date.getTime(); | 
|     } | 
|     // This extra tick is for calcuating ticks of next level. Will not been added to the final result | 
|     out.push({ | 
|       value: dateTime, | 
|       notAdd: true | 
|     }); | 
|   } | 
|   function addLevelTicks(unitName, lastLevelTicks, levelTicks) { | 
|     var newAddedTicks = []; | 
|     var isFirstLevel = !lastLevelTicks.length; | 
|     if (isUnitValueSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) { | 
|       return; | 
|     } | 
|     if (isFirstLevel) { | 
|       lastLevelTicks = [{ | 
|         // TODO Optimize. Not include so may ticks. | 
|         value: getFirstTimestampOfUnit(new Date(extent[0]), unitName, isUTC) | 
|       }, { | 
|         value: extent[1] | 
|       }]; | 
|     } | 
|     for (var i = 0; i < lastLevelTicks.length - 1; i++) { | 
|       var startTick = lastLevelTicks[i].value; | 
|       var endTick = lastLevelTicks[i + 1].value; | 
|       if (startTick === endTick) { | 
|         continue; | 
|       } | 
|       var interval = void 0; | 
|       var getterName = void 0; | 
|       var setterName = void 0; | 
|       var isDate = false; | 
|       switch (unitName) { | 
|         case 'year': | 
|           interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365)); | 
|           getterName = fullYearGetterName(isUTC); | 
|           setterName = fullYearSetterName(isUTC); | 
|           break; | 
|         case 'half-year': | 
|         case 'quarter': | 
|         case 'month': | 
|           interval = getMonthInterval(approxInterval); | 
|           getterName = monthGetterName(isUTC); | 
|           setterName = monthSetterName(isUTC); | 
|           break; | 
|         case 'week': // PENDING If week is added. Ignore day. | 
|         case 'half-week': | 
|         case 'day': | 
|           interval = getDateInterval(approxInterval, 31); // Use 32 days and let interval been 16 | 
|           getterName = dateGetterName(isUTC); | 
|           setterName = dateSetterName(isUTC); | 
|           isDate = true; | 
|           break; | 
|         case 'half-day': | 
|         case 'quarter-day': | 
|         case 'hour': | 
|           interval = getHourInterval(approxInterval); | 
|           getterName = hoursGetterName(isUTC); | 
|           setterName = hoursSetterName(isUTC); | 
|           break; | 
|         case 'minute': | 
|           interval = getMinutesAndSecondsInterval(approxInterval, true); | 
|           getterName = minutesGetterName(isUTC); | 
|           setterName = minutesSetterName(isUTC); | 
|           break; | 
|         case 'second': | 
|           interval = getMinutesAndSecondsInterval(approxInterval, false); | 
|           getterName = secondsGetterName(isUTC); | 
|           setterName = secondsSetterName(isUTC); | 
|           break; | 
|         case 'millisecond': | 
|           interval = getMillisecondsInterval(approxInterval); | 
|           getterName = millisecondsGetterName(isUTC); | 
|           setterName = millisecondsSetterName(isUTC); | 
|           break; | 
|       } | 
|       addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks); | 
|       if (unitName === 'year' && levelTicks.length > 1 && i === 0) { | 
|         // Add nearest years to the left extent. | 
|         levelTicks.unshift({ | 
|           value: levelTicks[0].value - interval | 
|         }); | 
|       } | 
|     } | 
|     for (var i = 0; i < newAddedTicks.length; i++) { | 
|       levelTicks.push(newAddedTicks[i]); | 
|     } | 
|     // newAddedTicks.length && console.log(unitName, newAddedTicks); | 
|     return newAddedTicks; | 
|   } | 
|   var levelsTicks = []; | 
|   var currentLevelTicks = []; | 
|   var tickCount = 0; | 
|   var lastLevelTickCount = 0; | 
|   for (var i = 0; i < unitNames.length && iter++ < safeLimit; ++i) { | 
|     var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]); | 
|     if (!isPrimaryTimeUnit(unitNames[i])) { | 
|       // TODO | 
|       continue; | 
|     } | 
|     addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks); | 
|     var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null; | 
|     if (primaryTimeUnit !== nextPrimaryTimeUnit) { | 
|       if (currentLevelTicks.length) { | 
|         lastLevelTickCount = tickCount; | 
|         // Remove the duplicate so the tick count can be precisely. | 
|         currentLevelTicks.sort(function (a, b) { | 
|           return a.value - b.value; | 
|         }); | 
|         var levelTicksRemoveDuplicated = []; | 
|         for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) { | 
|           var tickValue = currentLevelTicks[i_1].value; | 
|           if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) { | 
|             levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]); | 
|             if (tickValue >= extent[0] && tickValue <= extent[1]) { | 
|               tickCount++; | 
|             } | 
|           } | 
|         } | 
|         var targetTickNum = (extent[1] - extent[0]) / approxInterval; | 
|         // Added too much in this level and not too less in last level | 
|         if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) { | 
|           break; | 
|         } | 
|         // Only treat primary time unit as one level. | 
|         levelsTicks.push(levelTicksRemoveDuplicated); | 
|         if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) { | 
|           break; | 
|         } | 
|       } | 
|       // Reset if next unitName is primary | 
|       currentLevelTicks = []; | 
|     } | 
|   } | 
|   if (process.env.NODE_ENV !== 'production') { | 
|     if (iter >= safeLimit) { | 
|       warn('Exceed safe limit.'); | 
|     } | 
|   } | 
|   var levelsTicksInExtent = filter(map(levelsTicks, function (levelTicks) { | 
|     return filter(levelTicks, function (tick) { | 
|       return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd; | 
|     }); | 
|   }), function (levelTicks) { | 
|     return levelTicks.length > 0; | 
|   }); | 
|   var ticks = []; | 
|   var maxLevel = levelsTicksInExtent.length - 1; | 
|   for (var i = 0; i < levelsTicksInExtent.length; ++i) { | 
|     var levelTicks = levelsTicksInExtent[i]; | 
|     for (var k = 0; k < levelTicks.length; ++k) { | 
|       ticks.push({ | 
|         value: levelTicks[k].value, | 
|         level: maxLevel - i | 
|       }); | 
|     } | 
|   } | 
|   ticks.sort(function (a, b) { | 
|     return a.value - b.value; | 
|   }); | 
|   // Remove duplicates | 
|   var result = []; | 
|   for (var i = 0; i < ticks.length; ++i) { | 
|     if (i === 0 || ticks[i].value !== ticks[i - 1].value) { | 
|       result.push(ticks[i]); | 
|     } | 
|   } | 
|   return result; | 
| } | 
| Scale.registerClass(TimeScale); | 
| export default TimeScale; |