@@ -225,3 +225,148 @@ describe('Log Tooltip interactions', function() {
225225 } , 20 ) ;
226226 } ) ;
227227} ) ;
228+
229+ describe ( 'Tooltip callback interactions' , function ( ) {
230+ var gd ;
231+
232+ function pushN ( xs , ys , x , y , n ) {
233+ for ( var i = 0 ; i < n ; i ++ ) {
234+ xs . push ( x ) ;
235+ ys . push ( y ) ;
236+ }
237+ }
238+
239+ function clickDataPoint ( gd , x , y ) {
240+ var bb = gd . getBoundingClientRect ( ) ;
241+ var size = gd . _fullLayout . _size ;
242+ var xa = gd . _fullLayout . xaxis ;
243+ var ya = gd . _fullLayout . yaxis ;
244+
245+ click (
246+ bb . left + size . l + xa . c2p ( x ) ,
247+ bb . top + size . t + ya . c2p ( y )
248+ ) ;
249+ }
250+
251+ beforeAll ( function ( done ) {
252+ var xs = [ ] ;
253+ var ys = [ ] ;
254+
255+ pushN ( xs , ys , 0.5 , 0.5 , 1 ) ;
256+ pushN ( xs , ys , 1.5 , 1.5 , 2 ) ;
257+ pushN ( xs , ys , 2.5 , 1.5 , 5 ) ;
258+ pushN ( xs , ys , 2.5 , 2.5 , 3 ) ;
259+
260+ gd = createGraphDiv ( ) ;
261+ Plotly . newPlot ( gd , [ {
262+ type : 'histogram2d' ,
263+ x : xs ,
264+ y : ys ,
265+ autobinx : false ,
266+ autobiny : false ,
267+ xbins : { start : 0 , end : 3 , size : 1 } ,
268+ ybins : { start : 0 , end : 3 , size : 1 } ,
269+ colorscale : 'Blues'
270+ } ] , {
271+ width : 400 ,
272+ height : 400 ,
273+ margin : { l : 60 , r : 20 , t : 20 , b : 60 } ,
274+ hovermode : 'closest' ,
275+ annotations : [ ]
276+ } , {
277+ editable : true
278+ } )
279+ . then ( function ( ) {
280+ gd . data [ 0 ] . tooltiptemplate = 'Local max: %{z}<br>x: %{x}<br>y: %{y}<br>kernel: %{kernelSizeX} x %{kernelSizeY}' ;
281+ gd . data [ 0 ] . tooltipfunction = function ( ctx ) {
282+ var kernelSizeX = 2 ;
283+ var kernelSizeY = 2 ;
284+ var cd0 = ctx . calcdata [ 0 ] ;
285+ var xs = ctx . fullTrace . _x ;
286+ var ys = ctx . fullTrace . _y ;
287+ var z = ctx . fullTrace . _z || cd0 . z ;
288+ var halfX = kernelSizeX / 2 ;
289+ var halfY = kernelSizeY / 2 ;
290+ var minX = ctx . point . x - halfX ;
291+ var maxX = ctx . point . x + halfX ;
292+ var minY = ctx . point . y - halfY ;
293+ var maxY = ctx . point . y + halfY ;
294+ var best = - Infinity ;
295+ var bestX = ctx . point . x ;
296+ var bestY = ctx . point . y ;
297+
298+ if ( ! xs || ! xs . length ) {
299+ xs = cd0 . xRanges . map ( function ( range ) { return ( range [ 0 ] + range [ 1 ] ) / 2 ; } ) ;
300+ }
301+ if ( ! ys || ! ys . length ) {
302+ ys = cd0 . yRanges . map ( function ( range ) { return ( range [ 0 ] + range [ 1 ] ) / 2 ; } ) ;
303+ }
304+
305+ for ( var iy = 0 ; iy < ys . length ; iy ++ ) {
306+ var y = ys [ iy ] ;
307+ if ( y < minY || y > maxY ) continue ;
308+
309+ for ( var ix = 0 ; ix < xs . length ; ix ++ ) {
310+ var x = xs [ ix ] ;
311+ if ( x < minX || x > maxX ) continue ;
312+
313+ var value = z [ iy ] [ ix ] ;
314+ if ( value > best ) {
315+ best = value ;
316+ bestX = x ;
317+ bestY = y ;
318+ }
319+ }
320+ }
321+
322+ return {
323+ point : {
324+ x : bestX ,
325+ y : bestY ,
326+ z : best ,
327+ kernelSizeX : kernelSizeX ,
328+ kernelSizeY : kernelSizeY
329+ } ,
330+ annotation : {
331+ x : bestX ,
332+ y : bestY
333+ }
334+ } ;
335+ } ;
336+ } )
337+ . then ( done , done . fail ) ;
338+ } ) ;
339+
340+ afterAll ( function ( ) {
341+ destroyGraphDiv ( ) ;
342+ } ) ;
343+
344+ it ( 'should create a tooltip annotation at the local maximum inside the callback kernel' , function ( done ) {
345+ modeBarButtons . tooltip . click ( gd ) ;
346+ setTimeout ( function ( ) {
347+ clickDataPoint ( gd , 1.5 , 1.5 ) ;
348+
349+ setTimeout ( function ( ) {
350+ expect ( gd . _fullLayout . annotations . length ) . toBe ( 1 ) ;
351+ expect ( gd . _fullLayout . annotations [ 0 ] . text ) . toBe ( 'Local max: 5<br>x: 2.5<br>y: 1.5<br>kernel: 2 x 2' ) ;
352+ expect ( gd . _fullLayout . annotations [ 0 ] . x ) . toBe ( 2.5 ) ;
353+ expect ( gd . _fullLayout . annotations [ 0 ] . y ) . toBe ( 1.5 ) ;
354+ done ( ) ;
355+ } , 30 ) ;
356+ } , 30 ) ;
357+ } ) ;
358+
359+ it ( 'should cancel tooltip creation when tooltipfunction returns false' , function ( done ) {
360+ Plotly . relayout ( gd , { annotations : [ ] } ) . then ( function ( ) {
361+ gd . data [ 0 ] . tooltipfunction = function ( ) { return false ; } ;
362+
363+ clickDataPoint ( gd , 1.5 , 1.5 ) ;
364+
365+ setTimeout ( function ( ) {
366+ expect ( gd . _fullLayout . annotations . length ) . toBe ( 0 ) ;
367+ done ( ) ;
368+ } , 30 ) ;
369+ } )
370+ . catch ( done . fail ) ;
371+ } ) ;
372+ } ) ;
0 commit comments