@visactor/vscale
Version:
Scales for visual encoding, used in VGrammar, VTable
205 lines (190 loc) • 12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.forceStepTicksBaseTransform = exports.forceTicksBaseTransform = exports.ticksBaseTransform = exports.d3TicksForLog = exports.fixPrecision = exports.parseNiceOptions = exports.niceLinear = exports.stepTicks = exports.forceTickIncrement = exports.forceTicks = exports.tickIncrement = exports.ticks = exports.appendTicksToCount = exports.d3Ticks = exports.calculateTicksOfSingleValue = void 0;
const vutils_1 = require("@visactor/vutils"), utils_1 = require("./utils"), e10 = Math.sqrt(50), e5 = Math.sqrt(10), e2 = Math.sqrt(2), niceNumbers = [ 1, 2, 5, 10 ], calculateTicksOfSingleValue = (value, tickCount, noDecimals) => {
let step = 1, start = value;
const middleIndex = Math.floor((tickCount - 1) / 2), absVal = Math.abs(value);
return value >= 0 && value <= Number.MIN_VALUE ? start = 0 : value < 0 && value >= -Number.MIN_VALUE ? start = -(tickCount - 1) : !noDecimals && absVal < 1 ? step = getNickStep(absVal).step : (noDecimals || absVal > 1) && (start = Math.floor(value) - middleIndex * step),
step > 0 ? (value > 0 ? start = Math.max(start, 0) : value < 0 && (start = Math.min(start, -(tickCount - 1) * step)),
(0, vutils_1.range)(0, tickCount).map((index => start + index * step))) : value > 0 ? calculateTicksByStep(0, -(tickCount - 1) / step, step) : calculateTicksByStep((tickCount - 1) / step, 0, step);
};
exports.calculateTicksOfSingleValue = calculateTicksOfSingleValue, exports.d3Ticks = (0,
vutils_1.memoize)(((start, stop, count, options) => {
let reverse, n, ticks, step, i = -1;
if (count = +count, (start = +start) === (stop = +stop)) return [ start ];
if (Math.abs(start - stop) <= Number.MIN_VALUE && count > 0) return [ start ];
if ((reverse = stop < start) && (n = start, start = stop, stop = n), step = tickIncrement(start, stop, count).step,
!isFinite(step)) return [];
if (step > 0) {
let r0 = Math.round(start / step), r1 = Math.round(stop / step);
for (r0 * step < start && ++r0, r1 * step > stop && --r1, ticks = new Array(n = r1 - r0 + 1); ++i < n; ) ticks[i] = (r0 + i) * step;
} else if (step < 0 && (null == options ? void 0 : options.noDecimals)) {
step = 1;
const r0 = Math.ceil(start), r1 = Math.floor(stop);
if (!(r0 <= r1)) return [];
for (ticks = new Array(n = r1 - r0 + 1); ++i < n; ) ticks[i] = r0 + i;
} else {
step = -step;
let r0 = Math.round(start * step), r1 = Math.round(stop * step);
for (r0 / step < start && ++r0, r1 / step > stop && --r1, ticks = new Array(n = r1 - r0 + 1); ++i < n; ) ticks[i] = (r0 + i) / step;
}
return reverse && ticks.reverse(), ticks;
}));
const calculateTicksByStep = (start, stop, step) => {
let n, ticks, i = -1;
if (step > 0) {
let r0 = Math.floor(start / step), r1 = Math.ceil(stop / step);
for ((r0 + 1) * step < start && ++r0, (r1 - 1) * step > stop && --r1, ticks = new Array(n = r1 - r0 + 1); ++i < n; ) ticks[i] = (r0 + i) * step;
} else {
step = -step;
let r0 = Math.floor(start * step), r1 = Math.ceil(stop * step);
for ((r0 + 1) / step < start && ++r0, (r1 - 1) / step > stop && --r1, ticks = new Array(n = r1 - r0 + 1); ++i < n; ) ticks[i] = (r0 + i) / step;
}
return ticks;
}, appendTicksToCount = (ticks, count, step) => {
let n;
const firstTick = ticks[0], lastTick = ticks[ticks.length - 1], appendCount = count - ticks.length;
if (lastTick <= 0) {
const headTicks = [];
for (n = appendCount; n >= 1; n--) headTicks.push(firstTick - n * step);
return headTicks.concat(ticks);
}
if (firstTick >= 0) {
for (n = 1; n <= appendCount; n++) ticks.push(lastTick + n * step);
return ticks;
}
let headTicks = [];
const tailTicks = [];
for (n = 1; n <= appendCount; n++) n % 2 == 0 ? headTicks = [ firstTick - Math.floor(n / 2) * step ].concat(headTicks) : tailTicks.push(lastTick + Math.ceil(n / 2) * step);
return headTicks.concat(ticks).concat(tailTicks);
};
exports.appendTicksToCount = appendTicksToCount, exports.ticks = (0, vutils_1.memoize)(((start, stop, count, options) => {
let reverse, ticks, n;
if (count = +count, (start = +start) === (stop = +stop)) return (0, exports.calculateTicksOfSingleValue)(start, count, null == options ? void 0 : options.noDecimals);
if (Math.abs(start - stop) <= Number.MIN_VALUE && count > 0) return (0, exports.calculateTicksOfSingleValue)(start, count, null == options ? void 0 : options.noDecimals);
(reverse = stop < start) && (n = start, start = stop, stop = n);
const stepRes = tickIncrement(start, stop, count);
let step = stepRes.step;
if (!isFinite(step)) return [];
if (step > 0) {
let cur = 1;
const {power: power, gap: gap} = stepRes, delatStep = 10 === gap ? 2 * 10 ** power : 1 * 10 ** power;
for (;cur <= 5 && (ticks = calculateTicksByStep(start, stop, step), ticks.length > count + 1) && count > 2; ) step += delatStep,
cur += 1;
count > 2 && ticks.length < count - 1 && (ticks = (0, exports.appendTicksToCount)(ticks, count, step));
} else (null == options ? void 0 : options.noDecimals) && step < 0 && (step = 1),
ticks = calculateTicksByStep(start, stop, step);
return reverse && ticks.reverse(), ticks;
}));
const getNickStep = step => {
const power = Math.floor(Math.log(step) / Math.LN10), error = step / 10 ** power;
let gap = niceNumbers[0];
return error >= e10 ? gap = niceNumbers[3] : error >= e5 ? gap = niceNumbers[2] : error >= e2 && (gap = niceNumbers[1]),
power >= 0 ? {
step: gap * 10 ** power,
gap: gap,
power: power
} : {
step: -(10 ** -power) / gap,
gap: gap,
power: power
};
};
function tickIncrement(start, stop, count) {
const step = (stop - start) / Math.max(0, count);
return getNickStep(step);
}
function forceTicks(start, stop, count) {
let step;
if (count = +count, (start = +start) === (stop = +stop) && count > 0) return [ start ];
if (count <= 0 || 0 === (step = forceTickIncrement(start, stop, count)) || !isFinite(step)) return [];
const ticks = new Array(count);
for (let i = 0; i < count; i++) ticks[i] = start + i * step;
return ticks;
}
function forceTickIncrement(start, stop, count) {
return (stop - start) / Math.max(1, count - 1);
}
function stepTicks(start, stop, step) {
let n, reverse, i = -1;
if (step = +step, (reverse = (stop = +stop) < (start = +start)) && (n = start, start = stop,
stop = n), !isFinite(step) || stop - start <= step) return [ start ];
const count = Math.floor((stop - start) / step + 1), ticks = new Array(count);
for (;++i < count; ) ticks[i] = start + i * step;
return reverse && ticks.reverse(), ticks;
}
function niceLinear(d, count = 10) {
let prestep, step, i0 = 0, i1 = d.length - 1, start = d[i0], stop = d[i1], maxIter = 10;
for (stop < start && (step = start, start = stop, stop = step, step = i0, i0 = i1,
i1 = step); maxIter-- > 0; ) {
if (step = tickIncrement(start, stop, count).step, step === prestep) return d[i0] = start,
d[i1] = stop, d;
if (step > 0) start = Math.floor(start / step) * step, stop = Math.ceil(stop / step) * step; else {
if (!(step < 0)) break;
start = Math.ceil(start * step) / step, stop = Math.floor(stop * step) / step;
}
prestep = step;
}
}
function parseNiceOptions(originalDomain, option) {
const hasForceMin = (0, vutils_1.isNumber)(option.forceMin), hasForceMax = (0, vutils_1.isNumber)(option.forceMax);
let niceType = null;
const niceMinMax = [];
let niceDomain = null;
const domainValidator = hasForceMin && hasForceMax ? x => x >= option.forceMin && x <= option.forceMax : hasForceMin ? x => x >= option.forceMin : hasForceMax ? x => x <= option.forceMax : null;
return hasForceMin ? niceMinMax[0] = option.forceMin : (0, vutils_1.isNumber)(option.min) && option.min <= Math.min(originalDomain[0], originalDomain[originalDomain.length - 1]) && (niceMinMax[0] = option.min),
hasForceMax ? niceMinMax[1] = option.forceMax : (0, vutils_1.isNumber)(option.max) && option.max >= Math.max(originalDomain[0], originalDomain[originalDomain.length - 1]) && (niceMinMax[1] = option.max),
(0, vutils_1.isNumber)(niceMinMax[0]) && (0, vutils_1.isNumber)(niceMinMax[1]) ? (niceDomain = originalDomain.slice(),
niceDomain[0] = niceMinMax[0], niceDomain[niceDomain.length - 1] = niceMinMax[1]) : niceType = (0,
vutils_1.isNumber)(niceMinMax[0]) || (0, vutils_1.isNumber)(niceMinMax[1]) ? (0,
vutils_1.isNumber)(niceMinMax[0]) ? "max" : "min" : "all", {
niceType: niceType,
niceDomain: niceDomain,
niceMinMax: niceMinMax,
domainValidator: domainValidator
};
}
exports.tickIncrement = tickIncrement, exports.forceTicks = forceTicks, exports.forceTickIncrement = forceTickIncrement,
exports.stepTicks = stepTicks, exports.niceLinear = niceLinear, exports.parseNiceOptions = parseNiceOptions;
const fixPrecision = (start, stop, value) => Math.abs(stop - start) < 1 ? +value.toFixed(1) : Math.round(+value);
exports.fixPrecision = fixPrecision, exports.d3TicksForLog = (0, vutils_1.memoize)(((start, stop, count, base, transformer, untransformer, options) => {
let u = start, v = stop;
const r = v < u;
r && ([u, v] = [ v, u ]);
let k, t, i = transformer(u), j = transformer(v), z = [];
if (!(base % 1) && j - i < count) {
if (i = Math.floor(i), j = Math.ceil(j), u > 0) {
for (;i <= j; ++i) for (k = 1; k < base; ++k) if (t = i < 0 ? k / untransformer(-i) : k * untransformer(i),
!(t < u)) {
if (t > v) break;
z.push(t);
}
} else for (;i <= j; ++i) for (k = base - 1; k >= 1; --k) if (t = i > 0 ? k / untransformer(-i) : k * untransformer(i),
!(t < u)) {
if (t > v) break;
z.push(t);
}
2 * z.length < count && (z = (0, exports.ticks)(u, v, count));
} else z = (0, exports.ticks)(i, j, Math.min(j - i, count)).map(untransformer);
return z = z.filter((t => 0 !== t)), (null == options ? void 0 : options.noDecimals) && (z = Array.from(new Set(z.map((t => Math.floor(t)))))),
r ? z.reverse() : z;
})), exports.ticksBaseTransform = (0, vutils_1.memoize)(((start, stop, count, base, transformer, untransformer) => {
const ticksResult = [], ticksMap = {}, startExp = transformer(start), stopExp = transformer(stop);
let ticksExp = [];
if (Number.isInteger(base)) ticksExp = (0, exports.ticks)(startExp, stopExp, count); else {
const stepExp = (stopExp - startExp) / (count - 1);
for (let i = 0; i < count; i++) ticksExp.push(startExp + i * stepExp);
}
return ticksExp.forEach((tl => {
const power = untransformer(tl), nicePower = Number.isInteger(base) ? (0, exports.fixPrecision)(start, stop, power) : (0,
exports.fixPrecision)(start, stop, (0, utils_1.niceNumber)(power)), scopePower = (0,
exports.fixPrecision)(start, stop, (0, utils_1.restrictNumber)(nicePower, [ start, stop ]));
!ticksMap[scopePower] && !isNaN(scopePower) && ticksExp.length > 1 && (ticksMap[scopePower] = 1,
ticksResult.push(scopePower));
})), ticksResult;
})), exports.forceTicksBaseTransform = (0, vutils_1.memoize)(((start, stop, count, transformer, untransformer) => forceTicks(transformer(start), transformer(stop), count).map((te => (0,
utils_1.niceNumber)(untransformer(te)))))), exports.forceStepTicksBaseTransform = (0,
vutils_1.memoize)(((start, stop, step, transformer, untransformer) => stepTicks(transformer(start), transformer(stop), step).map((te => (0,
utils_1.niceNumber)(untransformer(te))))));
//# sourceMappingURL=tick-sample.js.map