@antv/scale
Version:
Toolkit for mapping abstract data into visual representation.
149 lines • 6.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Linear = void 0;
const util_1 = require("@antv/util");
const continuous_1 = require("./continuous");
const utils_1 = require("../utils");
const d3_ticks_1 = require("../tick-methods/d3-ticks");
const d3_linear_nice_1 = require("../utils/d3-linear-nice");
/**
* Linear 比例尺
*
* 构造可创建一个在输入和输出之间具有线性关系的比例尺
*/
class Linear extends continuous_1.Continuous {
getDefaultOptions() {
return {
domain: [0, 1],
range: [0, 1],
unknown: undefined,
nice: false,
clamp: false,
round: false,
interpolate: utils_1.createInterpolateValue,
tickMethod: d3_ticks_1.d3Ticks,
tickCount: 5,
};
}
removeUnsortedValues(breaksDomain, breaksRange, reverse) {
let pre = -Infinity;
const deleteIndices = breaksRange.reduce((acc, current, i) => {
if (i === 0)
return acc;
const value = pre > 0 ? pre : current;
if (pre > 0 && (reverse ? current > pre : current < pre)) {
acc.push(i);
}
else {
const diff = (value - breaksRange[i - 1]) * (reverse ? -1 : 1);
if (diff < 0) {
if (pre < 0)
pre = breaksRange[i - 1];
acc.push(i);
}
else {
pre = -Infinity;
}
}
return acc;
}, []);
deleteIndices
.slice()
.reverse()
.forEach((index) => {
breaksDomain.splice(index, 1);
breaksRange.splice(index, 1);
});
return { breaksDomain, breaksRange };
}
transformDomain(options) {
const RANGE_LIMIT = [0.2, 0.8];
const DEFAULT_GAP = 0.03;
const { domain = [], range = [1, 0], breaks = [], tickCount = 5, nice } = options;
const [min, max] = [Math.min(...domain), Math.max(...domain)];
let niceDomainMin = min;
let niceDomainMax = max;
if (nice && breaks.length < 2) {
const niceDomain = this.chooseNice()(min, max, tickCount);
niceDomainMin = niceDomain[0];
niceDomainMax = niceDomain[niceDomain.length - 1];
}
const domainMin = Math.min(niceDomainMin, min);
let domainMax = Math.max(niceDomainMax, max);
const sortedBreaks = breaks.filter(({ end }) => end < domainMax).sort((a, b) => a.start - b.start);
const breaksDomain = (0, d3_ticks_1.d3Ticks)(domainMin, domainMax, tickCount, sortedBreaks);
if ((0, util_1.last)(breaksDomain) < domainMax) {
const nicest = (0, d3_linear_nice_1.d3LinearNice)(0, domainMax - (0, util_1.last)(breaksDomain), 3);
breaksDomain.push((0, util_1.last)(breaksDomain) + (0, util_1.last)(nicest));
domainMax = (0, util_1.last)(breaksDomain);
}
const [r0, r1] = [range[0], (0, util_1.last)(range)];
const diffDomain = domainMax - domainMin;
const diffRange = Math.abs(r1 - r0);
const reverse = r0 > r1;
// Calculate the new range based on breaks.
const breaksRange = breaksDomain.map((d) => {
const ratio = (d - domainMin) / diffDomain;
return reverse ? r0 - ratio * diffRange : r0 + ratio * diffRange;
});
// Compress the range scale according to breaks.
const [MIN, MAX] = RANGE_LIMIT;
sortedBreaks.forEach(({ start, end, gap = DEFAULT_GAP, compress = 'middle' }) => {
const startIndex = breaksDomain.indexOf(start);
const endIndex = breaksDomain.indexOf(end);
let value = (breaksRange[startIndex] + breaksRange[endIndex]) / 2;
if (compress === 'start')
value = breaksRange[startIndex];
if (compress === 'end')
value = breaksRange[endIndex];
const halfSpan = (gap * diffRange) / 2;
// Calculate the new start and end values based on the center and scaled span.
let startValue = reverse ? value + halfSpan : value - halfSpan;
let endValue = reverse ? value - halfSpan : value + halfSpan;
// Ensure the new start and end values are within the defined limits.
if (startValue < MIN) {
endValue += MIN - startValue;
startValue = MIN;
}
if (endValue > MAX) {
startValue -= endValue - MAX;
endValue = MAX;
}
if (startValue > MAX) {
endValue -= startValue - MAX;
startValue = MAX;
}
if (endValue < MIN) {
startValue += MIN - endValue;
endValue = MIN;
}
breaksRange[startIndex] = startValue;
breaksRange[endIndex] = endValue;
});
return this.removeUnsortedValues(breaksDomain, breaksRange, reverse);
}
transformBreaks(options) {
const { domain, breaks = [] } = options;
if (!(0, util_1.isArray)(options.breaks))
return options;
const domainMax = Math.max(...domain);
const filteredBreaks = breaks.filter(({ end }) => end < domainMax);
const optWithFilteredBreaks = { ...options, breaks: filteredBreaks };
const { breaksDomain, breaksRange } = this.transformDomain(optWithFilteredBreaks);
return {
...options,
domain: breaksDomain,
range: breaksRange,
breaks: filteredBreaks,
tickMethod: () => [...breaksDomain],
};
}
chooseTransforms() {
return [util_1.identity, util_1.identity];
}
clone() {
return new Linear(this.options);
}
}
exports.Linear = Linear;
//# sourceMappingURL=linear.js.map