| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 | 
/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements.  See the NOTICE file* distributed with this work for additional information* regarding copyright ownership.  The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License.  You may obtain a copy of the License at**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied.  See the License for the* specific language governing permissions and limitations* under the License.*/var _util = require("zrender/lib/core/util");var each = _util.each;var map = _util.map;var _number = require("../util/number");var linearMap = _number.linearMap;var getPixelPrecision = _number.getPixelPrecision;var round = _number.round;var _axisTickLabelBuilder = require("./axisTickLabelBuilder");var createAxisTicks = _axisTickLabelBuilder.createAxisTicks;var createAxisLabels = _axisTickLabelBuilder.createAxisLabels;var calculateCategoryInterval = _axisTickLabelBuilder.calculateCategoryInterval;/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements.  See the NOTICE file* distributed with this work for additional information* regarding copyright ownership.  The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License.  You may obtain a copy of the License at**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied.  See the License for the* specific language governing permissions and limitations* under the License.*/var NORMALIZED_EXTENT = [0, 1];/** * Base class of Axis. * @constructor */var Axis = function (dim, scale, extent) {  /**   * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.   * @type {string}   */  this.dim = dim;  /**   * Axis scale   * @type {module:echarts/coord/scale/*}   */  this.scale = scale;  /**   * @type {Array.<number>}   * @private   */  this._extent = extent || [0, 0];  /**   * @type {boolean}   */  this.inverse = false;  /**   * Usually true when axis has a ordinal scale   * @type {boolean}   */  this.onBand = false;};Axis.prototype = {  constructor: Axis,  /**   * If axis extent contain given coord   * @param {number} coord   * @return {boolean}   */  contain: function (coord) {    var extent = this._extent;    var min = Math.min(extent[0], extent[1]);    var max = Math.max(extent[0], extent[1]);    return coord >= min && coord <= max;  },  /**   * If axis extent contain given data   * @param {number} data   * @return {boolean}   */  containData: function (data) {    return this.scale.contain(data);  },  /**   * Get coord extent.   * @return {Array.<number>}   */  getExtent: function () {    return this._extent.slice();  },  /**   * Get precision used for formatting   * @param {Array.<number>} [dataExtent]   * @return {number}   */  getPixelPrecision: function (dataExtent) {    return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent);  },  /**   * Set coord extent   * @param {number} start   * @param {number} end   */  setExtent: function (start, end) {    var extent = this._extent;    extent[0] = start;    extent[1] = end;  },  /**   * Convert data to coord. Data is the rank if it has an ordinal scale   * @param {number} data   * @param  {boolean} clamp   * @return {number}   */  dataToCoord: function (data, clamp) {    var extent = this._extent;    var scale = this.scale;    data = scale.normalize(data);    if (this.onBand && scale.type === 'ordinal') {      extent = extent.slice();      fixExtentWithBands(extent, scale.count());    }    return linearMap(data, NORMALIZED_EXTENT, extent, clamp);  },  /**   * Convert coord to data. Data is the rank if it has an ordinal scale   * @param {number} coord   * @param  {boolean} clamp   * @return {number}   */  coordToData: function (coord, clamp) {    var extent = this._extent;    var scale = this.scale;    if (this.onBand && scale.type === 'ordinal') {      extent = extent.slice();      fixExtentWithBands(extent, scale.count());    }    var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);    return this.scale.scale(t);  },  /**   * Convert pixel point to data in axis   * @param {Array.<number>} point   * @param  {boolean} clamp   * @return {number} data   */  pointToData: function (point, clamp) {// Should be implemented in derived class if necessary.  },  /**   * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,   * `axis.getTicksCoords` considers `onBand`, which is used by   * `boundaryGap:true` of category axis and splitLine and splitArea.   * @param {Object} [opt]   * @param {Model} [opt.tickModel=axis.model.getModel('axisTick')]   * @param {boolean} [opt.clamp] If `true`, the first and the last   *        tick must be at the axis end points. Otherwise, clip ticks   *        that outside the axis extent.   * @return {Array.<Object>} [{   *     coord: ...,   *     tickValue: ...   * }, ...]   */  getTicksCoords: function (opt) {    opt = opt || {};    var tickModel = opt.tickModel || this.getTickModel();    var result = createAxisTicks(this, tickModel);    var ticks = result.ticks;    var ticksCoords = map(ticks, function (tickValue) {      return {        coord: this.dataToCoord(tickValue),        tickValue: tickValue      };    }, this);    var alignWithLabel = tickModel.get('alignWithLabel');    fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp);    return ticksCoords;  },  /**   * @return {Array.<Array.<Object>>} [{ coord: ..., tickValue: ...}]   */  getMinorTicksCoords: function () {    if (this.scale.type === 'ordinal') {      // Category axis doesn't support minor ticks      return [];    }    var minorTickModel = this.model.getModel('minorTick');    var splitNumber = minorTickModel.get('splitNumber'); // Protection.    if (!(splitNumber > 0 && splitNumber < 100)) {      splitNumber = 5;    }    var minorTicks = this.scale.getMinorTicks(splitNumber);    var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {      return map(minorTicksGroup, function (minorTick) {        return {          coord: this.dataToCoord(minorTick),          tickValue: minorTick        };      }, this);    }, this);    return minorTicksCoords;  },  /**   * @return {Array.<Object>} [{   *     formattedLabel: string,   *     rawLabel: axis.scale.getLabel(tickValue)   *     tickValue: number   * }, ...]   */  getViewLabels: function () {    return createAxisLabels(this).labels;  },  /**   * @return {module:echarts/coord/model/Model}   */  getLabelModel: function () {    return this.model.getModel('axisLabel');  },  /**   * Notice here we only get the default tick model. For splitLine   * or splitArea, we should pass the splitLineModel or splitAreaModel   * manually when calling `getTicksCoords`.   * In GL, this method may be overrided to:   * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`   * @return {module:echarts/coord/model/Model}   */  getTickModel: function () {    return this.model.getModel('axisTick');  },  /**   * Get width of band   * @return {number}   */  getBandWidth: function () {    var axisExtent = this._extent;    var dataExtent = this.scale.getExtent();    var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data.    len === 0 && (len = 1);    var size = Math.abs(axisExtent[1] - axisExtent[0]);    return Math.abs(size) / len;  },  /**   * @abstract   * @return {boolean} Is horizontal   */  isHorizontal: null,  /**   * @abstract   * @return {number} Get axis rotate, by degree.   */  getRotate: null,  /**   * Only be called in category axis.   * Can be overrided, consider other axes like in 3D.   * @return {number} Auto interval for cateogry axis tick and label   */  calculateCategoryInterval: function () {    return calculateCategoryInterval(this);  }};function fixExtentWithBands(extent, nTick) {  var size = extent[1] - extent[0];  var len = nTick;  var margin = size / len / 2;  extent[0] += margin;  extent[1] -= margin;} // If axis has labels [1, 2, 3, 4]. Bands on the axis are// |---1---|---2---|---3---|---4---|.// So the displayed ticks and splitLine/splitArea should between// each data item, otherwise cause misleading (e.g., split tow bars// of a single data item when there are two bar series).// Also consider if tickCategoryInterval > 0 and onBand, ticks and// splitLine/spliteArea should layout appropriately corresponding// to displayed labels. (So we should not use `getBandWidth` in this// case).function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) {  var ticksLen = ticksCoords.length;  if (!axis.onBand || alignWithLabel || !ticksLen) {    return;  }  var axisExtent = axis.getExtent();  var last;  var diffSize;  if (ticksLen === 1) {    ticksCoords[0].coord = axisExtent[0];    last = ticksCoords[1] = {      coord: axisExtent[0]    };  } else {    var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue;    var shift = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen;    each(ticksCoords, function (ticksItem) {      ticksItem.coord -= shift / 2;    });    var dataExtent = axis.scale.getExtent();    diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue;    last = {      coord: ticksCoords[ticksLen - 1].coord + shift * diffSize    };    ticksCoords.push(last);  }  var inverse = axisExtent[0] > axisExtent[1]; // Handling clamp.  if (littleThan(ticksCoords[0].coord, axisExtent[0])) {    clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift();  }  if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {    ticksCoords.unshift({      coord: axisExtent[0]    });  }  if (littleThan(axisExtent[1], last.coord)) {    clamp ? last.coord = axisExtent[1] : ticksCoords.pop();  }  if (clamp && littleThan(last.coord, axisExtent[1])) {    ticksCoords.push({      coord: axisExtent[1]    });  }  function littleThan(a, b) {    // Avoid rounding error cause calculated tick coord different with extent.    // It may cause an extra unecessary tick added.    a = round(a);    b = round(b);    return inverse ? a > b : a < b;  }}var _default = Axis;module.exports = _default;
 |