1
1
import { create , namespaces , pointer as pointerof , quickselect , union } from "d3" ;
2
- import { identity , maybeFrameAnchor , maybeTuple } from "../options.js" ;
2
+ import { identity , maybeTuple } from "../options.js" ;
3
3
import { Mark } from "../plot.js" ;
4
4
import { selection } from "../selection.js" ;
5
- import { applyDirectStyles , applyFrameAnchor , applyIndirectStyles } from "../style.js" ;
5
+ import { applyDirectStyles , applyIndirectStyles } from "../style.js" ;
6
6
7
7
const defaults = {
8
8
ariaLabel : "pointer" ,
@@ -15,10 +15,9 @@ export class Pointer extends Mark {
15
15
constructor ( data , {
16
16
x,
17
17
y,
18
- n = Infinity ,
18
+ n = 1 ,
19
19
r = isFinite ( n ) ? 120 : 20 ,
20
20
mode = "auto" ,
21
- frameAnchor,
22
21
...options
23
22
} = { } ) {
24
23
super (
@@ -33,12 +32,10 @@ export class Pointer extends Mark {
33
32
this . n = + n ;
34
33
this . r = + r ;
35
34
this . mode = maybeMode ( mode , x , y ) ;
36
- this . frameAnchor = maybeFrameAnchor ( frameAnchor ) ;
37
35
}
38
- render ( index , scales , { x : X , y : Y } , dimensions ) {
36
+ render ( index , { x , y } , { x : X , y : Y } , dimensions ) {
39
37
const { marginLeft, width, marginRight, marginTop, height, marginBottom} = dimensions ;
40
38
const { mode, n, r} = this ;
41
- const [ cx , cy ] = applyFrameAnchor ( this , dimensions ) ;
42
39
const r2 = r * r ; // the squared radius; to determine points in proximity to the pointer
43
40
const down = new Set ( ) ; // the set of pointers that are currently down
44
41
let C = [ ] ; // a sparse index from index[i] to an svg:circle element
@@ -63,11 +60,14 @@ export class Pointer extends Mark {
63
60
S . forEach ( i => {
64
61
let c = C [ i ] ;
65
62
if ( ! c ) {
66
- c = document . createElementNS ( namespaces . svg , "circle" ) ;
67
- c . setAttribute ( "id" , i ) ;
68
- c . setAttribute ( "r" , 4 ) ;
69
- c . setAttribute ( "cx" , X ? X [ i ] : cx ) ;
70
- c . setAttribute ( "cy" , Y ? Y [ i ] : cy ) ;
63
+ c = X && Y ? ( x . bandwidth && y . bandwidth ? element ( "rect" , { x : X [ i ] , y : Y [ i ] , width : x . bandwidth ( ) , height : y . bandwidth ( ) } )
64
+ : x . bandwidth ? element ( "line" , { x1 : X [ i ] , x2 : X [ i ] + x . bandwidth ( ) , y1 : Y [ i ] , y2 : Y [ i ] } )
65
+ : y . bandwidth ? element ( "line" , { x1 : X [ i ] , x2 : X [ i ] , y1 : Y [ i ] , y2 : Y [ i ] + y . bandwidth ( ) } )
66
+ : element ( "circle" , { cx : X [ i ] , cy : Y [ i ] , r : 4 } ) )
67
+ : X ? ( x . bandwidth ? element ( "rect" , { x : X [ i ] , y : marginTop , width : x . bandwidth ( ) , height : height - marginBottom - marginTop } )
68
+ : element ( "line" , { x1 : X [ i ] , x2 : X [ i ] , y1 : marginTop , y2 : height - marginBottom } ) )
69
+ : ( y . bandwidth ? element ( "rect" , { x : marginLeft , y : Y [ i ] , width : width - marginRight - marginLeft , height : y . bandwidth ( ) } )
70
+ : element ( "line" , { y1 : Y [ i ] , y2 : Y [ i ] , x1 : marginLeft , x2 : width - marginRight } ) ) ;
71
71
parent . appendChild ( c ) ;
72
72
changed = true ;
73
73
}
@@ -119,11 +119,16 @@ export class Pointer extends Mark {
119
119
// If any pointer is down, only consider pointers that are down.
120
120
if ( P && ! down . has ( event . pointerId ) ) return ;
121
121
122
+ // Adjust the pointer to account for band scales; for band scales, the
123
+ // data is mapped to the start of the band (e.g., a bar’s left edge).
124
+ let [ mx , my ] = pointerof ( event ) ;
125
+ if ( x . bandwidth ) mx -= x . bandwidth ( ) / 2 ;
126
+ if ( y . bandwidth ) my -= y . bandwidth ( ) / 2 ;
127
+
122
128
// Compute the current selection, S: the subset of index that is
123
129
// logically selected. Normally this should be an in-order subset of
124
130
// index, but it isn’t here because quickselect will reorder in-place
125
131
// if the n option is used!
126
- const [ mx , my ] = pointerof ( event ) ;
127
132
let S = index ;
128
133
switch ( mode ) {
129
134
case "xy" : {
@@ -185,7 +190,7 @@ export class Pointer extends Mark {
185
190
. on ( "pointerup" , event => {
186
191
// On pointerup, if the selection is empty, clear the persistent to
187
192
// selection to allow the ephemeral selection on subsequent hover.
188
- if ( ! P . length ) select ( P = null ) ;
193
+ if ( P && ! P . length ) select ( P = null ) ;
189
194
down . delete ( event . pointerId ) ;
190
195
} )
191
196
. on ( "pointerout" , ( ) => {
@@ -211,6 +216,12 @@ function maybeMode(mode = "auto", x, y) {
211
216
return mode ;
212
217
}
213
218
219
+ function element ( name , attrs ) {
220
+ const e = document . createElementNS ( namespaces . svg , name ) ;
221
+ for ( const key in attrs ) e . setAttribute ( key , attrs [ key ] ) ;
222
+ return e ;
223
+ }
224
+
214
225
export function pointer ( data , { x, y, ...options } = { } ) {
215
226
( [ x , y ] = maybeTuple ( x , y ) ) ;
216
227
return new Pointer ( data , { ...options , x, y} ) ;
0 commit comments