Log.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. var zrUtil = require("zrender/lib/core/util");
  2. var Scale = require("./Scale");
  3. var numberUtil = require("../util/number");
  4. var IntervalScale = require("./Interval");
  5. /**
  6. * Log scale
  7. * @module echarts/scale/Log
  8. */
  9. // Use some method of IntervalScale
  10. var scaleProto = Scale.prototype;
  11. var intervalScaleProto = IntervalScale.prototype;
  12. var getPrecisionSafe = numberUtil.getPrecisionSafe;
  13. var roundingErrorFix = numberUtil.round;
  14. var mathFloor = Math.floor;
  15. var mathCeil = Math.ceil;
  16. var mathPow = Math.pow;
  17. var mathLog = Math.log;
  18. var LogScale = Scale.extend({
  19. type: 'log',
  20. base: 10,
  21. $constructor: function () {
  22. Scale.apply(this, arguments);
  23. this._originalScale = new IntervalScale();
  24. },
  25. /**
  26. * @return {Array.<number>}
  27. */
  28. getTicks: function () {
  29. var originalScale = this._originalScale;
  30. var extent = this._extent;
  31. var originalExtent = originalScale.getExtent();
  32. return zrUtil.map(intervalScaleProto.getTicks.call(this), function (val) {
  33. var powVal = numberUtil.round(mathPow(this.base, val)); // Fix #4158
  34. powVal = val === extent[0] && originalScale.__fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal;
  35. powVal = val === extent[1] && originalScale.__fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal;
  36. return powVal;
  37. }, this);
  38. },
  39. /**
  40. * @param {number} val
  41. * @return {string}
  42. */
  43. getLabel: intervalScaleProto.getLabel,
  44. /**
  45. * @param {number} val
  46. * @return {number}
  47. */
  48. scale: function (val) {
  49. val = scaleProto.scale.call(this, val);
  50. return mathPow(this.base, val);
  51. },
  52. /**
  53. * @param {number} start
  54. * @param {number} end
  55. */
  56. setExtent: function (start, end) {
  57. var base = this.base;
  58. start = mathLog(start) / mathLog(base);
  59. end = mathLog(end) / mathLog(base);
  60. intervalScaleProto.setExtent.call(this, start, end);
  61. },
  62. /**
  63. * @return {number} end
  64. */
  65. getExtent: function () {
  66. var base = this.base;
  67. var extent = scaleProto.getExtent.call(this);
  68. extent[0] = mathPow(base, extent[0]);
  69. extent[1] = mathPow(base, extent[1]); // Fix #4158
  70. var originalScale = this._originalScale;
  71. var originalExtent = originalScale.getExtent();
  72. originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
  73. originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
  74. return extent;
  75. },
  76. /**
  77. * @param {Array.<number>} extent
  78. */
  79. unionExtent: function (extent) {
  80. this._originalScale.unionExtent(extent);
  81. var base = this.base;
  82. extent[0] = mathLog(extent[0]) / mathLog(base);
  83. extent[1] = mathLog(extent[1]) / mathLog(base);
  84. scaleProto.unionExtent.call(this, extent);
  85. },
  86. /**
  87. * @override
  88. */
  89. unionExtentFromData: function (data, dim) {
  90. this.unionExtent(data.getDataExtent(dim, true, function (val) {
  91. return val > 0;
  92. }));
  93. },
  94. /**
  95. * Update interval and extent of intervals for nice ticks
  96. * @param {number} [approxTickNum = 10] Given approx tick number
  97. */
  98. niceTicks: function (approxTickNum) {
  99. approxTickNum = approxTickNum || 10;
  100. var extent = this._extent;
  101. var span = extent[1] - extent[0];
  102. if (span === Infinity || span <= 0) {
  103. return;
  104. }
  105. var interval = numberUtil.quantity(span);
  106. var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count.
  107. if (err <= 0.5) {
  108. interval *= 10;
  109. } // Interval should be integer
  110. while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {
  111. interval *= 10;
  112. }
  113. var niceExtent = [numberUtil.round(mathCeil(extent[0] / interval) * interval), numberUtil.round(mathFloor(extent[1] / interval) * interval)];
  114. this._interval = interval;
  115. this._niceExtent = niceExtent;
  116. },
  117. /**
  118. * Nice extent.
  119. * @override
  120. */
  121. niceExtent: function (opt) {
  122. intervalScaleProto.niceExtent.call(this, opt);
  123. var originalScale = this._originalScale;
  124. originalScale.__fixMin = opt.fixMin;
  125. originalScale.__fixMax = opt.fixMax;
  126. }
  127. });
  128. zrUtil.each(['contain', 'normalize'], function (methodName) {
  129. LogScale.prototype[methodName] = function (val) {
  130. val = mathLog(val) / mathLog(this.base);
  131. return scaleProto[methodName].call(this, val);
  132. };
  133. });
  134. LogScale.create = function () {
  135. return new LogScale();
  136. };
  137. function fixRoundingError(val, originalVal) {
  138. return roundingErrorFix(val, getPrecisionSafe(originalVal));
  139. }
  140. var _default = LogScale;
  141. module.exports = _default;