/**
* Interval scale
* @module echarts/scale/Interval
*/
define(function (require) {
var numberUtil = require('../util/number');
var formatUtil = require('../util/format');
var Scale = require('./Scale');
var mathFloor = Math.floor;
var mathCeil = Math.ceil;
/**
* @alias module:echarts/coord/scale/Interval
* @constructor
*/
var IntervalScale = Scale.extend({
type: 'interval',
_interval: 0,
setExtent: function (start, end) {
var thisExtent = this._extent;
//start,end may be a Number like '25',so...
if (!isNaN(start)) {
thisExtent[0] = parseFloat(start);
}
if (!isNaN(end)) {
thisExtent[1] = parseFloat(end);
}
},
unionExtent: function (other) {
var extent = this._extent;
other[0] < extent[0] && (extent[0] = other[0]);
other[1] > extent[1] && (extent[1] = other[1]);
// unionExtent may called by it's sub classes
IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);
},
/**
* Get interval
*/
getInterval: function () {
if (!this._interval) {
this.niceTicks();
}
return this._interval;
},
/**
* Set interval
*/
setInterval: function (interval) {
this._interval = interval;
// Dropped auto calculated niceExtent and use user setted extent
// We assume user wan't to set both interval, min, max to get a better result
this._niceExtent = this._extent.slice();
},
/**
* @return {Array.<number>}
*/
getTicks: function () {
if (!this._interval) {
this.niceTicks();
}
var interval = this._interval;
var extent = this._extent;
var ticks = [];
// Consider this case: using dataZoom toolbox, zoom and zoom.
var safeLimit = 10000;
if (interval) {
var niceExtent = this._niceExtent;
if (extent[0] < niceExtent[0]) {
ticks.push(extent[0]);
}
var tick = niceExtent[0];
while (tick <= niceExtent[1]) {
ticks.push(tick);
// Avoid rounding error
tick = numberUtil.round(tick + interval);
if (ticks.length > safeLimit) {
return [];
}
}
if (extent[1] > niceExtent[1]) {
ticks.push(extent[1]);
}
}
return ticks;
},
/**
* @return {Array.<string>}
*/
getTicksLabels: function () {
var labels = [];
var ticks = this.getTicks();
for (var i = 0; i < ticks.length; i++) {
labels.push(this.getLabel(ticks[i]));
}
return labels;
},
/**
* @param {number} n
* @return {number}
*/
getLabel: function (data) {
return formatUtil.addCommas(data);
},
/**
* Update interval and extent of intervals for nice ticks
*
* @param {number} [splitNumber = 5] Desired number of ticks
*/
niceTicks: function (splitNumber) {
splitNumber = splitNumber || 5;
var extent = this._extent;
var span = extent[1] - extent[0];
if (!isFinite(span)) {
return;
}
// User may set axis min 0 and data are all negative
// FIXME If it needs to reverse ?
if (span < 0) {
span = -span;
extent.reverse();
}
// From "Nice Numbers for Graph Labels" of Graphic Gems
// var niceSpan = numberUtil.nice(span, false);
var step = numberUtil.nice(span / splitNumber, true);
// Niced extent inside original extent
var niceExtent = [
numberUtil.round(mathCeil(extent[0] / step) * step),
numberUtil.round(mathFloor(extent[1] / step) * step)
];
this._interval = step;
this._niceExtent = niceExtent;
},
/**
* Nice extent.
* @param {number} [splitNumber = 5] Given approx tick number
* @param {boolean} [fixMin=false]
* @param {boolean} [fixMax=false]
*/
niceExtent: function (splitNumber, fixMin, fixMax) {
var extent = this._extent;
// If extent start and end are same, expand them
if (extent[0] === extent[1]) {
if (extent[0] !== 0) {
// Expand extent
var expandSize = extent[0] / 2;
extent[0] -= expandSize;
extent[1] += expandSize;
}
else {
extent[1] = 1;
}
}
var span = extent[1] - extent[0];
// If there are no data and extent are [Infinity, -Infinity]
if (!isFinite(span)) {
extent[0] = 0;
extent[1] = 1;
}
this.niceTicks(splitNumber);
// var extent = this._extent;
var interval = this._interval;
if (!fixMin) {
extent[0] = numberUtil.round(mathFloor(extent[0] / interval) * interval);
}
if (!fixMax) {
extent[1] = numberUtil.round(mathCeil(extent[1] / interval) * interval);
}
}
});
/**
* @return {module:echarts/scale/Time}
*/
IntervalScale.create = function () {
return new IntervalScale();
};
return IntervalScale;
});
|