Axis.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 { each, map } from 'zrender/lib/core/util.js';
  41. import { linearMap, getPixelPrecision, round } from '../util/number.js';
  42. import { createAxisTicks, createAxisLabels, calculateCategoryInterval, AxisTickLabelComputingKind, createAxisLabelsComputingContext } from './axisTickLabelBuilder.js';
  43. var NORMALIZED_EXTENT = [0, 1];
  44. /**
  45. * Base class of Axis.
  46. *
  47. * Lifetime: recreate for each main process.
  48. * [NOTICE]: Some caches is stored on the axis instance (see `axisTickLabelBuilder.ts`)
  49. * which is based on this lifetime.
  50. */
  51. var Axis = /** @class */function () {
  52. function Axis(dim, scale, extent) {
  53. this.onBand = false;
  54. // Make sure that `extent[0] > extent[1]` only if `inverse: true`.
  55. // `inverse` can be inferred by `extent` unless `extent[0] === extent[1]`.
  56. this.inverse = false;
  57. this.dim = dim;
  58. this.scale = scale;
  59. this._extent = extent || [0, 0];
  60. }
  61. /**
  62. * If axis extent contain given coord
  63. */
  64. Axis.prototype.contain = function (coord) {
  65. var extent = this._extent;
  66. var min = Math.min(extent[0], extent[1]);
  67. var max = Math.max(extent[0], extent[1]);
  68. return coord >= min && coord <= max;
  69. };
  70. /**
  71. * If axis extent contain given data
  72. */
  73. Axis.prototype.containData = function (data) {
  74. return this.scale.contain(this.scale.parse(data));
  75. };
  76. /**
  77. * Get coord extent.
  78. */
  79. Axis.prototype.getExtent = function () {
  80. return this._extent.slice();
  81. };
  82. /**
  83. * Get precision used for formatting
  84. */
  85. Axis.prototype.getPixelPrecision = function (dataExtent) {
  86. return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent);
  87. };
  88. /**
  89. * Set coord extent
  90. */
  91. Axis.prototype.setExtent = function (start, end) {
  92. var extent = this._extent;
  93. extent[0] = start;
  94. extent[1] = end;
  95. };
  96. /**
  97. * Convert data to coord. Data is the rank if it has an ordinal scale
  98. */
  99. Axis.prototype.dataToCoord = function (data, clamp) {
  100. var extent = this._extent;
  101. var scale = this.scale;
  102. data = scale.normalize(scale.parse(data));
  103. if (this.onBand && scale.type === 'ordinal') {
  104. extent = extent.slice();
  105. fixExtentWithBands(extent, scale.count());
  106. }
  107. return linearMap(data, NORMALIZED_EXTENT, extent, clamp);
  108. };
  109. /**
  110. * Convert coord to data. Data is the rank if it has an ordinal scale
  111. */
  112. Axis.prototype.coordToData = function (coord, clamp) {
  113. var extent = this._extent;
  114. var scale = this.scale;
  115. if (this.onBand && scale.type === 'ordinal') {
  116. extent = extent.slice();
  117. fixExtentWithBands(extent, scale.count());
  118. }
  119. var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);
  120. return this.scale.scale(t);
  121. };
  122. /**
  123. * Convert pixel point to data in axis
  124. */
  125. Axis.prototype.pointToData = function (point, clamp) {
  126. // Should be implemented in derived class if necessary.
  127. return;
  128. };
  129. /**
  130. * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,
  131. * `axis.getTicksCoords` considers `onBand`, which is used by
  132. * `boundaryGap:true` of category axis and splitLine and splitArea.
  133. * @param opt.tickModel default: axis.model.getModel('axisTick')
  134. * @param opt.clamp If `true`, the first and the last
  135. * tick must be at the axis end points. Otherwise, clip ticks
  136. * that outside the axis extent.
  137. */
  138. Axis.prototype.getTicksCoords = function (opt) {
  139. opt = opt || {};
  140. var tickModel = opt.tickModel || this.getTickModel();
  141. var result = createAxisTicks(this, tickModel, {
  142. breakTicks: opt.breakTicks,
  143. pruneByBreak: opt.pruneByBreak
  144. });
  145. var ticks = result.ticks;
  146. var ticksCoords = map(ticks, function (tickVal) {
  147. return {
  148. coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawOrdinalNumber(tickVal) : tickVal),
  149. tickValue: tickVal
  150. };
  151. }, this);
  152. var alignWithLabel = tickModel.get('alignWithLabel');
  153. fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp);
  154. return ticksCoords;
  155. };
  156. Axis.prototype.getMinorTicksCoords = function () {
  157. if (this.scale.type === 'ordinal') {
  158. // Category axis doesn't support minor ticks
  159. return [];
  160. }
  161. var minorTickModel = this.model.getModel('minorTick');
  162. var splitNumber = minorTickModel.get('splitNumber');
  163. // Protection.
  164. if (!(splitNumber > 0 && splitNumber < 100)) {
  165. splitNumber = 5;
  166. }
  167. var minorTicks = this.scale.getMinorTicks(splitNumber);
  168. var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {
  169. return map(minorTicksGroup, function (minorTick) {
  170. return {
  171. coord: this.dataToCoord(minorTick),
  172. tickValue: minorTick
  173. };
  174. }, this);
  175. }, this);
  176. return minorTicksCoords;
  177. };
  178. Axis.prototype.getViewLabels = function (ctx) {
  179. ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine);
  180. return createAxisLabels(this, ctx).labels;
  181. };
  182. Axis.prototype.getLabelModel = function () {
  183. return this.model.getModel('axisLabel');
  184. };
  185. /**
  186. * Notice here we only get the default tick model. For splitLine
  187. * or splitArea, we should pass the splitLineModel or splitAreaModel
  188. * manually when calling `getTicksCoords`.
  189. * In GL, this method may be overridden to:
  190. * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`
  191. */
  192. Axis.prototype.getTickModel = function () {
  193. return this.model.getModel('axisTick');
  194. };
  195. /**
  196. * Get width of band
  197. */
  198. Axis.prototype.getBandWidth = function () {
  199. var axisExtent = this._extent;
  200. var dataExtent = this.scale.getExtent();
  201. var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);
  202. // Fix #2728, avoid NaN when only one data.
  203. len === 0 && (len = 1);
  204. var size = Math.abs(axisExtent[1] - axisExtent[0]);
  205. return Math.abs(size) / len;
  206. };
  207. /**
  208. * Only be called in category axis.
  209. * Can be overridden, consider other axes like in 3D.
  210. * @return Auto interval for cateogry axis tick and label
  211. */
  212. Axis.prototype.calculateCategoryInterval = function (ctx) {
  213. ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine);
  214. return calculateCategoryInterval(this, ctx);
  215. };
  216. return Axis;
  217. }();
  218. function fixExtentWithBands(extent, nTick) {
  219. var size = extent[1] - extent[0];
  220. var len = nTick;
  221. var margin = size / len / 2;
  222. extent[0] += margin;
  223. extent[1] -= margin;
  224. }
  225. // If axis has labels [1, 2, 3, 4]. Bands on the axis are
  226. // |---1---|---2---|---3---|---4---|.
  227. // So the displayed ticks and splitLine/splitArea should between
  228. // each data item, otherwise cause misleading (e.g., split tow bars
  229. // of a single data item when there are two bar series).
  230. // Also consider if tickCategoryInterval > 0 and onBand, ticks and
  231. // splitLine/spliteArea should layout appropriately corresponding
  232. // to displayed labels. (So we should not use `getBandWidth` in this
  233. // case).
  234. function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) {
  235. var ticksLen = ticksCoords.length;
  236. if (!axis.onBand || alignWithLabel || !ticksLen) {
  237. return;
  238. }
  239. var axisExtent = axis.getExtent();
  240. var last;
  241. var diffSize;
  242. if (ticksLen === 1) {
  243. ticksCoords[0].coord = axisExtent[0];
  244. ticksCoords[0].onBand = true;
  245. last = ticksCoords[1] = {
  246. coord: axisExtent[1],
  247. tickValue: ticksCoords[0].tickValue,
  248. onBand: true
  249. };
  250. } else {
  251. var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue;
  252. var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen;
  253. each(ticksCoords, function (ticksItem) {
  254. ticksItem.coord -= shift_1 / 2;
  255. ticksItem.onBand = true;
  256. });
  257. var dataExtent = axis.scale.getExtent();
  258. diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue;
  259. last = {
  260. coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize,
  261. tickValue: dataExtent[1] + 1,
  262. onBand: true
  263. };
  264. ticksCoords.push(last);
  265. }
  266. var inverse = axisExtent[0] > axisExtent[1];
  267. // Handling clamp.
  268. if (littleThan(ticksCoords[0].coord, axisExtent[0])) {
  269. clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift();
  270. }
  271. if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {
  272. ticksCoords.unshift({
  273. coord: axisExtent[0],
  274. onBand: true
  275. });
  276. }
  277. if (littleThan(axisExtent[1], last.coord)) {
  278. clamp ? last.coord = axisExtent[1] : ticksCoords.pop();
  279. }
  280. if (clamp && littleThan(last.coord, axisExtent[1])) {
  281. ticksCoords.push({
  282. coord: axisExtent[1],
  283. onBand: true
  284. });
  285. }
  286. function littleThan(a, b) {
  287. // Avoid rounding error cause calculated tick coord different with extent.
  288. // It may cause an extra unnecessary tick added.
  289. a = round(a);
  290. b = round(b);
  291. return inverse ? a > b : a < b;
  292. }
  293. }
  294. export default Axis;