Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interpolateNumberArray #77

Merged
merged 9 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 [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).

Based on the chosen interpolator, *a* is coerced to the suitable corresponding type.

Expand Down Expand Up @@ -92,12 +93,20 @@ Note: **no defensive copy** of the returned date is created; the same Date insta

<a name="interpolateArray" href="#interpolateArray">#</a> d3.<b>interpolateArray</b>(<i>a</i>, <i>b</i>) · [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), the interpolateNumberArray method is called instead.

<a name="interpolateNumberArray" href="#interpolateNumberArray">#</a> d3.<b>interpolateNumberArray</b>(<i>a</i>, <i>b</i>) · [Source](https://github.com/d3/d3-interpolate/blob/master/src/numberArray.js) <!-- , [Examples](https://observablehq.com/@d3/d3-interpolateobject) -->

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.

<a name="interpolateObject" href="#interpolateObject">#</a> d3.<b>interpolateObject</b>(<i>a</i>, <i>b</i>) · [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.
Expand Down
5 changes: 5 additions & 0 deletions src/array.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import value from "./value.js";
import numberArray, {isNumberArray} from "./numberArray.js";

export default function(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),
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
14 changes: 14 additions & 0 deletions src/numberArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function(a, b) {
if (!b) b = [];
var n = a ? Math.min(b.length, a.length) : 0,
c = b.slice(),
i;
return function(t) {
for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
return c;
};
}

export function isNumberArray(x) {
return ArrayBuffer.isView(x) && !(x instanceof DataView);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Just wanted to flag that typeof ArrayBuffer.isView === 'undefined' in PhantomJS. I know it's a super old browser and I'm not really expecting D3 to be perfectly compatible with it, but just commenting here in case someone else gets the same error. Thanks!

re: openstreetmap/iD#7072 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could test for it?

return ArrayBuffer.isView && ArrayBuffer.isView(x) && !(x instanceof DataView);

}
6 changes: 4 additions & 2 deletions src/value.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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";
import string from "./string.js";
import constant from "./constant.js";
import numberArray, {isNumberArray} from "./numberArray.js";

export default function(a, b) {
var t = typeof b, c;
Expand All @@ -14,7 +15,8 @@ export default function(a, b) {
: t === "string" ? ((c = color(b)) ? (b = c, rgb) : string)
: b instanceof color ? rgb
: b instanceof Date ? date
: Array.isArray(b) ? array
: isNumberArray(b) ? numberArray
: Array.isArray(b) ? genericArray
: typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
: number)(a, b);
}
44 changes: 44 additions & 0 deletions test/numberArray-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var tape = require("tape"),
interpolate = require("../");

tape("interpolateNumberArray(a, b) interpolates defined elements in a and b", function(test) {
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.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.of(2, 12), Float64Array.of(4, 24, 12))(0.5), Float64Array.of(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.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.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();
});
13 changes: 13 additions & 0 deletions test/value-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.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();
});


function noproto(properties, proto = null) {
return Object.assign(Object.create(proto), properties);
}
Expand Down