165 lines
4.8 KiB
JavaScript
165 lines
4.8 KiB
JavaScript
/**
|
||
* @fileOverview 自动计算数字坐标轴
|
||
* @author dxq613@gmail.com
|
||
*/
|
||
var isNil = require('@antv/util/lib/type/is-nil');
|
||
|
||
var isNumber = require('@antv/util/lib/type/is-number');
|
||
|
||
var AutoUtil = require('./util');
|
||
|
||
var MIN_COUNT = 5;
|
||
var MAX_COUNT = 7;
|
||
var SNAP_COUNT_ARRAY = [1, 1.2, 1.5, 1.6, 2, 2.2, 2.4, 2.5, 3, 4, 5, 6, 7.5, 8, 10];
|
||
var SNAP_ARRAY = [1, 2, 4, 5, 10];
|
||
var EPS = 1e-12;
|
||
|
||
module.exports = function (info) {
|
||
var min = info.min;
|
||
var max = info.max;
|
||
var interval = info.interval;
|
||
var minTickInterval = info.minTickInterval;
|
||
var ticks = [];
|
||
var minCount = info.minCount || MIN_COUNT;
|
||
var maxCount = info.maxCount || MAX_COUNT;
|
||
var isFixedCount = minCount === maxCount; // 是否限定死了个数
|
||
|
||
var minLimit = isNil(info.minLimit) ? -Infinity : info.minLimit; // 限定的最小值
|
||
|
||
var maxLimit = isNil(info.maxLimit) ? Infinity : info.maxLimit; // 限定最大值
|
||
|
||
var avgCount = (minCount + maxCount) / 2;
|
||
var count = avgCount; // 用户传入的逼近数组
|
||
|
||
var snapArray = info.snapArray ? info.snapArray : isFixedCount ? SNAP_COUNT_ARRAY : SNAP_ARRAY; // 如果限定大小范围,同时大小范围等于用户传入的范围,同时限定了个数,interval 按照个数均分
|
||
|
||
if (min === minLimit && max === maxLimit && isFixedCount) {
|
||
interval = (max - min) / (count - 1);
|
||
}
|
||
|
||
if (isNil(min)) {
|
||
min = 0;
|
||
}
|
||
|
||
if (isNil(max)) {
|
||
max = 0;
|
||
}
|
||
|
||
if (Math.abs(max - min) < EPS) {
|
||
if (min === 0) {
|
||
max = 1;
|
||
} else {
|
||
if (min > 0) {
|
||
min = 0;
|
||
} else {
|
||
max = 0;
|
||
}
|
||
}
|
||
|
||
if (max - min < 5 && !interval && max - min >= 1) {
|
||
interval = 1;
|
||
}
|
||
}
|
||
|
||
if (isNil(interval)) {
|
||
// 计算间距
|
||
var temp = (max - min) / (avgCount - 1);
|
||
interval = AutoUtil.snapFactorTo(temp, snapArray, 'ceil');
|
||
|
||
if (maxCount !== minCount) {
|
||
count = parseInt((max - min) / interval, 10);
|
||
|
||
if (count > maxCount) {
|
||
count = maxCount;
|
||
}
|
||
|
||
if (count < minCount) {
|
||
count = minCount;
|
||
} // 不确定tick的个数时,使得tick偏小
|
||
|
||
|
||
interval = AutoUtil.snapFactorTo((max - min) / (count - 1), snapArray);
|
||
}
|
||
} // interval should not be less than minTickInterval
|
||
|
||
|
||
if (isNumber(minTickInterval) && interval < minTickInterval) {
|
||
interval = minTickInterval;
|
||
}
|
||
|
||
if (info.interval || maxCount !== minCount) {
|
||
// 校正 max 和 min
|
||
max = Math.min(AutoUtil.snapMultiple(max, interval, 'ceil'), maxLimit); // 向上逼近
|
||
|
||
min = Math.max(AutoUtil.snapMultiple(min, interval, 'floor'), minLimit); // 向下逼近
|
||
|
||
count = Math.round((max - min) / interval);
|
||
min = AutoUtil.fixedBase(min, interval); // 当min为负数的时候,fixedBase后,min可能会大于minLimit,导致最终产出的tick是大于minLimit的,所以必须进行修正
|
||
|
||
max = AutoUtil.fixedBase(max, interval);
|
||
var prevMin = null;
|
||
|
||
while (min > minLimit && minLimit > -Infinity && (prevMin === null || min < prevMin)) {
|
||
// 保证计算出来的刻度最小值 min, 不大于数据最小值 min
|
||
prevMin = min;
|
||
min = AutoUtil.fixedBase(min - interval, interval);
|
||
}
|
||
} else {
|
||
avgCount = parseInt(avgCount, 10); // 取整
|
||
|
||
var avg = (max + min) / 2;
|
||
var avgTick = AutoUtil.snapMultiple(avg, interval, 'ceil');
|
||
var sideCount = Math.floor((avgCount - 2) / 2);
|
||
var maxTick = avgTick + sideCount * interval;
|
||
var minTick;
|
||
|
||
if (avgCount % 2 === 0) {
|
||
minTick = avgTick - sideCount * interval;
|
||
} else {
|
||
minTick = avgTick - (sideCount + 1) * interval;
|
||
}
|
||
|
||
var prevMaxTick = null; // 如果减去intervl, fixBase后,新的minTick没有大于之前的值,就退出,防止死循环
|
||
|
||
while (maxTick < max && (prevMaxTick === null || maxTick > prevMaxTick)) {
|
||
// 保证计算出来的刻度最大值 maxTick 不小于数据最大值 max
|
||
prevMaxTick = maxTick;
|
||
maxTick = AutoUtil.fixedBase(maxTick + interval, interval);
|
||
}
|
||
|
||
var prevMinTick = null; // 如果减去intervl, fixBase后,新的minTick没有小于之前的值,就退出,防止死循环
|
||
|
||
while (minTick > min && (prevMinTick === null || minTick < prevMinTick)) {
|
||
// 保证计算出来的刻度最小值 minTick 不大于数据最小值 min
|
||
prevMinTick = minTick;
|
||
minTick = AutoUtil.fixedBase(minTick - interval, interval); // 防止超常浮点数计算问题
|
||
}
|
||
|
||
max = maxTick;
|
||
min = minTick;
|
||
}
|
||
|
||
max = Math.min(max, maxLimit);
|
||
min = Math.max(min, minLimit);
|
||
ticks.push(min);
|
||
|
||
for (var i = 1; i < count; i++) {
|
||
var tickValue = AutoUtil.fixedBase(interval * i + min, interval);
|
||
|
||
if (tickValue < max) {
|
||
ticks.push(tickValue);
|
||
}
|
||
}
|
||
|
||
if (ticks[ticks.length - 1] < max) {
|
||
ticks.push(max);
|
||
}
|
||
|
||
return {
|
||
min: min,
|
||
max: max,
|
||
interval: interval,
|
||
count: count,
|
||
ticks: ticks
|
||
};
|
||
}; |