123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /*
- * 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;
|