Skip to content

Commit 2f6ae0a

Browse files
authored
fix interning for facet anchors (#1515)
1 parent c284a10 commit 2f6ae0a

File tree

5 files changed

+11941
-27
lines changed

5 files changed

+11941
-27
lines changed

src/facet.js

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {InternMap, cross, rollup, sum} from "d3";
2-
import {range} from "./options.js";
2+
import {keyof, map, range} from "./options.js";
33
import {createScales} from "./scales.js";
44

55
// Returns an array of {x?, y?, i} objects representing the facet domain.
@@ -17,8 +17,8 @@ export function createFacets(channelsByScale, options) {
1717
}
1818

1919
export function recreateFacets(facets, {x: X, y: Y}) {
20-
X &&= new InternMap(X.map((x, i) => [x, i]));
21-
Y &&= new InternMap(Y.map((y, i) => [y, i]));
20+
X &&= facetIndex(X);
21+
Y &&= facetIndex(Y);
2222
return facets
2323
.filter(
2424
X && Y // remove any facets no longer present in the domain
@@ -110,56 +110,72 @@ export function maybeFacetAnchor(facetAnchor) {
110110
throw new Error(`invalid facet anchor: ${facetAnchor}`);
111111
}
112112

113+
const indexCache = new WeakMap();
114+
115+
function facetIndex(V) {
116+
let I = indexCache.get(V);
117+
if (!I) indexCache.set(V, (I = new InternMap(map(V, (v, i) => [v, i]))));
118+
return I;
119+
}
120+
121+
// Like V.indexOf(v), but with the same semantics as InternMap.
122+
function facetIndexOf(V, v) {
123+
return facetIndex(V).get(v);
124+
}
125+
126+
// Like facets.find, but with the same semantics as InternMap.
127+
function facetFind(facets, x, y) {
128+
x = keyof(x);
129+
y = keyof(y);
130+
return facets.find((f) => Object.is(keyof(f.x), x) && Object.is(keyof(f.y), y));
131+
}
132+
133+
function facetEmpty(facets, x, y) {
134+
return facetFind(facets, x, y)?.empty;
135+
}
136+
113137
function facetAnchorTop(facets, {y: Y}, {y}) {
114-
return Y ? Y.indexOf(y) === 0 : true;
138+
return Y ? facetIndexOf(Y, y) === 0 : true;
115139
}
116140

117141
function facetAnchorBottom(facets, {y: Y}, {y}) {
118-
return Y ? Y.indexOf(y) === Y.length - 1 : true;
142+
return Y ? facetIndexOf(Y, y) === Y.length - 1 : true;
119143
}
120144

121145
function facetAnchorLeft(facets, {x: X}, {x}) {
122-
return X ? X.indexOf(x) === 0 : true;
146+
return X ? facetIndexOf(X, x) === 0 : true;
123147
}
124148

125149
function facetAnchorRight(facets, {x: X}, {x}) {
126-
return X ? X.indexOf(x) === X.length - 1 : true;
150+
return X ? facetIndexOf(X, x) === X.length - 1 : true;
127151
}
128152

129153
function facetAnchorTopEmpty(facets, {y: Y}, {x, y, empty}) {
130154
if (empty) return false;
131-
const i = Y?.indexOf(y);
132-
if (i > 0) {
133-
const y = Y[i - 1];
134-
return facets.find((f) => f.x === x && f.y === y)?.empty;
135-
}
155+
if (!Y) return;
156+
const i = facetIndexOf(Y, y);
157+
if (i > 0) return facetEmpty(facets, x, Y[i - 1]);
136158
}
137159

138160
function facetAnchorBottomEmpty(facets, {y: Y}, {x, y, empty}) {
139161
if (empty) return false;
140-
const i = Y?.indexOf(y);
141-
if (i < Y?.length - 1) {
142-
const y = Y[i + 1];
143-
return facets.find((f) => f.x === x && f.y === y)?.empty;
144-
}
162+
if (!Y) return;
163+
const i = facetIndexOf(Y, y);
164+
if (i < Y.length - 1) return facetEmpty(facets, x, Y[i + 1]);
145165
}
146166

147167
function facetAnchorLeftEmpty(facets, {x: X}, {x, y, empty}) {
148168
if (empty) return false;
149-
const i = X?.indexOf(x);
150-
if (i > 0) {
151-
const x = X[i - 1];
152-
return facets.find((f) => f.x === x && f.y === y)?.empty;
153-
}
169+
if (!X) return;
170+
const i = facetIndexOf(X, x);
171+
if (i > 0) return facetEmpty(facets, X[i - 1], y);
154172
}
155173

156174
function facetAnchorRightEmpty(facets, {x: X}, {x, y, empty}) {
157175
if (empty) return false;
158-
const i = X?.indexOf(x);
159-
if (i < X?.length - 1) {
160-
const x = X[i + 1];
161-
return facets.find((f) => f.x === x && f.y === y)?.empty;
162-
}
176+
if (!X) return;
177+
const i = facetIndexOf(X, x);
178+
if (i < X.length - 1) return facetEmpty(facets, X[i + 1], y);
163179
}
164180

165181
function facetAnchorEmpty(facets, channels, {empty}) {

0 commit comments

Comments
 (0)