Skip to content

Commit 7999256

Browse files
committed
exclusive facets on the dodge transform
1 parent f6e7636 commit 7999256

File tree

4 files changed

+771
-7
lines changed

4 files changed

+771
-7
lines changed

src/transforms/dodge.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {finite, positive} from "../defined.js";
33
import {identity, maybeNamed, number, valueof} from "../options.js";
44
import {coerceNumbers} from "../scales.js";
55
import {initializer} from "./basic.js";
6+
import {facetReindex, getter} from "../facet.js";
67

78
const anchorXLeft = ({marginLeft}) => [1, marginLeft];
89
const anchorXRight = ({width, marginRight}) => [-1, width - marginRight];
@@ -90,21 +91,26 @@ function dodge(y, x, anchor, padding, options) {
9091
return initializer(options, function (data, facets, {[x]: X, r: R}, scales, dimensions) {
9192
if (!X) throw new Error(`missing channel: ${x}`);
9293
X = coerceNumbers(valueof(X.value, scales[X.scale] || identity));
94+
95+
// make facets exclusive
96+
facets = facetReindex(facets, data.length);
97+
9398
const r = R ? undefined : this.r !== undefined ? this.r : options.r !== undefined ? number(options.r) : 3;
9499
if (R) R = coerceNumbers(valueof(R.value, scales[R.scale] || identity));
95100
let [ky, ty] = anchor(dimensions);
96101
const compare = ky ? compareAscending : compareSymmetric;
97-
const Y = new Float64Array(X.length);
98-
const radius = R ? (i) => R[i] : () => r;
102+
const Y = new Float64Array((facets.plan || X).length);
103+
const radius = R ? getter(facets, R) : () => r;
104+
const getX = getter(facets, X);
99105
for (let I of facets) {
100106
const tree = IntervalTree();
101-
I = I.filter(R ? (i) => finite(X[i]) && positive(R[i]) : (i) => finite(X[i]));
107+
I = I.filter(R ? (i) => finite(getX(i)) && positive(radius(i)) : (i) => finite(getX(i)));
102108
const intervals = new Float64Array(2 * I.length + 2);
103109
for (const i of I) {
104110
const ri = radius(i);
105111
const y0 = ky ? ri + padding : 0; // offset baseline for varying radius
106-
const l = X[i] - ri;
107-
const h = X[i] + ri;
112+
const l = getX(i) - ri;
113+
const h = getX(i) + ri;
108114

109115
// The first two positions are 0 to test placing the dot on the baseline.
110116
let k = 2;
@@ -114,8 +120,8 @@ function dodge(y, x, anchor, padding, options) {
114120
// https://observablehq.com/@mbostock/circle-offset-along-line
115121
tree.queryInterval(l - padding, h + padding, ([, , j]) => {
116122
const yj = Y[j] - y0;
117-
const dx = X[i] - X[j];
118-
const dr = padding + (R ? R[i] + R[j] : 2 * r);
123+
const dx = getX(i) - getX(j);
124+
const dr = padding + (R ? radius(i) + radius(j) : 2 * r);
119125
const dy = Math.sqrt(dr * dr - dx * dx);
120126
intervals[k++] = yj - dy;
121127
intervals[k++] = yj + dy;

0 commit comments

Comments
 (0)