@@ -6,16 +6,19 @@ var createGraphDiv = require('../assets/create_graph_div');
66var destroyGraphDiv = require ( '../assets/destroy_graph_div' ) ;
77var click = require ( '../assets/click' ) ;
88
9- function makePlot ( gd , layoutExtras = { } , configExtras ) {
9+ function makePlot ( gd , layoutExtras = { } , traceExtras = { } , configExtras ) {
1010 return Plotly . newPlot (
1111 gd ,
1212 [
13- {
14- x : [ 1 , 2 , 3 ] ,
15- y : [ 1 , 3 , 2 ] ,
16- type : 'scatter' ,
17- mode : 'markers'
18- }
13+ Lib . extendFlat (
14+ {
15+ x : [ 1 , 2 , 3 ] ,
16+ y : [ 1 , 3 , 2 ] ,
17+ type : 'scatter' ,
18+ mode : 'markers'
19+ } ,
20+ traceExtras
21+ )
1922 ] ,
2023 Lib . extendFlat (
2124 {
@@ -32,6 +35,20 @@ function makePlot(gd, layoutExtras = {}, configExtras) {
3235 ) ;
3336}
3437
38+ // local midnight, as in https://github.com/plotly/plotly.js/issues/7816
39+ var dayStart = new Date ( 2026 , 4 , 31 ) ;
40+ var dayNoon = new Date ( 2026 , 4 , 31 , 12 ) ;
41+ var dayEnd = new Date ( 2026 , 5 , 1 ) ;
42+
43+ // the 300px-wide plot area spans exactly one day, so 0px is local midnight
44+ // and 150px is local noon, in any timezone
45+ function makeDatePlot ( gd , layoutExtras ) {
46+ return makePlot ( gd , Lib . extendFlat ( { xaxis : { type : 'date' , range : [ dayStart , dayEnd ] } } , layoutExtras ) , {
47+ x : [ dayStart , dayNoon ] ,
48+ y : [ 1 , 3 ]
49+ } ) ;
50+ }
51+
3552describe ( 'hoveranywhere' , ( ) => {
3653 'use strict' ;
3754
@@ -205,6 +222,7 @@ describe('hoveranywhere', () => {
205222 }
206223 ]
207224 } ,
225+ { } ,
208226 { edits : { shapePosition : true } }
209227 )
210228 . then ( ( ) => {
@@ -231,6 +249,55 @@ describe('hoveranywhere', () => {
231249 } )
232250 . then ( done , done . fail ) ;
233251 } ) ;
252+
253+ it ( 'reports date axis positions as date strings' , ( done ) => {
254+ var hoverData ;
255+
256+ makeDatePlot ( gd , { hoveranywhere : true } )
257+ . then ( ( ) => {
258+ gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
259+
260+ _hover ( 0 , 60 ) ;
261+ expect ( hoverData . points ) . toEqual ( [ ] ) ;
262+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
263+ expect ( hoverData . yvals [ 0 ] ) . toBeCloseTo ( 10 - 60 / 30 , 2 ) ;
264+
265+ _hover ( 150 , 60 ) ;
266+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31 12:00' ) ;
267+
268+ // the point at (dayStart, 1) reports that same value
269+ _hover ( 0 , gd . _fullLayout . yaxis . c2p ( 1 ) ) ;
270+ expect ( hoverData . points [ 0 ] . x ) . toBe ( '2026-05-31' ) ;
271+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
272+ } )
273+ . then ( done , done . fail ) ;
274+ } ) ;
275+
276+ it ( 'reports category names and log axis data values' , ( done ) => {
277+ var hoverData ;
278+
279+ makePlot (
280+ gd ,
281+ { xaxis : { type : 'category' } , yaxis : { type : 'log' , range : [ 1 , 3 ] } , hoveranywhere : true } ,
282+ { x : [ 'a' , 'b' , 'c' ] , y : [ 10 , 20 , 30 ] }
283+ )
284+ . then ( ( ) => {
285+ gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
286+
287+ var xa = gd . _fullLayout . xaxis ;
288+
289+ // empty space above the middle category, halfway up 10 -> 1000
290+ _hover ( xa . c2p ( 1 ) , 150 ) ;
291+ expect ( hoverData . points ) . toEqual ( [ ] ) ;
292+ expect ( hoverData . xvals [ 0 ] ) . toBe ( 'b' ) ;
293+ expect ( hoverData . yvals [ 0 ] ) . toBeCloseTo ( 100 , 6 ) ;
294+
295+ _hover ( xa . c2p ( 1 ) , gd . _fullLayout . yaxis . c2p ( 20 ) ) ;
296+ expect ( hoverData . points [ 0 ] . x ) . toBe ( 'b' ) ;
297+ expect ( hoverData . xvals [ 0 ] ) . toBe ( 'b' ) ;
298+ } )
299+ . then ( done , done . fail ) ;
300+ } ) ;
234301} ) ;
235302
236303describe ( 'clickanywhere' , ( ) => {
@@ -342,6 +409,7 @@ describe('clickanywhere', () => {
342409 }
343410 ]
344411 } ,
412+ { } ,
345413 { edits : { shapePosition : true } }
346414 )
347415 . then ( ( ) => {
@@ -367,4 +435,21 @@ describe('clickanywhere', () => {
367435 } )
368436 . then ( done , done . fail ) ;
369437 } ) ;
438+ it ( 'reports date axis positions as date strings' , ( done ) => {
439+ var clickData ;
440+
441+ makeDatePlot ( gd , { clickanywhere : true } )
442+ . then ( ( ) => {
443+ gd . on ( 'plotly_click' , ( d ) => ( clickData = d ) ) ;
444+
445+ var bb = gd . getBoundingClientRect ( ) ;
446+ var s = gd . _fullLayout . _size ;
447+ click ( bb . left + s . l , bb . top + s . t + 60 ) ;
448+
449+ expect ( clickData . points ) . toEqual ( [ ] ) ;
450+ expect ( clickData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
451+ expect ( clickData . yvals [ 0 ] ) . toBeCloseTo ( 10 - 60 / 30 , 2 ) ;
452+ } )
453+ . then ( done , done . fail ) ;
454+ } ) ;
370455} ) ;
0 commit comments