Time.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. var zrUtil = require("zrender/lib/core/util");
  2. var numberUtil = require("../util/number");
  3. var formatUtil = require("../util/format");
  4. var scaleHelper = require("./helper");
  5. var IntervalScale = require("./Interval");
  6. // [About UTC and local time zone]:
  7. // In most cases, `number.parseDate` will treat input data string as local time
  8. // (except time zone is specified in time string). And `format.formateTime` returns
  9. // local time by default. option.useUTC is false by default. This design have
  10. // concidered these common case:
  11. // (1) Time that is persistent in server is in UTC, but it is needed to be diplayed
  12. // in local time by default.
  13. // (2) By default, the input data string (e.g., '2011-01-02') should be displayed
  14. // as its original time, without any time difference.
  15. var intervalScaleProto = IntervalScale.prototype;
  16. var mathCeil = Math.ceil;
  17. var mathFloor = Math.floor;
  18. var ONE_SECOND = 1000;
  19. var ONE_MINUTE = ONE_SECOND * 60;
  20. var ONE_HOUR = ONE_MINUTE * 60;
  21. var ONE_DAY = ONE_HOUR * 24; // FIXME 公用?
  22. var bisect = function (a, x, lo, hi) {
  23. while (lo < hi) {
  24. var mid = lo + hi >>> 1;
  25. if (a[mid][1] < x) {
  26. lo = mid + 1;
  27. } else {
  28. hi = mid;
  29. }
  30. }
  31. return lo;
  32. };
  33. /**
  34. * @alias module:echarts/coord/scale/Time
  35. * @constructor
  36. */
  37. var TimeScale = IntervalScale.extend({
  38. type: 'time',
  39. /**
  40. * @override
  41. */
  42. getLabel: function (val) {
  43. var stepLvl = this._stepLvl;
  44. var date = new Date(val);
  45. return formatUtil.formatTime(stepLvl[0], date, this.getSetting('useUTC'));
  46. },
  47. /**
  48. * @override
  49. */
  50. niceExtent: function (opt) {
  51. var extent = this._extent; // If extent start and end are same, expand them
  52. if (extent[0] === extent[1]) {
  53. // Expand extent
  54. extent[0] -= ONE_DAY;
  55. extent[1] += ONE_DAY;
  56. } // If there are no data and extent are [Infinity, -Infinity]
  57. if (extent[1] === -Infinity && extent[0] === Infinity) {
  58. var d = new Date();
  59. extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());
  60. extent[0] = extent[1] - ONE_DAY;
  61. }
  62. this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // var extent = this._extent;
  63. var interval = this._interval;
  64. if (!opt.fixMin) {
  65. extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
  66. }
  67. if (!opt.fixMax) {
  68. extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
  69. }
  70. },
  71. /**
  72. * @override
  73. */
  74. niceTicks: function (approxTickNum, minInterval, maxInterval) {
  75. approxTickNum = approxTickNum || 10;
  76. var extent = this._extent;
  77. var span = extent[1] - extent[0];
  78. var approxInterval = span / approxTickNum;
  79. if (minInterval != null && approxInterval < minInterval) {
  80. approxInterval = minInterval;
  81. }
  82. if (maxInterval != null && approxInterval > maxInterval) {
  83. approxInterval = maxInterval;
  84. }
  85. var scaleLevelsLen = scaleLevels.length;
  86. var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);
  87. var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];
  88. var interval = level[1]; // Same with interval scale if span is much larger than 1 year
  89. if (level[0] === 'year') {
  90. var yearSpan = span / interval; // From "Nice Numbers for Graph Labels" of Graphic Gems
  91. // var niceYearSpan = numberUtil.nice(yearSpan, false);
  92. var yearStep = numberUtil.nice(yearSpan / approxTickNum, true);
  93. interval *= yearStep;
  94. }
  95. var timezoneOffset = this.getSetting('useUTC') ? 0 : new Date(+extent[0] || +extent[1]).getTimezoneOffset() * 60 * 1000;
  96. var niceExtent = [Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset), Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)];
  97. scaleHelper.fixExtent(niceExtent, extent);
  98. this._stepLvl = level; // Interval will be used in getTicks
  99. this._interval = interval;
  100. this._niceExtent = niceExtent;
  101. },
  102. parse: function (val) {
  103. // val might be float.
  104. return +numberUtil.parseDate(val);
  105. }
  106. });
  107. zrUtil.each(['contain', 'normalize'], function (methodName) {
  108. TimeScale.prototype[methodName] = function (val) {
  109. return intervalScaleProto[methodName].call(this, this.parse(val));
  110. };
  111. }); // Steps from d3
  112. var scaleLevels = [// Format interval
  113. ['hh:mm:ss', ONE_SECOND], // 1s
  114. ['hh:mm:ss', ONE_SECOND * 5], // 5s
  115. ['hh:mm:ss', ONE_SECOND * 10], // 10s
  116. ['hh:mm:ss', ONE_SECOND * 15], // 15s
  117. ['hh:mm:ss', ONE_SECOND * 30], // 30s
  118. ['hh:mm\nMM-dd', ONE_MINUTE], // 1m
  119. ['hh:mm\nMM-dd', ONE_MINUTE * 5], // 5m
  120. ['hh:mm\nMM-dd', ONE_MINUTE * 10], // 10m
  121. ['hh:mm\nMM-dd', ONE_MINUTE * 15], // 15m
  122. ['hh:mm\nMM-dd', ONE_MINUTE * 30], // 30m
  123. ['hh:mm\nMM-dd', ONE_HOUR], // 1h
  124. ['hh:mm\nMM-dd', ONE_HOUR * 2], // 2h
  125. ['hh:mm\nMM-dd', ONE_HOUR * 6], // 6h
  126. ['hh:mm\nMM-dd', ONE_HOUR * 12], // 12h
  127. ['MM-dd\nyyyy', ONE_DAY], // 1d
  128. ['MM-dd\nyyyy', ONE_DAY * 2], // 2d
  129. ['MM-dd\nyyyy', ONE_DAY * 3], // 3d
  130. ['MM-dd\nyyyy', ONE_DAY * 4], // 4d
  131. ['MM-dd\nyyyy', ONE_DAY * 5], // 5d
  132. ['MM-dd\nyyyy', ONE_DAY * 6], // 6d
  133. ['week', ONE_DAY * 7], // 7d
  134. ['MM-dd\nyyyy', ONE_DAY * 10], // 10d
  135. ['week', ONE_DAY * 14], // 2w
  136. ['week', ONE_DAY * 21], // 3w
  137. ['month', ONE_DAY * 31], // 1M
  138. ['week', ONE_DAY * 42], // 6w
  139. ['month', ONE_DAY * 62], // 2M
  140. ['week', ONE_DAY * 42], // 10w
  141. ['quarter', ONE_DAY * 380 / 4], // 3M
  142. ['month', ONE_DAY * 31 * 4], // 4M
  143. ['month', ONE_DAY * 31 * 5], // 5M
  144. ['half-year', ONE_DAY * 380 / 2], // 6M
  145. ['month', ONE_DAY * 31 * 8], // 8M
  146. ['month', ONE_DAY * 31 * 10], // 10M
  147. ['year', ONE_DAY * 380] // 1Y
  148. ];
  149. /**
  150. * @param {module:echarts/model/Model}
  151. * @return {module:echarts/scale/Time}
  152. */
  153. TimeScale.create = function (model) {
  154. return new TimeScale({
  155. useUTC: model.ecModel.get('useUTC')
  156. });
  157. };
  158. var _default = TimeScale;
  159. module.exports = _default;