/* * 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. */ var zrUtil = require("zrender/lib/core/util"); var numberUtil = require("../util/number"); var formatUtil = require("../util/format"); var scaleHelper = require("./helper"); var IntervalScale = require("./Interval"); /* * 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. */ /* * A third-party license is embeded 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 * ). */ // [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 have // concidered these common case: // (1) Time that is persistent in server is in UTC, but it is needed to be diplayed // 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. var intervalScaleProto = IntervalScale.prototype; var mathCeil = Math.ceil; var mathFloor = Math.floor; var ONE_SECOND = 1000; var ONE_MINUTE = ONE_SECOND * 60; var ONE_HOUR = ONE_MINUTE * 60; var ONE_DAY = ONE_HOUR * 24; // 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; }; /** * @alias module:echarts/coord/scale/Time * @constructor */ var TimeScale = IntervalScale.extend({ type: 'time', /** * @override */ getLabel: function (val) { var stepLvl = this._stepLvl; var date = new Date(val); return formatUtil.formatTime(stepLvl[0], date, this.getSetting('useUTC')); }, /** * @override */ niceExtent: 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.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // var extent = this._extent; var interval = this._interval; if (!opt.fixMin) { extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval); } if (!opt.fixMax) { extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval); } }, /** * @override */ niceTicks: function (approxTickNum, minInterval, maxInterval) { approxTickNum = approxTickNum || 10; var extent = this._extent; var span = extent[1] - extent[0]; var approxInterval = span / approxTickNum; if (minInterval != null && approxInterval < minInterval) { approxInterval = minInterval; } if (maxInterval != null && approxInterval > maxInterval) { approxInterval = maxInterval; } var scaleLevelsLen = scaleLevels.length; var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen); var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)]; var interval = level[1]; // Same with interval scale if span is much larger than 1 year if (level[0] === 'year') { var yearSpan = span / interval; // From "Nice Numbers for Graph Labels" of Graphic Gems // var niceYearSpan = numberUtil.nice(yearSpan, false); var yearStep = numberUtil.nice(yearSpan / approxTickNum, true); interval *= yearStep; } var timezoneOffset = this.getSetting('useUTC') ? 0 : new Date(+extent[0] || +extent[1]).getTimezoneOffset() * 60 * 1000; var niceExtent = [Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset), Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)]; scaleHelper.fixExtent(niceExtent, extent); this._stepLvl = level; // Interval will be used in getTicks this._interval = interval; this._niceExtent = niceExtent; }, parse: function (val) { // val might be float. return +numberUtil.parseDate(val); } }); zrUtil.each(['contain', 'normalize'], function (methodName) { TimeScale.prototype[methodName] = function (val) { return intervalScaleProto[methodName].call(this, this.parse(val)); }; }); /** * This implementation was originally copied from "d3.js" * * with some modifications made for this program. * See the license statement at the head of this file. */ var scaleLevels = [// Format interval ['hh:mm:ss', ONE_SECOND], // 1s ['hh:mm:ss', ONE_SECOND * 5], // 5s ['hh:mm:ss', ONE_SECOND * 10], // 10s ['hh:mm:ss', ONE_SECOND * 15], // 15s ['hh:mm:ss', ONE_SECOND * 30], // 30s ['hh:mm\nMM-dd', ONE_MINUTE], // 1m ['hh:mm\nMM-dd', ONE_MINUTE * 5], // 5m ['hh:mm\nMM-dd', ONE_MINUTE * 10], // 10m ['hh:mm\nMM-dd', ONE_MINUTE * 15], // 15m ['hh:mm\nMM-dd', ONE_MINUTE * 30], // 30m ['hh:mm\nMM-dd', ONE_HOUR], // 1h ['hh:mm\nMM-dd', ONE_HOUR * 2], // 2h ['hh:mm\nMM-dd', ONE_HOUR * 6], // 6h ['hh:mm\nMM-dd', ONE_HOUR * 12], // 12h ['MM-dd\nyyyy', ONE_DAY], // 1d ['MM-dd\nyyyy', ONE_DAY * 2], // 2d ['MM-dd\nyyyy', ONE_DAY * 3], // 3d ['MM-dd\nyyyy', ONE_DAY * 4], // 4d ['MM-dd\nyyyy', ONE_DAY * 5], // 5d ['MM-dd\nyyyy', ONE_DAY * 6], // 6d ['week', ONE_DAY * 7], // 7d ['MM-dd\nyyyy', ONE_DAY * 10], // 10d ['week', ONE_DAY * 14], // 2w ['week', ONE_DAY * 21], // 3w ['month', ONE_DAY * 31], // 1M ['week', ONE_DAY * 42], // 6w ['month', ONE_DAY * 62], // 2M ['week', ONE_DAY * 70], // 10w ['quarter', ONE_DAY * 95], // 3M ['month', ONE_DAY * 31 * 4], // 4M ['month', ONE_DAY * 31 * 5], // 5M ['half-year', ONE_DAY * 380 / 2], // 6M ['month', ONE_DAY * 31 * 8], // 8M ['month', ONE_DAY * 31 * 10], // 10M ['year', ONE_DAY * 380] // 1Y ]; /** * @param {module:echarts/model/Model} * @return {module:echarts/scale/Time} */ TimeScale.create = function (model) { return new TimeScale({ useUTC: model.ecModel.get('useUTC') }); }; var _default = TimeScale; module.exports = _default;