UNPKG

@visactor/vscale

Version:

Scales for visual encoding, used in VGrammar, VTable

205 lines (190 loc) 12 kB
"use strict"; 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