diff --git a/README.md b/README.md
index fb22105..c26acd5 100644
--- a/README.md
+++ b/README.md
@@ -216,6 +216,10 @@ var interpolator = d3.interpolateRgb.gamma(2.2)("purple", "orange");
See Eric Brasseur’s article, [Gamma error in picture scaling](https://web.archive.org/web/20160112115812/http://www.4p8.com/eric.brasseur/gamma.html), for more on gamma correction.
+# d3.interpolateHue(a, b) [<>](https://github.com/d3/d3-interpolate/blob/master/src/hue.js "Source")
+
+Returns an interpolator between the two hue angles *a* and *b*. If either hue is NaN, the opposing value is used. The shortest path between hues is used. The return value of the interpolator is a number in [0, 360).
+
### Splines
Whereas standard interpolators blend from a starting value *a* at *t* = 0 to an ending value *b* at *t* = 1, spline interpolators smoothly blend multiple input values for *t* in [0,1] using piecewise polynomial functions. Only cubic uniform nonrational [B-splines](https://en.wikipedia.org/wiki/B-spline) are currently supported, also known as basis splines.
diff --git a/d3-interpolate.sublime-project b/d3-interpolate.sublime-project
index 6e0c2d4..858fc1c 100644
--- a/d3-interpolate.sublime-project
+++ b/d3-interpolate.sublime-project
@@ -2,12 +2,16 @@
"folders": [
{
"path": ".",
- "file_exclude_patterns": [
- "*.sublime-workspace"
- ],
- "folder_exclude_patterns": [
- "build"
- ]
+ "file_exclude_patterns": ["*.sublime-workspace"],
+ "folder_exclude_patterns": ["build"]
+ }
+ ],
+ "build_systems": [
+ {
+ "name": "yarn test",
+ "cmd": ["yarn", "test"],
+ "file_regex": "\\((...*?):([0-9]*):([0-9]*)\\)",
+ "working_dir": "$project_path"
}
]
}
diff --git a/index.js b/index.js
index 6e05c67..fe2e492 100644
--- a/index.js
+++ b/index.js
@@ -4,6 +4,7 @@ export {default as interpolateBasis} from "./src/basis";
export {default as interpolateBasisClosed} from "./src/basisClosed";
export {default as interpolateDate} from "./src/date";
export {default as interpolateDiscrete} from "./src/discrete";
+export {default as interpolateHue} from "./src/hue";
export {default as interpolateNumber} from "./src/number";
export {default as interpolateObject} from "./src/object";
export {default as interpolateRound} from "./src/round";
diff --git a/src/hue.js b/src/hue.js
new file mode 100644
index 0000000..be5e189
--- /dev/null
+++ b/src/hue.js
@@ -0,0 +1,9 @@
+import {hue} from "./color";
+
+export default function(a, b) {
+ var i = hue(+a, +b);
+ return function(t) {
+ var x = i(t);
+ return x - 360 * Math.floor(x / 360);
+ };
+}
diff --git a/test/hue-test.js b/test/hue-test.js
new file mode 100644
index 0000000..aedee3d
--- /dev/null
+++ b/test/hue-test.js
@@ -0,0 +1,48 @@
+var tape = require("tape"),
+ interpolate = require("../");
+
+tape("interpolateHue(a, b) interpolate numbers", function(test) {
+ var i = interpolate.interpolateHue("10", "20");
+ test.strictEqual(i(0.0), 10);
+ test.strictEqual(i(0.2), 12);
+ test.strictEqual(i(0.4), 14);
+ test.strictEqual(i(0.6), 16);
+ test.strictEqual(i(0.8), 18);
+ test.strictEqual(i(1.0), 20);
+ test.end();
+});
+
+tape("interpolateHue(a, b) returns a if b is NaN", function(test) {
+ var i = interpolate.interpolateHue(10, NaN);
+ test.equal(i(0.0), 10);
+ test.equal(i(0.5), 10);
+ test.equal(i(1.0), 10);
+ test.end();
+});
+
+tape("interpolateHue(a, b) returns b if a is NaN", function(test) {
+ var i = interpolate.interpolateHue(NaN, 20);
+ test.equal(i(0.0), 20);
+ test.equal(i(0.5), 20);
+ test.equal(i(1.0), 20);
+ test.end();
+});
+
+tape("interpolateHue(a, b) returns NaN if both a and b are NaN", function(test) {
+ var i = interpolate.interpolateHue(NaN, NaN);
+ test.equal(isNaN(i(0.0)), true);
+ test.equal(isNaN(i(0.5)), true);
+ test.equal(isNaN(i(1.0)), true);
+ test.end();
+});
+
+tape("interpolateHue(a, b) uses the shortest path", function(test) {
+ var i = interpolate.interpolateHue(10, 350);
+ test.equal(i(0.0), 10);
+ test.equal(i(0.2), 6);
+ test.equal(i(0.4), 2);
+ test.equal(i(0.6), 358);
+ test.equal(i(0.8), 354);
+ test.equal(i(1.0), 350);
+ test.end();
+});