From cb34407bcb29538740b4733d904aa92dd30ab3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 19 Nov 2019 19:46:25 +0100 Subject: [PATCH 1/9] interpolateNumberArray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - interpolates typed arrays (Float64Array, etc) and standard arrays that contain only numbers with a simple for… loop. - autodetects both situations (we could optionally unplug the number array detection) - not compatible with BigInt typed arrays (#75) --- README.md | 17 +++++++++++++---- src/array.js | 2 ++ src/index.js | 1 + src/numberArray.js | 15 +++++++++++++++ src/value.js | 2 ++ test/numberArray-test.js | 37 +++++++++++++++++++++++++++++++++++++ test/value-test.js | 13 +++++++++++++ 7 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/numberArray.js create mode 100644 test/numberArray-test.js diff --git a/README.md b/README.md index 73295ff..2a4756d 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,10 @@ Returns an interpolator between the two arbitrary values *a* and *b*. The interp 3. If *b* is a [color](https://github.com/d3/d3-color/blob/master/README.md#color) or a string coercible to a color, use [interpolateRgb](#interpolateRgb). 4. If *b* is a [date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), use [interpolateDate](#interpolateDate). 5. If *b* is a string, use [interpolateString](#interpolateString). -6. If *b* is an [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray), use [interpolateArray](#interpolateArray). -7. If *b* is coercible to a number, use [interpolateNumber](#interpolateNumber). -8. Use [interpolateObject](#interpolateObject). +6. If *b* is a number array (a [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) or an array containing only numbers, use [interpolateNumberArray](#interpolateNumberArray). +7. If *b* is a generic [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray), use [interpolateArray](#interpolateArray). +8. If *b* is coercible to a number, use [interpolateNumber](#interpolateNumber). +9. Use [interpolateObject](#interpolateObject). Based on the chosen interpolator, *a* is coerced to the suitable corresponding type. @@ -92,12 +93,20 @@ Note: **no defensive copy** of the returned date is created; the same Date insta # d3.interpolateArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/array.js), [Examples](https://observablehq.com/@d3/d3-interpolateobject) -Returns an interpolator between the two arrays *a* and *b*. Internally, an array template is created that is the same length in *b*. For each element in *b*, if there exists a corresponding element in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such element, the static value from *b* is used in the template. Then, for the given parameter *t*, the template’s embedded interpolators are evaluated. The updated array template is then returned. +Returns an interpolator between the two arrays *a* and *b*. Internally, an array template is created that is the same length as *b*. For each element in *b*, if there exists a corresponding element in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such element, the static value from *b* is used in the template. Then, for the given parameter *t*, the template’s embedded interpolators are evaluated. The updated array template is then returned. For example, if *a* is the array `[0, 1]` and *b* is the array `[1, 10, 100]`, then the result of the interpolator for *t* = 0.5 is the array `[0.5, 5.5, 100]`. Note: **no defensive copy** of the template array is created; modifications of the returned array may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition). +If the array is a typed array (Float64Array, etc) or contains only numbers, the interpolateNumberArray method is called instead. + +# d3.interpolateNumberArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js) + +Returns an interpolator between the two number arrays *a* and *b*. Internally, an array template is created that is the same type and length as *b*. For each element in *b*, if there exists a corresponding element in *a*, the values are directly interpolated in the array template. If there is no such element, the static value from *b* is copied. The updated array template is then returned. + +Note: For performance reasons, **no defensive copy** is made of the template array and the arguments *a* and *b*; modifications of these arrays may affect subsequent evaluation of the interpolator. + # d3.interpolateObject(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/object.js), [Examples](https://observablehq.com/@d3/d3-interpolateobject) Returns an interpolator between the two objects *a* and *b*. Internally, an object template is created that has the same properties as *b*. For each property in *b*, if there exists a corresponding property in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such property, the static value from *b* is used in the template. Then, for the given parameter *t*, the template's embedded interpolators are evaluated and the updated object template is then returned. diff --git a/src/array.js b/src/array.js index 9399bbe..719b360 100644 --- a/src/array.js +++ b/src/array.js @@ -1,6 +1,8 @@ import value from "./value.js"; +import {default as numberArray, isNumberArray} from "./numberArray.js"; export default function(a, b) { + if (isNumberArray(b)) return numberArray(a, b); var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), diff --git a/src/index.js b/src/index.js index 916bc1e..b4dce7d 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ export {default as interpolateDate} from "./date.js"; export {default as interpolateDiscrete} from "./discrete.js"; export {default as interpolateHue} from "./hue.js"; export {default as interpolateNumber} from "./number.js"; +export {default as interpolateNumberArray} from "./numberArray.js"; export {default as interpolateObject} from "./object.js"; export {default as interpolateRound} from "./round.js"; export {default as interpolateString} from "./string.js"; diff --git a/src/numberArray.js b/src/numberArray.js new file mode 100644 index 0000000..abfa100 --- /dev/null +++ b/src/numberArray.js @@ -0,0 +1,15 @@ +export default function(a, b) { + if (!b) b = []; + var na = a ? Math.min(b.length, a.length) : 0, + c = b.slice(); + let i; + return function(t) { + for (i = 0; i < na; ++i) c[i] = a[i] + (b[i] - a[i]) * t; + return c; + }; +} + +export function isNumberArray(x) { + if (ArrayBuffer.isView(x)) return !(x instanceof DataView); + return Array.isArray(x) && x.every(i => typeof i == "number"); +} diff --git a/src/value.js b/src/value.js index b2b8351..79327ff 100644 --- a/src/value.js +++ b/src/value.js @@ -6,6 +6,7 @@ import number from "./number.js"; import object from "./object.js"; import string from "./string.js"; import constant from "./constant.js"; +import {default as numberArray, isNumberArray} from "./numberArray.js"; export default function(a, b) { var t = typeof b, c; @@ -14,6 +15,7 @@ export default function(a, b) { : t === "string" ? ((c = color(b)) ? (b = c, rgb) : string) : b instanceof color ? rgb : b instanceof Date ? date + : isNumberArray(b) ? numberArray : Array.isArray(b) ? array : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : number)(a, b); diff --git a/test/numberArray-test.js b/test/numberArray-test.js new file mode 100644 index 0000000..ffa51a1 --- /dev/null +++ b/test/numberArray-test.js @@ -0,0 +1,37 @@ +var tape = require("tape"), + interpolate = require("../"); + +tape("interpolateNumberArray(a, b) interpolates defined elements in a and b", function(test) { + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24]))(0.5), Float64Array.from([3, 18])); + test.end(); +}); + +tape("interpolateNumberArray(a, b) ignores elements in a that are not in b", function(test) { + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12, 12]), Float64Array.from([4, 24]))(0.5), Float64Array.from([3, 18])); + test.end(); +}); + +tape("interpolateNumberArray(a, b) uses constant elements in b that are not in a", function(test) { + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24, 12]))(0.5), Float64Array.from([3, 18, 12])); + test.end(); +}); + +tape("interpolateNumberArray(a, b) treats undefined as an empty array", function(test) { + test.deepEqual(interpolate.interpolateNumberArray(undefined, [2, 12])(0.5), [2, 12]); + test.deepEqual(interpolate.interpolateNumberArray([2, 12], undefined)(0.5), []); + test.deepEqual(interpolate.interpolateNumberArray(undefined, undefined)(0.5), []); + test.end(); +}); + +tape("interpolateNumberArray(a, b) uses b’s array type", function(test) { + test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24, 12]))(0.5) instanceof Float64Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float32Array.from([4, 24, 12]))(0.5) instanceof Float32Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Uint8Array.from([4, 24, 12]))(0.5) instanceof Uint8Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Uint16Array.from([4, 24, 12]))(0.5) instanceof Uint16Array); + test.end(); +}); + +tape("interpolateNumberArray(a, b) works with unsigned data", function(test) { + test.deepEqual(interpolate.interpolateNumberArray(Uint8Array.from([1, 12]), Uint8Array.from([255, 0]))(0.5), Uint8Array.from([128, 6])); + test.end(); +}); \ No newline at end of file diff --git a/test/value-test.js b/test/value-test.js index 9bc0659..d23e649 100644 --- a/test/value-test.js +++ b/test/value-test.js @@ -115,6 +115,19 @@ tape("interpolate(a, b) interpolates objects with toString as objects if toStrin test.end(); }); +tape("interpolate(a, b) interpolates number arrays if b is a typed array", function(test) { + test.deepEqual(interpolate.interpolate([0, 0], Float64Array.from([-1, 1]))(0.5), Float64Array.from([-0.5, 0.5])); + test.assert(interpolate.interpolate([0, 0], Float64Array.from([-1, 1]))(0.5) instanceof Float64Array); + test.deepEqual(interpolate.interpolate([0, 0], Float32Array.from([-1, 1]))(0.5), Float32Array.from([-0.5, 0.5])); + test.assert(interpolate.interpolate([0, 0], Float32Array.from([-1, 1]))(0.5) instanceof Float32Array); + test.deepEqual(interpolate.interpolate([0, 0], Uint32Array.from([-2, 2]))(0.5), Uint32Array.from([Math.pow(2, 31) - 1, 1])); + test.assert(interpolate.interpolate([0, 0], Uint32Array.from([-1, 1]))(0.5) instanceof Uint32Array); + test.deepEqual(interpolate.interpolate([0, 0], Uint8Array.from([-2, 2]))(0.5), Uint8Array.from([Math.pow(2, 7) - 1, 1])); + test.assert(interpolate.interpolate([0, 0], Uint8Array.from([-1, 1]))(0.5) instanceof Uint8Array); + test.end(); +}); + + function noproto(properties, proto = null) { return Object.assign(Object.create(proto), properties); } From df8daefcabbadddaa76fb3a884932308df231655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 19 Nov 2019 21:55:31 +0100 Subject: [PATCH 2/9] style --- src/array.js | 2 +- src/value.js | 2 +- test/numberArray-test.js | 23 +++++++++++++++-------- test/value-test.js | 16 ++++++++-------- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/array.js b/src/array.js index 719b360..08e35d9 100644 --- a/src/array.js +++ b/src/array.js @@ -1,5 +1,5 @@ import value from "./value.js"; -import {default as numberArray, isNumberArray} from "./numberArray.js"; +import numberArray, {isNumberArray} from "./numberArray.js"; export default function(a, b) { if (isNumberArray(b)) return numberArray(a, b); diff --git a/src/value.js b/src/value.js index 79327ff..4a3ccee 100644 --- a/src/value.js +++ b/src/value.js @@ -6,7 +6,7 @@ import number from "./number.js"; import object from "./object.js"; import string from "./string.js"; import constant from "./constant.js"; -import {default as numberArray, isNumberArray} from "./numberArray.js"; +import numberArray, {isNumberArray} from "./numberArray.js"; export default function(a, b) { var t = typeof b, c; diff --git a/test/numberArray-test.js b/test/numberArray-test.js index ffa51a1..b749c0b 100644 --- a/test/numberArray-test.js +++ b/test/numberArray-test.js @@ -2,17 +2,17 @@ var tape = require("tape"), interpolate = require("../"); tape("interpolateNumberArray(a, b) interpolates defined elements in a and b", function(test) { - test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24]))(0.5), Float64Array.from([3, 18])); + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Float64Array.of(4, 24))(0.5), Float64Array.of(3, 18)); test.end(); }); tape("interpolateNumberArray(a, b) ignores elements in a that are not in b", function(test) { - test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12, 12]), Float64Array.from([4, 24]))(0.5), Float64Array.from([3, 18])); + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.of(2, 12, 12), Float64Array.of(4, 24))(0.5), Float64Array.of(3, 18)); test.end(); }); tape("interpolateNumberArray(a, b) uses constant elements in b that are not in a", function(test) { - test.deepEqual(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24, 12]))(0.5), Float64Array.from([3, 18, 12])); + test.deepEqual(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Float64Array.of(4, 24, 12))(0.5), Float64Array.of(3, 18, 12)); test.end(); }); @@ -24,14 +24,21 @@ tape("interpolateNumberArray(a, b) treats undefined as an empty array", function }); tape("interpolateNumberArray(a, b) uses b’s array type", function(test) { - test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float64Array.from([4, 24, 12]))(0.5) instanceof Float64Array); - test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Float32Array.from([4, 24, 12]))(0.5) instanceof Float32Array); - test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Uint8Array.from([4, 24, 12]))(0.5) instanceof Uint8Array); - test.ok(interpolate.interpolateNumberArray(Float64Array.from([2, 12]), Uint16Array.from([4, 24, 12]))(0.5) instanceof Uint16Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Float64Array.of(4, 24, 12))(0.5) instanceof Float64Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Float32Array.of(4, 24, 12))(0.5) instanceof Float32Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Uint8Array.of(4, 24, 12))(0.5) instanceof Uint8Array); + test.ok(interpolate.interpolateNumberArray(Float64Array.of(2, 12), Uint16Array.of(4, 24, 12))(0.5) instanceof Uint16Array); test.end(); }); tape("interpolateNumberArray(a, b) works with unsigned data", function(test) { - test.deepEqual(interpolate.interpolateNumberArray(Uint8Array.from([1, 12]), Uint8Array.from([255, 0]))(0.5), Uint8Array.from([128, 6])); + test.deepEqual(interpolate.interpolateNumberArray(Uint8Array.of(1, 12), Uint8Array.of(255, 0))(0.5), Uint8Array.of(128, 6)); + test.end(); +}); + +tape("interpolateNumberArray(a, b) gives exact ends", function(test) { + var i = interpolate.interpolateNumberArray(Float64Array.of(2e42), Float64Array.of(355)); + test.deepEqual(i(0), Float64Array.of(2e42)); + test.deepEqual(i(1), Float64Array.of(355)); test.end(); }); \ No newline at end of file diff --git a/test/value-test.js b/test/value-test.js index d23e649..752b054 100644 --- a/test/value-test.js +++ b/test/value-test.js @@ -116,14 +116,14 @@ tape("interpolate(a, b) interpolates objects with toString as objects if toStrin }); tape("interpolate(a, b) interpolates number arrays if b is a typed array", function(test) { - test.deepEqual(interpolate.interpolate([0, 0], Float64Array.from([-1, 1]))(0.5), Float64Array.from([-0.5, 0.5])); - test.assert(interpolate.interpolate([0, 0], Float64Array.from([-1, 1]))(0.5) instanceof Float64Array); - test.deepEqual(interpolate.interpolate([0, 0], Float32Array.from([-1, 1]))(0.5), Float32Array.from([-0.5, 0.5])); - test.assert(interpolate.interpolate([0, 0], Float32Array.from([-1, 1]))(0.5) instanceof Float32Array); - test.deepEqual(interpolate.interpolate([0, 0], Uint32Array.from([-2, 2]))(0.5), Uint32Array.from([Math.pow(2, 31) - 1, 1])); - test.assert(interpolate.interpolate([0, 0], Uint32Array.from([-1, 1]))(0.5) instanceof Uint32Array); - test.deepEqual(interpolate.interpolate([0, 0], Uint8Array.from([-2, 2]))(0.5), Uint8Array.from([Math.pow(2, 7) - 1, 1])); - test.assert(interpolate.interpolate([0, 0], Uint8Array.from([-1, 1]))(0.5) instanceof Uint8Array); + test.deepEqual(interpolate.interpolate([0, 0], Float64Array.of(-1, 1))(0.5), Float64Array.of(-0.5, 0.5)); + test.assert(interpolate.interpolate([0, 0], Float64Array.of(-1, 1))(0.5) instanceof Float64Array); + test.deepEqual(interpolate.interpolate([0, 0], Float32Array.of(-1, 1))(0.5), Float32Array.of(-0.5, 0.5)); + test.assert(interpolate.interpolate([0, 0], Float32Array.of(-1, 1))(0.5) instanceof Float32Array); + test.deepEqual(interpolate.interpolate([0, 0], Uint32Array.of(-2, 2))(0.5), Uint32Array.of(Math.pow(2, 31) - 1, 1)); + test.assert(interpolate.interpolate([0, 0], Uint32Array.of(-1, 1))(0.5) instanceof Uint32Array); + test.deepEqual(interpolate.interpolate([0, 0], Uint8Array.of(-2, 2))(0.5), Uint8Array.of(Math.pow(2, 7) - 1, 1)); + test.assert(interpolate.interpolate([0, 0], Uint8Array.of(-1, 1))(0.5) instanceof Uint8Array); test.end(); }); From 333f98d807436c20e3a58a47390aac848b19518f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 19 Nov 2019 21:56:06 +0100 Subject: [PATCH 3/9] var not let --- src/numberArray.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numberArray.js b/src/numberArray.js index abfa100..1e1efa1 100644 --- a/src/numberArray.js +++ b/src/numberArray.js @@ -1,8 +1,8 @@ export default function(a, b) { if (!b) b = []; var na = a ? Math.min(b.length, a.length) : 0, - c = b.slice(); - let i; + c = b.slice(), + i; return function(t) { for (i = 0; i < na; ++i) c[i] = a[i] + (b[i] - a[i]) * t; return c; From 5a32b88ede430913b0a785fee95c3a18694c50c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 19 Nov 2019 21:56:26 +0100 Subject: [PATCH 4/9] exact ends for interpolateNumberArray --- src/numberArray.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numberArray.js b/src/numberArray.js index 1e1efa1..83b1848 100644 --- a/src/numberArray.js +++ b/src/numberArray.js @@ -4,7 +4,7 @@ export default function(a, b) { c = b.slice(), i; return function(t) { - for (i = 0; i < na; ++i) c[i] = a[i] + (b[i] - a[i]) * t; + for (i = 0; i < na; ++i) c[i] = a[i] * (1 - t) + b[i] * t; return c; }; } From 9669bad88e76b50e813299eaa20abd1430053cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 19 Nov 2019 22:00:10 +0100 Subject: [PATCH 5/9] don't switch arrays of numbers from interpolateArray to interpolateNumberArray --- README.md | 4 ++-- src/numberArray.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2a4756d..c9cc917 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Returns an interpolator between the two arbitrary values *a* and *b*. The interp 3. If *b* is a [color](https://github.com/d3/d3-color/blob/master/README.md#color) or a string coercible to a color, use [interpolateRgb](#interpolateRgb). 4. If *b* is a [date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), use [interpolateDate](#interpolateDate). 5. If *b* is a string, use [interpolateString](#interpolateString). -6. If *b* is a number array (a [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) or an array containing only numbers, use [interpolateNumberArray](#interpolateNumberArray). +6. If *b* is a [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) of numbers, use [interpolateNumberArray](#interpolateNumberArray). 7. If *b* is a generic [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray), use [interpolateArray](#interpolateArray). 8. If *b* is coercible to a number, use [interpolateNumber](#interpolateNumber). 9. Use [interpolateObject](#interpolateObject). @@ -99,7 +99,7 @@ For example, if *a* is the array `[0, 1]` and *b* is the array `[1, 10, 100]`, t Note: **no defensive copy** of the template array is created; modifications of the returned array may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition). -If the array is a typed array (Float64Array, etc) or contains only numbers, the interpolateNumberArray method is called instead. +If the array is a typed array (Float64Array, etc), the interpolateNumberArray method is called instead. # d3.interpolateNumberArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js) diff --git a/src/numberArray.js b/src/numberArray.js index 83b1848..6715a46 100644 --- a/src/numberArray.js +++ b/src/numberArray.js @@ -10,6 +10,5 @@ export default function(a, b) { } export function isNumberArray(x) { - if (ArrayBuffer.isView(x)) return !(x instanceof DataView); - return Array.isArray(x) && x.every(i => typeof i == "number"); + return ArrayBuffer.isView(x) && !(x instanceof DataView); } From 24d1dea456996cf94860cdc16bb7ff898aaa30de Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Tue, 19 Nov 2019 14:40:43 -0800 Subject: [PATCH 6/9] Update numberArray.js --- src/numberArray.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/numberArray.js b/src/numberArray.js index 6715a46..4081086 100644 --- a/src/numberArray.js +++ b/src/numberArray.js @@ -1,10 +1,10 @@ export default function(a, b) { if (!b) b = []; - var na = a ? Math.min(b.length, a.length) : 0, - c = b.slice(), - i; + var n = a ? Math.min(b.length, a.length) : 0, + c = b.slice(), + i; return function(t) { - for (i = 0; i < na; ++i) c[i] = a[i] * (1 - t) + b[i] * t; + for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t; return c; }; } From ba015f032b8c1981e98be508cad0d87802610ed7 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Tue, 19 Nov 2019 14:48:46 -0800 Subject: [PATCH 7/9] Update array.js --- src/array.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/array.js b/src/array.js index 08e35d9..89f7722 100644 --- a/src/array.js +++ b/src/array.js @@ -2,7 +2,10 @@ import value from "./value.js"; import numberArray, {isNumberArray} from "./numberArray.js"; export default function(a, b) { - if (isNumberArray(b)) return numberArray(a, b); + return (isNumberArray(b) ? numberArray : genericArray)(a, b); +} + +export function genericArray(a, b) { var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), From d211ea7ea6a623802a31ecfbfcd1066a93d5bc90 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Tue, 19 Nov 2019 14:49:26 -0800 Subject: [PATCH 8/9] Avoid redundant isNumberArray call. --- src/value.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/value.js b/src/value.js index 4a3ccee..6a67ac4 100644 --- a/src/value.js +++ b/src/value.js @@ -1,6 +1,6 @@ import {color} from "d3-color"; import rgb from "./rgb.js"; -import array from "./array.js"; +import {genericArray} from "./array.js"; import date from "./date.js"; import number from "./number.js"; import object from "./object.js"; @@ -16,7 +16,7 @@ export default function(a, b) { : b instanceof color ? rgb : b instanceof Date ? date : isNumberArray(b) ? numberArray - : Array.isArray(b) ? array + : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : number)(a, b); } From 92e0bc71ac7bc4ec6008728fc147f74c29a5172b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Wed, 20 Nov 2019 10:39:51 +0100 Subject: [PATCH 9/9] examples notebook preview URL: https://observablehq.com/d/9b417e049e687a65 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9cc917..a634122 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Note: **no defensive copy** of the template array is created; modifications of t If the array is a typed array (Float64Array, etc), the interpolateNumberArray method is called instead. -# d3.interpolateNumberArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js) +# d3.interpolateNumberArray(a, b) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js), [Examples](https://observablehq.com/@d3/d3-interpolatenumberarray) Returns an interpolator between the two number arrays *a* and *b*. Internally, an array template is created that is the same type and length as *b*. For each element in *b*, if there exists a corresponding element in *a*, the values are directly interpolated in the array template. If there is no such element, the static value from *b* is copied. The updated array template is then returned.