@@ -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 , traceExtras = { } , layoutExtras = { } , 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,21 @@ 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 , traceExtras , layoutExtras ) {
46+ return makePlot (
47+ gd ,
48+ Lib . extendFlat ( { x : [ dayStart , dayNoon ] , y : [ 1 , 3 ] } , traceExtras ) ,
49+ Lib . extendFlat ( { xaxis : { type : 'date' , range : [ dayStart , dayEnd ] } } , layoutExtras )
50+ ) ;
51+ }
52+
3553describe ( 'hoveranywhere' , ( ) => {
3654 'use strict' ;
3755
@@ -58,7 +76,7 @@ describe('hoveranywhere', () => {
5876 it ( 'emits plotly_hover with coordinate data on empty space' , ( done ) => {
5977 var hoverData ;
6078
61- makePlot ( gd , { hoveranywhere : true } )
79+ makePlot ( gd , { } , { hoveranywhere : true } )
6280 . then ( ( ) => {
6381 gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
6482
@@ -94,7 +112,7 @@ describe('hoveranywhere', () => {
94112 it ( 'still returns normal point data on traces' , ( done ) => {
95113 var hoverData ;
96114
97- makePlot ( gd , { hoveranywhere : true } )
115+ makePlot ( gd , { } , { hoveranywhere : true } )
98116 . then ( ( ) => {
99117 gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
100118
@@ -132,7 +150,7 @@ describe('hoveranywhere', () => {
132150 it ( 'respects hovermode:false' , ( done ) => {
133151 var hoverData ;
134152
135- makePlot ( gd , { hoveranywhere : true , hovermode : false } )
153+ makePlot ( gd , { } , { hoveranywhere : true , hovermode : false } )
136154 . then ( ( ) => {
137155 gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
138156 _hover ( 250 , 50 ) ;
@@ -144,7 +162,7 @@ describe('hoveranywhere', () => {
144162 it ( 'emits plotly_hover over an editable shape' , ( done ) => {
145163 let hoverData ;
146164
147- makePlot ( gd , {
165+ makePlot ( gd , { } , {
148166 hoveranywhere : true ,
149167 shapes : [
150168 {
@@ -192,6 +210,7 @@ describe('hoveranywhere', () => {
192210
193211 makePlot (
194212 gd ,
213+ { } ,
195214 {
196215 hoveranywhere : true ,
197216 shapes : [
@@ -231,6 +250,55 @@ describe('hoveranywhere', () => {
231250 } )
232251 . then ( done , done . fail ) ;
233252 } ) ;
253+
254+ it ( 'reports date axis positions as date strings' , ( done ) => {
255+ var hoverData ;
256+
257+ makeDatePlot ( gd , { } , { hoveranywhere : true } )
258+ . then ( ( ) => {
259+ gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
260+
261+ _hover ( 0 , 60 ) ;
262+ expect ( hoverData . points ) . toEqual ( [ ] ) ;
263+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
264+ expect ( hoverData . yvals [ 0 ] ) . toBeCloseTo ( 10 - 60 / 30 , 2 ) ;
265+
266+ _hover ( 150 , 60 ) ;
267+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31 12:00' ) ;
268+
269+ // the point at (dayStart, 1) reports that same value
270+ _hover ( 0 , gd . _fullLayout . yaxis . c2p ( 1 ) ) ;
271+ expect ( hoverData . points [ 0 ] . x ) . toBe ( '2026-05-31' ) ;
272+ expect ( hoverData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
273+ } )
274+ . then ( done , done . fail ) ;
275+ } ) ;
276+
277+ it ( 'reports category names and log axis data values' , ( done ) => {
278+ var hoverData ;
279+
280+ makePlot (
281+ gd ,
282+ { x : [ 'a' , 'b' , 'c' ] , y : [ 10 , 20 , 30 ] } ,
283+ { xaxis : { type : 'category' } , yaxis : { type : 'log' , range : [ 1 , 3 ] } , hoveranywhere : true }
284+ )
285+ . then ( ( ) => {
286+ gd . on ( 'plotly_hover' , ( d ) => ( hoverData = d ) ) ;
287+
288+ var xa = gd . _fullLayout . xaxis ;
289+
290+ // empty space above the middle category, halfway up 10 -> 1000
291+ _hover ( xa . c2p ( 1 ) , 150 ) ;
292+ expect ( hoverData . points ) . toEqual ( [ ] ) ;
293+ expect ( hoverData . xvals [ 0 ] ) . toBe ( 'b' ) ;
294+ expect ( hoverData . yvals [ 0 ] ) . toBeCloseTo ( 100 , 6 ) ;
295+
296+ _hover ( xa . c2p ( 1 ) , gd . _fullLayout . yaxis . c2p ( 20 ) ) ;
297+ expect ( hoverData . points [ 0 ] . x ) . toBe ( 'b' ) ;
298+ expect ( hoverData . xvals [ 0 ] ) . toBe ( 'b' ) ;
299+ } )
300+ . then ( done , done . fail ) ;
301+ } ) ;
234302} ) ;
235303
236304describe ( 'clickanywhere' , ( ) => {
@@ -244,7 +312,7 @@ describe('clickanywhere', () => {
244312 it ( 'emits plotly_click with empty points on empty space' , ( done ) => {
245313 var clickData ;
246314
247- makePlot ( gd , { clickanywhere : true } )
315+ makePlot ( gd , { } , { clickanywhere : true } )
248316 . then ( ( ) => {
249317 gd . on ( 'plotly_click' , ( d ) => ( clickData = d ) ) ;
250318
@@ -285,7 +353,7 @@ describe('clickanywhere', () => {
285353 it ( 'emits plotly_click over an editable shape' , ( done ) => {
286354 let clickData ;
287355
288- makePlot ( gd , {
356+ makePlot ( gd , { } , {
289357 clickanywhere : true ,
290358 shapes : [
291359 {
@@ -329,6 +397,7 @@ describe('clickanywhere', () => {
329397
330398 makePlot (
331399 gd ,
400+ { } ,
332401 {
333402 clickanywhere : true ,
334403 shapes : [
@@ -367,4 +436,21 @@ describe('clickanywhere', () => {
367436 } )
368437 . then ( done , done . fail ) ;
369438 } ) ;
439+ it ( 'reports date axis positions as date strings' , ( done ) => {
440+ var clickData ;
441+
442+ makeDatePlot ( gd , { } , { clickanywhere : true } )
443+ . then ( ( ) => {
444+ gd . on ( 'plotly_click' , ( d ) => ( clickData = d ) ) ;
445+
446+ var bb = gd . getBoundingClientRect ( ) ;
447+ var s = gd . _fullLayout . _size ;
448+ click ( bb . left + s . l , bb . top + s . t + 60 ) ;
449+
450+ expect ( clickData . points ) . toEqual ( [ ] ) ;
451+ expect ( clickData . xvals [ 0 ] ) . toBe ( '2026-05-31' ) ;
452+ expect ( clickData . yvals [ 0 ] ) . toBeCloseTo ( 10 - 60 / 30 , 2 ) ;
453+ } )
454+ . then ( done , done . fail ) ;
455+ } ) ;
370456} ) ;
0 commit comments