/** * @fileOverview 使用度量,进行log转换 * @author dxq613@gmail.com */ const each = require('@antv/util/lib/each'); const Base = require('./base'); const Linear = require('./linear'); // 计算log function log(a, b) { if (a === 1) { return 1; } return Math.log(b) / Math.log(a); } /** * 度量的log计算 * @class Scale.Log */ class Log extends Linear { _initDefaultCfg() { super._initDefaultCfg(); this.type = 'log'; /** * @override * log 的坐标点的个数控制在10个以下 * @type {Number} */ this.tickCount = 10; /** * 进行log计算的基数 * @type {Number} */ this.base = 2; // 最小的tick,仅内部使用 this._minTick = null; } /** * @override */ calculateTicks() { const self = this; const base = self.base; let minTick; if (self.min < 0) { throw new Error('The minimum value must be greater than zero!'); } const maxTick = log(base, self.max); if (self.min > 0) { minTick = Math.floor(log(base, self.min)); } else { const values = self.values; let positiveMin = self.max; // 查找大于0的第一个值, 如果都小于0,默认为1 each(values, value => { if (value > 0 && value < positiveMin) { positiveMin = value; } }); if (positiveMin === self.max) { positiveMin = self.max / base; } if (positiveMin > 1) { positiveMin = 1; } minTick = Math.floor(log(base, positiveMin)); self._minTick = minTick; self.positiveMin = positiveMin; } const count = maxTick - minTick; const tickCount = self.tickCount; const avg = Math.ceil(count / tickCount); const ticks = []; for (let i = minTick; i < maxTick + avg; i = i + avg) { ticks.push(Math.pow(base, i)); } if (self.min === 0) { ticks.unshift(0); } return ticks; } // 获取度量计算时,value占的定义域百分比 _getScalePercent(value) { const max = this.max; let min = this.min; if (max === min) { return 0; } // 如果值小于等于0,则按照0处理 if (value <= 0) { return 0; } const base = this.base; const positiveMin = this.positiveMin; // 如果min == 0, 则根据比0大的最小值,计算比例关系。这个最小值作为坐标轴上的第二个tick,第一个是0但是不显示 if (positiveMin) { min = positiveMin * 1 / base; } let percent; // 如果数值小于次小值,那么就计算 value / 次小值 占整体的比例 if (value < positiveMin) { percent = (value / positiveMin) / (log(base, max) - log(base, min)); } else { percent = (log(base, value) - log(base, min)) / (log(base, max) - log(base, min)); } return percent; } /** * @override */ scale(value) { const percent = this._getScalePercent(value); const rangeMin = this.rangeMin(); const rangeMax = this.rangeMax(); return rangeMin + percent * (rangeMax - rangeMin); } /** * @override */ invert(value) { const base = this.base; const max = log(base, this.max); const rangeMin = this.rangeMin(); const range = (this.rangeMax() - rangeMin); let min; const positiveMin = this.positiveMin; if (positiveMin) { if (value === 0) { return 0; } min = log(base, positiveMin / base); const appendPercent = (1 / (max - min)) * range; // 0 到 positiveMin的占比 if (value < appendPercent) { // 落到 0 - positiveMin 之间 return value / appendPercent * positiveMin; } } else { min = log(base, this.min); } const percent = (value - rangeMin) / (range); const tmp = percent * (max - min) + min; return Math.pow(base, tmp); } } Base.Log = Log; module.exports = Log;