11import { create , namespaces , pointer as pointerof , quickselect , union } from "d3" ;
2- import { identity , maybeFrameAnchor , maybeTuple } from "../options.js" ;
2+ import { identity , maybeTuple } from "../options.js" ;
33import { Mark } from "../plot.js" ;
44import { selection } from "../selection.js" ;
5- import { applyDirectStyles , applyFrameAnchor , applyIndirectStyles } from "../style.js" ;
5+ import { applyDirectStyles , applyIndirectStyles } from "../style.js" ;
66
77const defaults = {
88 ariaLabel : "pointer" ,
@@ -15,10 +15,9 @@ export class Pointer extends Mark {
1515 constructor ( data , {
1616 x,
1717 y,
18- n = Infinity ,
18+ n = 1 ,
1919 r = isFinite ( n ) ? 120 : 20 ,
2020 mode = "auto" ,
21- frameAnchor,
2221 ...options
2322 } = { } ) {
2423 super (
@@ -33,12 +32,10 @@ export class Pointer extends Mark {
3332 this . n = + n ;
3433 this . r = + r ;
3534 this . mode = maybeMode ( mode , x , y ) ;
36- this . frameAnchor = maybeFrameAnchor ( frameAnchor ) ;
3735 }
38- render ( index , scales , { x : X , y : Y } , dimensions ) {
36+ render ( index , { x , y } , { x : X , y : Y } , dimensions ) {
3937 const { marginLeft, width, marginRight, marginTop, height, marginBottom} = dimensions ;
4038 const { mode, n, r} = this ;
41- const [ cx , cy ] = applyFrameAnchor ( this , dimensions ) ;
4239 const r2 = r * r ; // the squared radius; to determine points in proximity to the pointer
4340 const down = new Set ( ) ; // the set of pointers that are currently down
4441 let C = [ ] ; // a sparse index from index[i] to an svg:circle element
@@ -63,11 +60,14 @@ export class Pointer extends Mark {
6360 S . forEach ( i => {
6461 let c = C [ i ] ;
6562 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 } ) ) ;
7171 parent . appendChild ( c ) ;
7272 changed = true ;
7373 }
@@ -119,11 +119,16 @@ export class Pointer extends Mark {
119119 // If any pointer is down, only consider pointers that are down.
120120 if ( P && ! down . has ( event . pointerId ) ) return ;
121121
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+
122128 // Compute the current selection, S: the subset of index that is
123129 // logically selected. Normally this should be an in-order subset of
124130 // index, but it isn’t here because quickselect will reorder in-place
125131 // if the n option is used!
126- const [ mx , my ] = pointerof ( event ) ;
127132 let S = index ;
128133 switch ( mode ) {
129134 case "xy" : {
@@ -185,7 +190,7 @@ export class Pointer extends Mark {
185190 . on ( "pointerup" , event => {
186191 // On pointerup, if the selection is empty, clear the persistent to
187192 // selection to allow the ephemeral selection on subsequent hover.
188- if ( ! P . length ) select ( P = null ) ;
193+ if ( P && ! P . length ) select ( P = null ) ;
189194 down . delete ( event . pointerId ) ;
190195 } )
191196 . on ( "pointerout" , ( ) => {
@@ -211,6 +216,12 @@ function maybeMode(mode = "auto", x, y) {
211216 return mode ;
212217}
213218
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+
214225export function pointer ( data , { x, y, ...options } = { } ) {
215226 ( [ x , y ] = maybeTuple ( x , y ) ) ;
216227 return new Pointer ( data , { ...options , x, y} ) ;
0 commit comments