Axis.js 9.4 KB

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