diff --git a/README.md b/README.md
index 0dc694b..668baee 100644
--- a/README.md
+++ b/README.md
@@ -573,6 +573,10 @@ See [*continuous*.clamp](#continuous_clamp).
If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+# sequential.invert(fraction) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js)
+
+Inverts the given interpolation *fraction* and returns the corresponding domain value. This method does not invert the output of the interpolator function (which may be non-invertible), but rather inverts fractional values that serve as input to the interpolator.
+
# sequential.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/sequential.js), [Examples](https://observablehq.com/@d3/sequential-scales)
See [*continuous*.range](#continuous_range). If *range* is specified, implicitly uses [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) as the interpolator.
@@ -637,6 +641,10 @@ See [*continuous*.clamp](#continuous_clamp).
If *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.
+# diverging.invert(fraction) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js)
+
+Inverts the given interpolation *fraction* and returns the corresponding domain value. This method does not invert the output of the interpolator function (which may be non-invertible), but rather inverts fractional values that serve as input to the interpolator.
+
# diverging.range([range]) · [Source](https://github.com/d3/d3-scale/blob/master/src/diverging.js), [Examples](https://observablehq.com/@d3/diverging-scales)
See [*continuous*.range](#continuous_range). If *range* is specified, implicitly uses [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) as the interpolator.
diff --git a/src/diverging.js b/src/diverging.js
index f590748..5d646db 100644
--- a/src/diverging.js
+++ b/src/diverging.js
@@ -19,6 +19,7 @@ function transformer() {
k21,
interpolator = identity,
transform,
+ untransform,
clamp = false,
unknown;
@@ -26,6 +27,12 @@ function transformer() {
return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (s * x < s * t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
}
+ scale.invert = function(_) {
+ _ = clamp ? Math.max(0, Math.min(1, _)) : _;
+ return _ === 0 ? x0 : _ === 1 ? x2 : _ === 0.5 ? x1
+ : untransform((_ - 0.5) / (_ < 0.5 ? k10 : k21) + t1);
+ };
+
scale.domain = function(_) {
return arguments.length ? ([x0, x1, x2] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), t2 = transform(x2 = +x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1, scale) : [x0, x1, x2];
};
@@ -53,14 +60,14 @@ function transformer() {
return arguments.length ? (unknown = _, scale) : unknown;
};
- return function(t) {
- transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1;
+ return function(t, u) {
+ transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1, untransform = u;
return scale;
};
}
export default function diverging() {
- var scale = linearish(transformer()(identity));
+ var scale = linearish(transformer()(identity, identity));
scale.copy = function() {
return copy(scale, diverging());
diff --git a/src/sequential.js b/src/sequential.js
index bd38dba..5c707ac 100644
--- a/src/sequential.js
+++ b/src/sequential.js
@@ -13,6 +13,7 @@ function transformer() {
t1,
k10,
transform,
+ untransform,
interpolator = identity,
clamp = false,
unknown;
@@ -21,6 +22,11 @@ function transformer() {
return isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
}
+ scale.invert = function(_) {
+ _ = clamp ? Math.max(0, Math.min(1, _)) : _;
+ return _ === 0 ? x0 : _ === 1 ? x1 : untransform(_ / k10 + t0);
+ };
+
scale.domain = function(_) {
return arguments.length ? ([x0, x1] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1];
};
@@ -48,8 +54,8 @@ function transformer() {
return arguments.length ? (unknown = _, scale) : unknown;
};
- return function(t) {
- transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0);
+ return function(t, u) {
+ transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), untransform = u;
return scale;
};
}
@@ -63,7 +69,7 @@ export function copy(source, target) {
}
export default function sequential() {
- var scale = linearish(transformer()(identity));
+ var scale = linearish(transformer()(identity, identity));
scale.copy = function() {
return copy(scale, sequential());
diff --git a/test/diverging-test.js b/test/diverging-test.js
index 5e7f5c0..116a901 100644
--- a/test/diverging-test.js
+++ b/test/diverging-test.js
@@ -162,3 +162,28 @@ tape("scaleDiverging(range) sets the interpolator", function(test) {
test.deepEqual(s.range(), [1, 3, 10]);
test.end();
});
+
+tape("scaleDiverging.invert(value) inverts interpolation fractions", function(test) {
+ var s = scale.scaleDiverging().domain([1,2,4]);
+ test.equal(s.invert(0), 1);
+ test.equal(s.invert(0.25), 1.5);
+ test.equal(s.invert(0.50), 2);
+ test.equal(s.invert(0.75), 3);
+ test.equal(s.invert(1), 4);
+ test.equal(s.invert(-0.5), 0);
+ test.equal(s.invert(1.5), 6);
+ test.end();
+});
+
+tape("scaleDivergingLog.invert(value) inverts interpolation fractions", function(test) {
+ var d = [1, 20, 100];
+ var s = scale.scaleDivergingLog().domain(d);
+ test.equal(s.invert(0), d[0]);
+ test.equal(s.invert(0.25), Math.exp(Math.log(d[0]) + 0.5 * (Math.log(d[1]) - Math.log(d[0]))));
+ test.equal(s.invert(0.50), d[1]);
+ test.equal(s.invert(0.75), Math.exp(Math.log(d[1]) + 0.5 * (Math.log(d[2]) - Math.log(d[1]))));
+ test.equal(s.invert(1), d[2]);
+ test.inDelta(s.invert(-0.5), Math.exp(Math.log(d[0]) - 1 * (Math.log(d[1]) - Math.log(d[0]))));
+ test.inDelta(s.invert(1.5), Math.exp(Math.log(d[1]) + 2 * (Math.log(d[2]) - Math.log(d[1]))));
+ test.end();
+});
\ No newline at end of file
diff --git a/test/sequential-test.js b/test/sequential-test.js
index 9ba7837..4c5bd19 100644
--- a/test/sequential-test.js
+++ b/test/sequential-test.js
@@ -131,3 +131,28 @@ tape("scaleSequential(range) sets the interpolator", function(test) {
test.deepEqual(s.range(), [1, 3]);
test.end();
});
+
+tape("scaleSequential.invert(value) inverts interpolation fractions", function(test) {
+ var s = scale.scaleSequential().domain([1,5]);
+ test.equal(s.invert(0), 1);
+ test.equal(s.invert(0.25), 2);
+ test.equal(s.invert(0.50), 3);
+ test.equal(s.invert(0.75), 4);
+ test.equal(s.invert(1), 5);
+ test.equal(s.invert(-1), -3);
+ test.equal(s.invert(2), 9);
+ test.end();
+});
+
+tape("scaleSequentialLog.invert(value) inverts interpolation fractions", function(test) {
+ var d = [1, 100];
+ var s = scale.scaleSequentialLog().domain(d);
+ test.equal(s.invert(0), d[0]);
+ test.equal(s.invert(0.25), Math.exp(Math.log(d[0]) + 0.25 * (Math.log(d[1]) - Math.log(d[0]))));
+ test.equal(s.invert(0.50), Math.exp(Math.log(d[0]) + 0.50 * (Math.log(d[1]) - Math.log(d[0]))));
+ test.equal(s.invert(0.75), Math.exp(Math.log(d[0]) + 0.75 * (Math.log(d[1]) - Math.log(d[0]))));
+ test.equal(s.invert(1), d[1]);
+ test.inDelta(s.invert(-1), d[0] / d[1]);
+ test.inDelta(s.invert(2), d[1] * d[1]);
+ test.end();
+});