Interval.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { __extends } from "tslib";
  41. import * as numberUtil from '../util/number.js';
  42. import * as formatUtil from '../util/format.js';
  43. import Scale from './Scale.js';
  44. import * as helper from './helper.js';
  45. import { getScaleBreakHelper } from './break.js';
  46. var roundNumber = numberUtil.round;
  47. var IntervalScale = /** @class */function (_super) {
  48. __extends(IntervalScale, _super);
  49. function IntervalScale() {
  50. var _this = _super !== null && _super.apply(this, arguments) || this;
  51. _this.type = 'interval';
  52. // Step is calculated in adjustExtent.
  53. _this._interval = 0;
  54. _this._intervalPrecision = 2;
  55. return _this;
  56. }
  57. IntervalScale.prototype.parse = function (val) {
  58. // `Scale#parse` (and its overrids) are typically applied at the axis values input
  59. // in echarts option. e.g., `axis.min/max`, `dataZoom.min/max`, etc.
  60. // but `series.data` is not included, which uses `dataValueHelper.ts`#`parseDataValue`.
  61. // `Scale#parse` originally introduced in fb8c813215098b9d2458966229bb95c510883d5e
  62. // at 2016 for dataZoom start/end settings (See `parseAxisModelMinMax`).
  63. //
  64. // Historically `scale/Interval.ts` returns the input value directly. But numeric
  65. // values (such as a number-like string '123') effectively passed through here and
  66. // were involved in calculations, which was error-prone and inconsistent with the
  67. // declared TS return type. Previously such issues are fixed separately in different
  68. // places case by case (such as #2475).
  69. //
  70. // Now, we perform actual parse to ensure its `number` type here. The parsing rule
  71. // follows the series data parsing rule (`dataValueHelper.ts`#`parseDataValue`)
  72. // and maintains compatibility as much as possible (thus a more strict parsing
  73. // `number.ts`#`numericToNumber` is not used here.)
  74. //
  75. // FIXME: `ScaleDataValue` also need to be modified to include numeric string type,
  76. // since it effectively does.
  77. return val == null || val === '' ? NaN
  78. // If string (like '-'), using '+' parse to NaN
  79. // If object, also parse to NaN
  80. : Number(val);
  81. };
  82. IntervalScale.prototype.contain = function (val) {
  83. return helper.contain(val, this._extent);
  84. };
  85. IntervalScale.prototype.normalize = function (val) {
  86. return this._calculator.normalize(val, this._extent);
  87. };
  88. IntervalScale.prototype.scale = function (val) {
  89. return this._calculator.scale(val, this._extent);
  90. };
  91. IntervalScale.prototype.getInterval = function () {
  92. return this._interval;
  93. };
  94. IntervalScale.prototype.setInterval = function (interval) {
  95. this._interval = interval;
  96. // Dropped auto calculated niceExtent and use user-set extent.
  97. // We assume user wants to set both interval, min, max to get a better result.
  98. this._niceExtent = this._extent.slice();
  99. this._intervalPrecision = helper.getIntervalPrecision(interval);
  100. };
  101. /**
  102. * @override
  103. */
  104. IntervalScale.prototype.getTicks = function (opt) {
  105. opt = opt || {};
  106. var interval = this._interval;
  107. var extent = this._extent;
  108. var niceTickExtent = this._niceExtent;
  109. var intervalPrecision = this._intervalPrecision;
  110. var scaleBreakHelper = getScaleBreakHelper();
  111. var ticks = [];
  112. // If interval is 0, return [];
  113. if (!interval) {
  114. return ticks;
  115. }
  116. if (opt.breakTicks === 'only_break' && scaleBreakHelper) {
  117. scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent);
  118. return ticks;
  119. }
  120. // Consider this case: using dataZoom toolbox, zoom and zoom.
  121. var safeLimit = 10000;
  122. if (extent[0] < niceTickExtent[0]) {
  123. if (opt.expandToNicedExtent) {
  124. ticks.push({
  125. value: roundNumber(niceTickExtent[0] - interval, intervalPrecision)
  126. });
  127. } else {
  128. ticks.push({
  129. value: extent[0]
  130. });
  131. }
  132. }
  133. var estimateNiceMultiple = function (tickVal, targetTick) {
  134. return Math.round((targetTick - tickVal) / interval);
  135. };
  136. var tick = niceTickExtent[0];
  137. while (tick <= niceTickExtent[1]) {
  138. ticks.push({
  139. value: tick
  140. });
  141. // Avoid rounding error
  142. tick = roundNumber(tick + interval, intervalPrecision);
  143. if (this._brkCtx) {
  144. var moreMultiple = this._brkCtx.calcNiceTickMultiple(tick, estimateNiceMultiple);
  145. if (moreMultiple >= 0) {
  146. tick = roundNumber(tick + moreMultiple * interval, intervalPrecision);
  147. }
  148. }
  149. if (ticks.length > 0 && tick === ticks[ticks.length - 1].value) {
  150. // Consider out of safe float point, e.g.,
  151. // -3711126.9907707 + 2e-10 === -3711126.9907707
  152. break;
  153. }
  154. if (ticks.length > safeLimit) {
  155. return [];
  156. }
  157. }
  158. // Consider this case: the last item of ticks is smaller
  159. // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
  160. var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1];
  161. if (extent[1] > lastNiceTick) {
  162. if (opt.expandToNicedExtent) {
  163. ticks.push({
  164. value: roundNumber(lastNiceTick + interval, intervalPrecision)
  165. });
  166. } else {
  167. ticks.push({
  168. value: extent[1]
  169. });
  170. }
  171. }
  172. if (scaleBreakHelper) {
  173. scaleBreakHelper.pruneTicksByBreak(opt.pruneByBreak, ticks, this._brkCtx.breaks, function (item) {
  174. return item.value;
  175. }, this._interval, this._extent);
  176. }
  177. if (opt.breakTicks !== 'none' && scaleBreakHelper) {
  178. scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent);
  179. }
  180. return ticks;
  181. };
  182. IntervalScale.prototype.getMinorTicks = function (splitNumber) {
  183. var ticks = this.getTicks({
  184. expandToNicedExtent: true
  185. });
  186. // NOTE: In log-scale, do not support minor ticks when breaks exist.
  187. // because currently log-scale minor ticks is calculated based on raw values
  188. // rather than log-transformed value, due to an odd effect when breaks exist.
  189. var minorTicks = [];
  190. var extent = this.getExtent();
  191. for (var i = 1; i < ticks.length; i++) {
  192. var nextTick = ticks[i];
  193. var prevTick = ticks[i - 1];
  194. if (prevTick["break"] || nextTick["break"]) {
  195. // Do not build minor ticks to the adjacent ticks to breaks ticks,
  196. // since the interval might be irregular.
  197. continue;
  198. }
  199. var count = 0;
  200. var minorTicksGroup = [];
  201. var interval = nextTick.value - prevTick.value;
  202. var minorInterval = interval / splitNumber;
  203. var minorIntervalPrecision = helper.getIntervalPrecision(minorInterval);
  204. while (count < splitNumber - 1) {
  205. var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval, minorIntervalPrecision);
  206. // For the first and last interval. The count may be less than splitNumber.
  207. if (minorTick > extent[0] && minorTick < extent[1]) {
  208. minorTicksGroup.push(minorTick);
  209. }
  210. count++;
  211. }
  212. var scaleBreakHelper = getScaleBreakHelper();
  213. scaleBreakHelper && scaleBreakHelper.pruneTicksByBreak('auto', minorTicksGroup, this._getNonTransBreaks(), function (value) {
  214. return value;
  215. }, this._interval, extent);
  216. minorTicks.push(minorTicksGroup);
  217. }
  218. return minorTicks;
  219. };
  220. IntervalScale.prototype._getNonTransBreaks = function () {
  221. return this._brkCtx ? this._brkCtx.breaks : [];
  222. };
  223. /**
  224. * @param opt.precision If 'auto', use nice presision.
  225. * @param opt.pad returns 1.50 but not 1.5 if precision is 2.
  226. */
  227. IntervalScale.prototype.getLabel = function (data, opt) {
  228. if (data == null) {
  229. return '';
  230. }
  231. var precision = opt && opt.precision;
  232. if (precision == null) {
  233. precision = numberUtil.getPrecision(data.value) || 0;
  234. } else if (precision === 'auto') {
  235. // Should be more precise then tick.
  236. precision = this._intervalPrecision;
  237. }
  238. // (1) If `precision` is set, 12.005 should be display as '12.00500'.
  239. // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.
  240. var dataNum = roundNumber(data.value, precision, true);
  241. return formatUtil.addCommas(dataNum);
  242. };
  243. /**
  244. * FIXME: refactor - disallow override, use composition instead.
  245. *
  246. * The override of `calcNiceTicks` should ensure these members are provided:
  247. * this._intervalPrecision
  248. * this._interval
  249. *
  250. * @param splitNumber By default `5`.
  251. */
  252. IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) {
  253. splitNumber = splitNumber || 5;
  254. var extent = this._extent.slice();
  255. var span = this._getExtentSpanWithBreaks();
  256. if (!isFinite(span)) {
  257. return;
  258. }
  259. // User may set axis min 0 and data are all negative
  260. // FIXME If it needs to reverse ?
  261. if (span < 0) {
  262. span = -span;
  263. extent.reverse();
  264. this._innerSetExtent(extent[0], extent[1]);
  265. extent = this._extent.slice();
  266. }
  267. var result = helper.intervalScaleNiceTicks(extent, span, splitNumber, minInterval, maxInterval);
  268. this._intervalPrecision = result.intervalPrecision;
  269. this._interval = result.interval;
  270. this._niceExtent = result.niceTickExtent;
  271. };
  272. IntervalScale.prototype.calcNiceExtent = function (opt) {
  273. var extent = this._extent.slice();
  274. // If extent start and end are same, expand them
  275. if (extent[0] === extent[1]) {
  276. if (extent[0] !== 0) {
  277. // Expand extent
  278. // Note that extents can be both negative. See #13154
  279. var expandSize = Math.abs(extent[0]);
  280. // In the fowllowing case
  281. // Axis has been fixed max 100
  282. // Plus data are all 100 and axis extent are [100, 100].
  283. // Extend to the both side will cause expanded max is larger than fixed max.
  284. // So only expand to the smaller side.
  285. if (!opt.fixMax) {
  286. extent[1] += expandSize / 2;
  287. extent[0] -= expandSize / 2;
  288. } else {
  289. extent[0] -= expandSize / 2;
  290. }
  291. } else {
  292. extent[1] = 1;
  293. }
  294. }
  295. var span = extent[1] - extent[0];
  296. // If there are no data and extent are [Infinity, -Infinity]
  297. if (!isFinite(span)) {
  298. extent[0] = 0;
  299. extent[1] = 1;
  300. }
  301. this._innerSetExtent(extent[0], extent[1]);
  302. extent = this._extent.slice();
  303. this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
  304. var interval = this._interval;
  305. var intervalPrecition = this._intervalPrecision;
  306. if (!opt.fixMin) {
  307. extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval, intervalPrecition);
  308. }
  309. if (!opt.fixMax) {
  310. extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval, intervalPrecition);
  311. }
  312. this._innerSetExtent(extent[0], extent[1]);
  313. };
  314. IntervalScale.prototype.setNiceExtent = function (min, max) {
  315. this._niceExtent = [min, max];
  316. };
  317. IntervalScale.type = 'interval';
  318. return IntervalScale;
  319. }(Scale);
  320. Scale.registerClass(IntervalScale);
  321. export default IntervalScale;