Skip to content

Commit 48115f9

Browse files
authored
avoid Array.from if possible (#888)
1 parent 3be866f commit 48115f9

File tree

8 files changed

+28
-22
lines changed

8 files changed

+28
-22
lines changed

src/channel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function valueObject(channels, scales) {
3131
for (const channelName in channels) {
3232
const {scale: scaleName, value} = channels[channelName];
3333
const scale = scales[scaleName];
34-
values[channelName] = scale === undefined ? value : Array.from(value, scale);
34+
values[channelName] = scale === undefined ? value : map(value, scale);
3535
}
3636
return values;
3737
}

src/legends/ramp.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {create, quantize, interpolateNumber, piecewise, format, scaleBand, scaleLinear, axisBottom} from "d3";
22
import {inferFontVariant} from "../axes.js";
3+
import {map} from "../options.js";
34
import {interpolatePiecewise} from "../scales/quantitative.js";
45
import {applyInlineStyles, impliedString, maybeClassName} from "../style.js";
56

@@ -115,7 +116,7 @@ export function legendRamp(color, {
115116
.attr("height", height - marginTop - marginBottom)
116117
.attr("fill", d => d);
117118

118-
ticks = Array.from(thresholds, (_, i) => i);
119+
ticks = map(thresholds, (_, i) => i);
119120
tickFormat = i => thresholdFormat(thresholds[i], i);
120121
}
121122

src/options.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ const objectToString = Object.prototype.toString;
77

88
// This allows transforms to behave equivalently to channels.
99
export function valueof(data, value, arrayType) {
10-
const array = arrayType === undefined ? Array : arrayType;
1110
const type = typeof value;
12-
return type === "string" ? array.from(data, field(value))
13-
: type === "function" ? array.from(data, value)
14-
: type === "number" || value instanceof Date || type === "boolean" ? array.from(data, constant(value))
11+
return type === "string" ? map(data, field(value), arrayType)
12+
: type === "function" ? map(data, value, arrayType)
13+
: type === "number" || value instanceof Date || type === "boolean" ? map(data, constant(value), arrayType)
1514
: value && typeof value.transform === "function" ? arrayify(value.transform(data), arrayType)
1615
: arrayify(value, arrayType); // preserve undefined type
1716
}
@@ -85,6 +84,12 @@ export function map(values, f, type = Array) {
8584
return values instanceof type ? values.map(f) : type.from(values, f);
8685
}
8786

87+
// An optimization of type.from(values): if the given values are already an
88+
// instanceof the desired array type, the faster values.slice method is used.
89+
export function slice(values, type = Array) {
90+
return values instanceof type ? values.slice() : type.from(values);
91+
}
92+
8893
export function isTypedArray(values) {
8994
return values instanceof TypedArray;
9095
}
@@ -149,7 +154,7 @@ export function where(data, test) {
149154

150155
// Returns an array [values[index[0]], values[index[1]], …].
151156
export function take(values, index) {
152-
return Array.from(index, i => values[i]);
157+
return map(index, i => values[i]);
153158
}
154159

155160
// Based on InternMap (d3.group).
@@ -201,8 +206,8 @@ export function mid(x1, x2) {
201206
const X1 = x1.transform(data);
202207
const X2 = x2.transform(data);
203208
return isTemporal(X1) || isTemporal(X2)
204-
? Array.from(X1, (_, i) => new Date((+X1[i] + +X2[i]) / 2))
205-
: Float64Array.from(X1, (_, i) => (+X1[i] + +X2[i]) / 2);
209+
? map(X1, (_, i) => new Date((+X1[i] + +X2[i]) / 2))
210+
: map(X1, (_, i) => (+X1[i] + +X2[i]) / 2, Float64Array);
206211
},
207212
label: x1.label
208213
};

src/plot.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {Channel, channelObject, channelDomain, channelSort, valueObject} from ".
44
import {defined} from "./defined.js";
55
import {Dimensions} from "./dimensions.js";
66
import {Legends, exposeLegends} from "./legends.js";
7-
import {arrayify, isOptions, isScaleOptions, keyword, range, second, where, yes} from "./options.js";
7+
import {arrayify, isOptions, isScaleOptions, keyword, map, range, second, where, yes} from "./options.js";
88
import {Scales, ScaleFunctions, autoScaleRange, exposeScales} from "./scales.js";
99
import {registry as scaleRegistry} from "./scales/index.js";
1010
import {applyInlineStyles, maybeClassName, maybeClip, styles} from "./style.js";
@@ -63,7 +63,7 @@ export function plot(options = {}) {
6363
}
6464
facetIndex = range(facetData);
6565
facets = facetGroups(facetIndex, facetChannels);
66-
facetsIndex = Array.from(facets, second);
66+
facetsIndex = facets.map(second);
6767
}
6868
}
6969

@@ -322,7 +322,7 @@ function applyScaleTransforms(channels, options) {
322322
const {scale} = channel;
323323
if (scale != null) {
324324
const {percent, transform = percent ? x => x * 100 : undefined} = options[scale] || {};
325-
if (transform != null) channel.value = Array.from(channel.value, transform);
325+
if (transform != null) channel.value = map(channel.value, transform);
326326
}
327327
}
328328
return channels;

src/scales.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {parse as isoParse} from "isoformat";
2-
import {isColor, isEvery, isOrdinal, isFirst, isTemporal, isTemporalString, isNumericString, isScaleOptions, isTypedArray, map, order} from "./options.js";
2+
import {isColor, isEvery, isOrdinal, isFirst, isTemporal, isTemporalString, isNumericString, isScaleOptions, isTypedArray, map, order, slice} from "./options.js";
33
import {registry, color, position, radius, opacity, symbol, length} from "./scales/index.js";
44
import {ScaleLinear, ScaleSqrt, ScalePow, ScaleLog, ScaleSymlog, ScaleQuantile, ScaleQuantize, ScaleThreshold, ScaleIdentity} from "./scales/quantitative.js";
55
import {ScaleDiverging, ScaleDivergingSqrt, ScaleDivergingPow, ScaleDivergingLog, ScaleDivergingSymlog} from "./scales/diverging.js";
@@ -417,8 +417,8 @@ function exposeScale({
417417
const unknown = scale.unknown ? scale.unknown() : undefined;
418418
return {
419419
type,
420-
domain: Array.from(domain), // defensive copy
421-
...range !== undefined && {range: Array.from(range)}, // defensive copy
420+
domain: slice(domain), // defensive copy
421+
...range !== undefined && {range: slice(range)}, // defensive copy
422422
...transform !== undefined && {transform},
423423
...percent && {percent}, // only exposed if truthy
424424
...label !== undefined && {label},

src/scales/ordinal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {InternSet, quantize, reverse as reverseof, sort, symbolsFill, symbolsStroke} from "d3";
22
import {scaleBand, scaleOrdinal, scalePoint, scaleImplicit} from "d3";
33
import {ascendingDefined} from "../defined.js";
4-
import {isNoneish} from "../options.js";
4+
import {isNoneish, map} from "../options.js";
55
import {maybeSymbol} from "../symbols.js";
66
import {registry, color, symbol} from "./index.js";
77
import {maybeBooleanRange, ordinalScheme, quantitativeScheme} from "./schemes.js";
@@ -41,7 +41,7 @@ export function ScaleOrdinal(key, channels, {
4141
let hint;
4242
if (registry.get(key) === symbol) {
4343
hint = inferSymbolHint(channels);
44-
range = range === undefined ? inferSymbolRange(hint) : Array.from(range, maybeSymbol);
44+
range = range === undefined ? inferSymbolRange(hint) : map(range, maybeSymbol);
4545
} else if (registry.get(key) === color) {
4646
if (range === undefined && (type === "ordinal" || type === ordinalImplicit)) {
4747
range = maybeBooleanRange(domain, scheme);

src/scales/quantitative.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
ticks
2525
} from "d3";
2626
import {positive, negative, finite} from "../defined.js";
27-
import {arrayify, constant, order} from "../options.js";
27+
import {arrayify, constant, order, slice} from "../options.js";
2828
import {ordinalRange, quantitativeScheme} from "./schemes.js";
2929
import {registry, radius, opacity, color, length} from "./index.js";
3030

@@ -94,7 +94,7 @@ export function ScaleQ(key, scale, channels, {
9494
if (zero) {
9595
const [min, max] = extent(domain);
9696
if ((min > 0) || (max < 0)) {
97-
domain = Array.from(domain);
97+
domain = slice(domain);
9898
if (order(domain) < 0) domain[domain.length - 1] = 0;
9999
else domain[0] = 0;
100100
}

src/transforms/interval.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {range} from "d3";
2-
import {isTemporal, labelof, maybeValue, valueof} from "../options.js";
2+
import {isTemporal, labelof, map, maybeValue, valueof} from "../options.js";
33
import {maybeInsetX, maybeInsetY} from "./inset.js";
44

55
// TODO Allow the interval to be specified as a string, e.g. “day” or “hour”?
@@ -46,7 +46,7 @@ function maybeIntervalK(k, maybeInsetK, options, trivial) {
4646
let D1, V1;
4747
function transform(data) {
4848
if (V1 !== undefined && data === D1) return V1; // memoize
49-
return V1 = Array.from(valueof(D1 = data, value), v => interval.floor(v));
49+
return V1 = map(valueof(D1 = data, value), v => interval.floor(v));
5050
}
5151
return maybeInsetK({
5252
...options,
@@ -65,7 +65,7 @@ function maybeIntervalMidK(k, maybeInsetK, options) {
6565
[k]: {
6666
label: labelof(v),
6767
transform: data => {
68-
const V1 = Array.from(valueof(data, value), v => interval.floor(v));
68+
const V1 = map(valueof(data, value), v => interval.floor(v));
6969
const V2 = V1.map(v => interval.offset(v));
7070
return V1.map(isTemporal(V1)
7171
? (v1, v2) => v1 == null || isNaN(v1 = +v1) || (v2 = V2[v2], v2 == null) || isNaN(v2 = +v2) ? undefined : new Date((v1 + v2) / 2)

0 commit comments

Comments
 (0)