You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.3 KiB
114 lines
3.3 KiB
import {bisect} from "d3-array";
|
|
import {interpolate as interpolateValue, interpolateRound} from "d3-interpolate";
|
|
import {map, slice} from "./array";
|
|
import constant from "./constant";
|
|
import number from "./number";
|
|
|
|
var unit = [0, 1];
|
|
|
|
export function deinterpolateLinear(a, b) {
|
|
return (b -= (a = +a))
|
|
? function(x) { return (x - a) / b; }
|
|
: constant(b);
|
|
}
|
|
|
|
function deinterpolateClamp(deinterpolate) {
|
|
return function(a, b) {
|
|
var d = deinterpolate(a = +a, b = +b);
|
|
return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
|
|
};
|
|
}
|
|
|
|
function reinterpolateClamp(reinterpolate) {
|
|
return function(a, b) {
|
|
var r = reinterpolate(a = +a, b = +b);
|
|
return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
|
|
};
|
|
}
|
|
|
|
function bimap(domain, range, deinterpolate, reinterpolate) {
|
|
var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
|
|
if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
|
|
else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
|
|
return function(x) { return r0(d0(x)); };
|
|
}
|
|
|
|
function polymap(domain, range, deinterpolate, reinterpolate) {
|
|
var j = Math.min(domain.length, range.length) - 1,
|
|
d = new Array(j),
|
|
r = new Array(j),
|
|
i = -1;
|
|
|
|
// Reverse descending domains.
|
|
if (domain[j] < domain[0]) {
|
|
domain = domain.slice().reverse();
|
|
range = range.slice().reverse();
|
|
}
|
|
|
|
while (++i < j) {
|
|
d[i] = deinterpolate(domain[i], domain[i + 1]);
|
|
r[i] = reinterpolate(range[i], range[i + 1]);
|
|
}
|
|
|
|
return function(x) {
|
|
var i = bisect(domain, x, 1, j) - 1;
|
|
return r[i](d[i](x));
|
|
};
|
|
}
|
|
|
|
export function copy(source, target) {
|
|
return target
|
|
.domain(source.domain())
|
|
.range(source.range())
|
|
.interpolate(source.interpolate())
|
|
.clamp(source.clamp());
|
|
}
|
|
|
|
// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
|
|
// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
|
|
export default function continuous(deinterpolate, reinterpolate) {
|
|
var domain = unit,
|
|
range = unit,
|
|
interpolate = interpolateValue,
|
|
clamp = false,
|
|
piecewise,
|
|
output,
|
|
input;
|
|
|
|
function rescale() {
|
|
piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
|
|
output = input = null;
|
|
return scale;
|
|
}
|
|
|
|
function scale(x) {
|
|
return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);
|
|
}
|
|
|
|
scale.invert = function(y) {
|
|
return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
|
|
};
|
|
|
|
scale.domain = function(_) {
|
|
return arguments.length ? (domain = map.call(_, number), rescale()) : domain.slice();
|
|
};
|
|
|
|
scale.range = function(_) {
|
|
return arguments.length ? (range = slice.call(_), rescale()) : range.slice();
|
|
};
|
|
|
|
scale.rangeRound = function(_) {
|
|
return range = slice.call(_), interpolate = interpolateRound, rescale();
|
|
};
|
|
|
|
scale.clamp = function(_) {
|
|
return arguments.length ? (clamp = !!_, rescale()) : clamp;
|
|
};
|
|
|
|
scale.interpolate = function(_) {
|
|
return arguments.length ? (interpolate = _, rescale()) : interpolate;
|
|
};
|
|
|
|
return rescale();
|
|
}
|