UNPKG

@antv/f2

Version:

Charts for mobile visualization.

157 lines (136 loc) 4.51 kB
// 认为是nice的刻度 const SNAP_COUNT_ARRAY = [1, 1.2, 1.5, 2, 2.2, 2.4, 2.5, 3, 4, 5, 6, 7.5, 8, 10]; const DEFAULT_COUNT = 5; // 默认刻度值 export default (cfg) => { const { tickCount, tickInterval } = cfg || {}; let { min, max } = cfg || {}; min = isNaN(min) ? 0 : min; max = isNaN(max) ? 0 : max; let count = tickCount && tickCount >= 2 ? tickCount : DEFAULT_COUNT; // 计算interval, 优先取tickInterval const interval = tickInterval || getBestInterval({ tickCount: count, max, min }); // 通过interval计算最小tick const minTick = Math.floor(min / interval) * interval; // 如果指定了tickInterval, count 需要根据指定的tickInterval来算计 if (tickInterval) { const intervalCount = Math.abs(Math.ceil((max - minTick) / tickInterval)) + 1; // tickCount 作为最小 count 处理 count = Math.max(count, intervalCount); } let tickLength = 0; const fixedLength = getFixedLength(interval); if (min < 0 && max > 0 && count === 2) { return [ toFixed(minTick, fixedLength), toFixed(Math.ceil(max / interval) * interval, fixedLength), ]; } const ticks = []; while (tickLength < count) { ticks.push(toFixed(minTick + tickLength * interval, fixedLength)); tickLength++; } return ticks; }; const DECIMAL_LENGTH = 12; function getFactor(number) { // 取正数 number = Math.abs(number); let factor = 1; if (number === 0) { return factor; } // 小于1,逐渐放大 if (number < 1) { let count = 0; while (number < 1) { factor = factor / 10; number = number * 10; count++; } // 浮点数计算出现问题 if (factor.toString().length > DECIMAL_LENGTH) { factor = parseFloat(factor.toFixed(count)); } return factor; } // 大于10逐渐缩小 while (number > 10) { factor = factor * 10; number = number / 10; } return factor; } // 获取最佳匹配刻度 function getBestInterval({ tickCount, min, max }) { // 如果最大最小相等,则直接按1处理 if (min === max) { return 1 * getFactor(max); } // 1.计算平均刻度间隔 const avgInterval = (max - min) / (tickCount - 1); // 2.数据标准归一化 映射到[1-10]区间 const factor = getFactor(avgInterval); const calInterval = avgInterval / factor; const calMax = max / factor; const calMin = min / factor; // 根据平均值推算最逼近刻度值 let similarityIndex = 0; for (let index = 0; index < SNAP_COUNT_ARRAY.length; index++) { const item = SNAP_COUNT_ARRAY[index]; if (calInterval <= item) { similarityIndex = index; break; } } const similarityInterval = min < 0 && max > 0 && tickCount === 2 ? SNAP_COUNT_ARRAY[similarityIndex] : getInterval(similarityIndex, tickCount, calMin, calMax); // 小数点位数还原到数据的位数, 因为similarityIndex有可能是小数,所以需要保留similarityIndex自己的小数位数 const fixedLength = getFixedLength(similarityInterval) + getFixedLength(factor); return toFixed(similarityInterval * factor, fixedLength); } function getInterval(startIndex, tickCount, min, max) { let verify = false; let interval = SNAP_COUNT_ARRAY[startIndex]; // 刻度值校验,如果不满足,循环下去 for (let i = startIndex; i < SNAP_COUNT_ARRAY.length; i++) { if (intervalIsVerify({ interval: SNAP_COUNT_ARRAY[i], tickCount, max, min })) { // 有符合条件的interval interval = SNAP_COUNT_ARRAY[i]; verify = true; break; } } // 如果不满足, 依次缩小10倍,再计算 if (!verify) { return 10 * getInterval(0, tickCount, min / 10, max / 10); } return interval; } // 刻度是否满足展示需求 function intervalIsVerify({ interval, tickCount, max, min }) { const minTick = Math.floor(min / interval) * interval; if (minTick + (tickCount - 1) * interval >= max) { return true; } return false; } // 计算小数点应该保留的位数 function getFixedLength(num) { const str = num.toString(); const index = str.indexOf('.'); const indexOfExp = str.indexOf('e-'); let length = indexOfExp >= 0 ? parseInt(str.substr(indexOfExp + 2), 10) : str.substr(index + 1).length; if (length > 20) { // 最多保留20位小数 length = 20; } return length; } // @antv/util fixedbase不支持科学计数法的判断,需要提mr function toFixed(v, length) { return parseFloat(v.toFixed(length)); }