@@ -3,6 +3,7 @@ import {finite, positive} from "../defined.js";
3
3
import { identity , maybeNamed , number , valueof } from "../options.js" ;
4
4
import { coerceNumbers } from "../scales.js" ;
5
5
import { initializer } from "./basic.js" ;
6
+ import { facetReindex , getter } from "../facet.js" ;
6
7
7
8
const anchorXLeft = ( { marginLeft} ) => [ 1 , marginLeft ] ;
8
9
const anchorXRight = ( { width, marginRight} ) => [ - 1 , width - marginRight ] ;
@@ -90,21 +91,26 @@ function dodge(y, x, anchor, padding, options) {
90
91
return initializer ( options , function ( data , facets , { [ x ] : X , r : R } , scales , dimensions ) {
91
92
if ( ! X ) throw new Error ( `missing channel: ${ x } ` ) ;
92
93
X = coerceNumbers ( valueof ( X . value , scales [ X . scale ] || identity ) ) ;
94
+
95
+ // make facets exclusive
96
+ facets = facetReindex ( facets , data . length ) ;
97
+
93
98
const r = R ? undefined : this . r !== undefined ? this . r : options . r !== undefined ? number ( options . r ) : 3 ;
94
99
if ( R ) R = coerceNumbers ( valueof ( R . value , scales [ R . scale ] || identity ) ) ;
95
100
let [ ky , ty ] = anchor ( dimensions ) ;
96
101
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 ) ;
99
105
for ( let I of facets ) {
100
106
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 ) ) ) ;
102
108
const intervals = new Float64Array ( 2 * I . length + 2 ) ;
103
109
for ( const i of I ) {
104
110
const ri = radius ( i ) ;
105
111
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 ;
108
114
109
115
// The first two positions are 0 to test placing the dot on the baseline.
110
116
let k = 2 ;
@@ -114,8 +120,8 @@ function dodge(y, x, anchor, padding, options) {
114
120
// https://observablehq.com/@mbostock /circle-offset-along-line
115
121
tree . queryInterval ( l - padding , h + padding , ( [ , , j ] ) => {
116
122
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 ) ;
119
125
const dy = Math . sqrt ( dr * dr - dx * dx ) ;
120
126
intervals [ k ++ ] = yj - dy ;
121
127
intervals [ k ++ ] = yj + dy ;
0 commit comments