diff --git a/draftlogs/5512_add.md b/draftlogs/5512_add.md new file mode 100644 index 00000000000..880c848b135 --- /dev/null +++ b/draftlogs/5512_add.md @@ -0,0 +1 @@ + - Provide bounding box positions in hover event data [[#5512](https://github.com/plotly/plotly.js/pull/5512)] diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 7ea1d78e4aa..eff1e1a2c4e 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -126,7 +126,48 @@ exports.loneHover = function loneHover(hoverItems, opts) { hoverItems = [hoverItems]; } + var gd = opts.gd; + var gTop = getTopOffset(gd); + var gLeft = getLeftOffset(gd); + var pointsData = hoverItems.map(function(hoverItem) { + var _x0 = hoverItem._x0 || hoverItem.x0 || hoverItem.x || 0; + var _x1 = hoverItem._x1 || hoverItem.x1 || hoverItem.x || 0; + var _y0 = hoverItem._y0 || hoverItem.y0 || hoverItem.y || 0; + var _y1 = hoverItem._y1 || hoverItem.y1 || hoverItem.y || 0; + + var eventData = hoverItem.eventData; + if(eventData) { + var x0 = Math.min(_x0, _x1); + var x1 = Math.max(_x0, _x1); + var y0 = Math.min(_y0, _y1); + var y1 = Math.max(_y0, _y1); + + var trace = hoverItem.trace; + if(Registry.traceIs(trace, 'gl3d')) { + var container = gd._fullLayout[trace.scene]._scene.container; + var dx = container.offsetLeft; + var dy = container.offsetTop; + x0 += dx; + x1 += dx; + y0 += dy; + y1 += dy; + } // TODO: handle heatmapgl + + eventData.bbox = { + x0: x0 + gLeft, + x1: x1 + gLeft, + y0: y0 + gTop, + y1: y1 + gTop + }; + + if(opts.inOut_bbox) { + opts.inOut_bbox.push(eventData.bbox); + } + } else { + eventData = false; + } + return { color: hoverItem.color || Color.defaultLine, x0: hoverItem.x0 || hoverItem.x || 0, @@ -158,8 +199,9 @@ exports.loneHover = function loneHover(hoverItems, opts) { index: 0, hovertemplate: hoverItem.hovertemplate || false, - eventData: hoverItem.eventData || false, hovertemplateLabels: hoverItem.hovertemplateLabels || false, + + eventData: eventData }; }); @@ -174,7 +216,7 @@ exports.loneHover = function loneHover(hoverItems, opts) { outerContainer: outerContainer3 }; - var hoverLabel = createHoverText(pointsData, fullOpts, opts.gd); + var hoverLabel = createHoverText(pointsData, fullOpts, gd); // Fix vertical overlap var tooltipSpacing = 5; @@ -199,8 +241,8 @@ exports.loneHover = function loneHover(hoverItems, opts) { d.offset -= anchor; }); - var scaleX = opts.gd._fullLayout._invScaleX; - var scaleY = opts.gd._fullLayout._invScaleY; + var scaleX = gd._fullLayout._invScaleX; + var scaleY = gd._fullLayout._invScaleY; alignHoverText(hoverLabel, fullOpts.rotateLabels, scaleX, scaleY); return multiHover ? hoverLabel : hoverLabel.node(); @@ -732,6 +774,9 @@ function _hover(gd, evt, subplot, noHoverEvent) { var oldhoverdata = gd._hoverdata; var newhoverdata = []; + var gTop = getTopOffset(gd); + var gLeft = getLeftOffset(gd); + // pull out just the data that's useful to // other people and send it to the event for(itemnum = 0; itemnum < hoverData.length; itemnum++) { @@ -746,6 +791,25 @@ function _hover(gd, evt, subplot, noHoverEvent) { pt.hovertemplate = ht || pt.trace.hovertemplate || false; } + if(pt.xa && pt.ya) { + var _x0 = pt.x0 + pt.xa._offset; + var _x1 = pt.x1 + pt.xa._offset; + var _y0 = pt.y0 + pt.ya._offset; + var _y1 = pt.y1 + pt.ya._offset; + + var x0 = Math.min(_x0, _x1); + var x1 = Math.max(_x0, _x1); + var y0 = Math.min(_y0, _y1); + var y1 = Math.max(_y0, _y1); + + eventData.bbox = { + x0: x0 + gLeft, + x1: x1 + gLeft, + y0: y0 + gTop, + y1: y1 + gTop + }; + } + pt.eventData = [eventData]; newhoverdata.push(eventData); } @@ -2033,3 +2097,9 @@ function getCoord(axLetter, winningPoint, fullLayout) { return val; } + +// Top/left hover offsets relative to graph div. As long as hover content is +// a sibling of the graph div, it will be positioned correctly relative to +// the offset parent, whatever that may be. +function getTopOffset(gd) { return gd.offsetTop + gd.clientTop; } +function getLeftOffset(gd) { return gd.offsetLeft + gd.clientLeft; } diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index b7ee3871218..174d1b30d52 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -421,6 +421,7 @@ proto.render = function() { var eventData = {points: [pointData]}; if(scene.fullSceneLayout.hovermode) { + var bbox = []; Fx.loneHover({ trace: traceNow, x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width, @@ -442,8 +443,11 @@ proto.render = function() { eventData: [pointData] }, { container: svgContainer, - gd: gd + gd: gd, + inOut_bbox: bbox }); + + pointData.bbox = bbox[0]; } if(selection.buttons && selection.distance < 5) { diff --git a/src/traces/icicle/draw_descendants.js b/src/traces/icicle/draw_descendants.js index b742438ea24..feec1ce4386 100644 --- a/src/traces/icicle/draw_descendants.js +++ b/src/traces/icicle/draw_descendants.js @@ -116,6 +116,12 @@ module.exports = function drawDescendants(gd, cd, entry, slices, opts) { } updateSlices.each(function(pt) { + // for bbox + pt._x0 = viewX(pt.x0); + pt._x1 = viewX(pt.x1); + pt._y0 = viewY(pt.y0); + pt._y1 = viewY(pt.y1); + pt._hoverX = viewX(pt.x1 - trace.tiling.pad), pt._hoverY = hasBottom ? viewY(pt.y1 - trace.tiling.pad / 2) : diff --git a/src/traces/pie/event_data.js b/src/traces/pie/event_data.js index 3393f0353dd..cb738f450a1 100644 --- a/src/traces/pie/event_data.js +++ b/src/traces/pie/event_data.js @@ -16,6 +16,7 @@ module.exports = function eventData(pt, trace) { value: pt.v, percent: pt.percent, text: pt.text, + bbox: pt.bbox, // pt.v (and pt.i below) for backward compatibility v: pt.v diff --git a/src/traces/pie/plot.js b/src/traces/pie/plot.js index cca8694817d..8d2cd2d39ee 100644 --- a/src/traces/pie/plot.js +++ b/src/traces/pie/plot.js @@ -344,9 +344,10 @@ function plotTextLines(slices, trace) { function attachFxHandlers(sliceTop, gd, cd) { var cd0 = cd[0]; - var trace = cd0.trace; var cx = cd0.cx; var cy = cd0.cy; + var trace = cd0.trace; + var isFunnelArea = trace.type === 'funnelarea'; // hover state vars // have we drawn a hover label, so it should be cleared later @@ -404,11 +405,16 @@ function attachFxHandlers(sliceTop, gd, cd) { var hoverLabel = trace2.hoverlabel; var hoverFont = hoverLabel.font; + var bbox = []; Fx.loneHover({ trace: trace, x0: hoverCenterX - rInscribed * cd0.r, x1: hoverCenterX + rInscribed * cd0.r, y: hoverCenterY, + _x0: isFunnelArea ? cx + pt.TL[0] : hoverCenterX - rInscribed * cd0.r, + _x1: isFunnelArea ? cx + pt.TR[0] : hoverCenterX + rInscribed * cd0.r, + _y0: isFunnelArea ? cy + pt.TL[1] : hoverCenterY - rInscribed * cd0.r, + _y1: isFunnelArea ? cy + pt.BL[1] : hoverCenterY + rInscribed * cd0.r, text: text.join('
'), name: (trace2.hovertemplate || hoverinfo.indexOf('name') !== -1) ? trace2.name : undefined, idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right', @@ -425,8 +431,10 @@ function attachFxHandlers(sliceTop, gd, cd) { }, { container: fullLayout2._hoverlayer.node(), outerContainer: fullLayout2._paper.node(), - gd: gd + gd: gd, + inOut_bbox: bbox }); + pt.bbox = bbox[0]; trace._hasHoverLabel = true; } diff --git a/src/traces/sunburst/fx.js b/src/traces/sunburst/fx.js index 66f2cec6d27..931541b3929 100644 --- a/src/traces/sunburst/fx.js +++ b/src/traces/sunburst/fx.js @@ -52,6 +52,8 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { var hoverinfo = Fx.castHoverinfo(traceNow, fullLayoutNow, ptNumber); var separators = fullLayoutNow.separators; + var eventData; + if(hovertemplate || (hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip')) { var hoverCenterX; var hoverCenterY; @@ -125,9 +127,15 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { if(Lib.isValidTextValue(tx)) thisText.push(tx); } + eventData = [makeEventData(pt, traceNow, opts.eventDataKeys)]; + var hoverItems = { trace: traceNow, y: hoverCenterY, + _x0: pt._x0, + _x1: pt._x1, + _y0: pt._y0, + _y1: pt._y1, text: thisText.join('
'), name: (hovertemplate || hasFlag('name')) ? traceNow.name : undefined, color: _cast('hoverlabel.bgcolor') || cdi.color, @@ -139,7 +147,7 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { textAlign: _cast('hoverlabel.align'), hovertemplate: hovertemplate, hovertemplateLabels: hoverPt, - eventData: [makeEventData(pt, traceNow, opts.eventDataKeys)] + eventData: eventData }; if(isSunburst) { @@ -152,11 +160,14 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { hoverItems.idealAlign = hoverCenterX < 0 ? 'left' : 'right'; } + var bbox = []; Fx.loneHover(hoverItems, { container: fullLayoutNow._hoverlayer.node(), outerContainer: fullLayoutNow._paper.node(), - gd: gd + gd: gd, + inOut_bbox: bbox }); + eventData[0].bbox = bbox[0]; trace._hasHoverLabel = true; } @@ -170,7 +181,7 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) { trace._hasHoverEvent = true; gd.emit('plotly_hover', { - points: [makeEventData(pt, traceNow, opts.eventDataKeys)], + points: eventData || [makeEventData(pt, traceNow, opts.eventDataKeys)], event: d3.event }); }; diff --git a/src/traces/treemap/draw_ancestors.js b/src/traces/treemap/draw_ancestors.js index 294af2fc624..a25bcfea236 100644 --- a/src/traces/treemap/draw_ancestors.js +++ b/src/traces/treemap/draw_ancestors.js @@ -89,6 +89,12 @@ module.exports = function drawAncestors(gd, cd, entry, slices, opts) { } updateSlices.each(function(pt) { + // for bbox + pt._x0 = viewX(pt.x0); + pt._x1 = viewX(pt.x1); + pt._y0 = viewY(pt.y0); + pt._y1 = viewY(pt.y1); + pt._hoverX = viewX(pt.x1 - Math.min(width, height) / 2); pt._hoverY = viewY(pt.y1 - height / 2); diff --git a/src/traces/treemap/draw_descendants.js b/src/traces/treemap/draw_descendants.js index 4e1fe8062be..d34296e8d05 100644 --- a/src/traces/treemap/draw_descendants.js +++ b/src/traces/treemap/draw_descendants.js @@ -124,6 +124,12 @@ module.exports = function drawDescendants(gd, cd, entry, slices, opts) { updateSlices.each(function(pt) { var isHeader = helpers.isHeader(pt, trace); + // for bbox + pt._x0 = viewX(pt.x0); + pt._x1 = viewX(pt.x1); + pt._y0 = viewY(pt.y0); + pt._y1 = viewY(pt.y1); + pt._hoverX = viewX(pt.x1 - trace.marker.pad.r), pt._hoverY = hasBottom ? viewY(pt.y1 - trace.marker.pad.b / 2) : diff --git a/test/jasmine/tests/cartesian_interact_test.js b/test/jasmine/tests/cartesian_interact_test.js index 9c972bee260..12c6ebd3254 100644 --- a/test/jasmine/tests/cartesian_interact_test.js +++ b/test/jasmine/tests/cartesian_interact_test.js @@ -2422,6 +2422,12 @@ describe('Cartesian plots with css transforms', function() { } }; + var bbox = { + one: { x0: 20, x1: 180, y0: 273.33, y1: 273.33 }, + two: { x0: 220, x1: 380, y0: 146.67, y1: 146.67 }, + three: { x0: 420, x1: 580, y0: 20, y1: 20 } + }; + [{ transform: 'scaleX(0.5)', hovered: 1, @@ -2436,12 +2442,14 @@ describe('Cartesian plots with css transforms', function() { selected: {numPoints: 3, selectedLabels: ['one', 'two', 'three']} }].forEach(function(t) { var transform = t.transform; - it('hover behaves correctly after css transform: ' + transform, function(done) { + var _bboxRecordings = {}; + function _hoverAndAssertEventOccurred(point, label) { return _hover(point) .then(function() { expect(eventRecordings[label]).toBe(t.hovered); + expect(_bboxRecordings[label]).toEqual(bbox[label]); }) .then(function() { _unhover(point); @@ -2454,6 +2462,7 @@ describe('Cartesian plots with css transforms', function() { gd.on('plotly_hover', function(d) { eventRecordings[d.points[0].x] = 1; + _bboxRecordings[d.points[0].x] = d.points[0].bbox; }); }) .then(function() {_hoverAndAssertEventOccurred(points[0], xLabels[0]);}) diff --git a/test/jasmine/tests/click_test.js b/test/jasmine/tests/click_test.js index e2b0ca81c6a..10e1d03d515 100644 --- a/test/jasmine/tests/click_test.js +++ b/test/jasmine/tests/click_test.js @@ -115,10 +115,11 @@ describe('Test click interactions:', function() { expect(contextPassthroughs).toBe(0); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); @@ -148,10 +149,11 @@ describe('Test click interactions:', function() { expect(contextPassthroughs).toBe(0); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); @@ -219,10 +221,11 @@ describe('Test click interactions:', function() { expect(contextPassthroughs).toBe(0, i); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); @@ -308,10 +311,11 @@ describe('Test click interactions:', function() { expect(futureData.points.length).toEqual(1); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); @@ -341,10 +345,11 @@ describe('Test click interactions:', function() { expect(futureData.points.length).toEqual(1); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); @@ -378,10 +383,11 @@ describe('Test click interactions:', function() { expect(futureData.points.length).toEqual(1); var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ + expect(Object.keys(pt).sort()).toEqual([ 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'bbox', 'x', 'y', 'xaxis', 'yaxis' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0); expect(pt.pointNumber).toEqual(11); expect(pt.x).toEqual(0.125); diff --git a/test/jasmine/tests/funnelarea_test.js b/test/jasmine/tests/funnelarea_test.js index 2afb934e434..d898be597f1 100644 --- a/test/jasmine/tests/funnelarea_test.js +++ b/test/jasmine/tests/funnelarea_test.js @@ -765,9 +765,16 @@ describe('funnelarea hovering', function() { 'curveNumber', 'pointNumber', 'pointNumbers', 'data', 'fullData', 'label', 'color', 'value', - 'percent', 'text' + 'percent', 'text', + 'bbox' ]; + expect(typeof hoverData.points[0].bbox).toEqual('object'); + expect(typeof hoverData.points[0].bbox.x0).toEqual('number'); + expect(typeof hoverData.points[0].bbox.x1).toEqual('number'); + expect(typeof hoverData.points[0].bbox.y0).toEqual('number'); + expect(typeof hoverData.points[0].bbox.y1).toEqual('number'); + expect(Object.keys(hoverData.points[0]).sort()).toEqual(fields.sort()); expect(hoverData.points[0].pointNumber).toEqual(3); diff --git a/test/jasmine/tests/geo_test.js b/test/jasmine/tests/geo_test.js index 335bcf990e4..f28ff0e7d70 100644 --- a/test/jasmine/tests/geo_test.js +++ b/test/jasmine/tests/geo_test.js @@ -882,10 +882,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'marker.size' - ]); + ].sort()); expect(cnt).toEqual(1); }); @@ -947,10 +947,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'marker.size' - ]); + ].sort()); }); it('should show the correct point data', function() { @@ -979,10 +979,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'marker.size' - ]); + ].sort()); }); it('should show the correct point data', function() { @@ -1008,10 +1008,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'location', 'z', 'ct' - ]); + ].sort()); }); it('should show the correct point data', function() { @@ -1036,10 +1036,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'location', 'z', 'ct' - ]); + ].sort()); }); it('should show the correct point data', function() { @@ -1068,10 +1068,10 @@ describe('Test geo interactions', function() { }); it('should contain the correct fields', function() { - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(ptData).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'location', 'z', 'ct' - ]); + ].sort()); }); it('should show the correct point data', function() { @@ -1789,11 +1789,11 @@ describe('Test event property of interactions on a geo plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'text', 'marker.size' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1847,11 +1847,11 @@ describe('Test event property of interactions on a geo plot:', function() { // var pt = futureData.points[0], // evt = futureData.event; - // expect(Object.keys(pt)).toEqual([ - // 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + // expect(Object.keys(pt).sort()).toEqual([ + // 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', // 'lon', 'lat', // 'location', 'text', 'marker.size' - // ]); + // ].sort()); // expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); // expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1893,11 +1893,11 @@ describe('Test event property of interactions on a geo plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'text', 'marker.size' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1934,11 +1934,11 @@ describe('Test event property of interactions on a geo plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'bbox', 'lon', 'lat', 'location', 'text', 'marker.size' - ]); + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); diff --git a/test/jasmine/tests/gl3d_hover_click_test.js b/test/jasmine/tests/gl3d_hover_click_test.js index 3fbb56edeaa..9359edd2f28 100644 --- a/test/jasmine/tests/gl3d_hover_click_test.js +++ b/test/jasmine/tests/gl3d_hover_click_test.js @@ -58,7 +58,8 @@ describe('Test gl3d trace click/hover:', function() { function assertEventData(x, y, z, curveNumber, pointNumber, extra) { expect(Object.keys(ptData)).toEqual(jasmine.arrayContaining([ 'x', 'y', 'z', - 'data', 'fullData', 'curveNumber', 'pointNumber' + 'data', 'fullData', 'curveNumber', 'pointNumber', + 'bbox' ]), 'correct hover data fields'); expect(ptData.x).toEqual(x, 'x val'); @@ -67,6 +68,12 @@ describe('Test gl3d trace click/hover:', function() { expect(ptData.curveNumber).toEqual(curveNumber, 'curveNumber'); expect(ptData.pointNumber).toEqual(pointNumber, 'pointNumber'); + expect(typeof ptData.bbox).toEqual('object'); + expect(typeof ptData.bbox.x0).toEqual('number'); + expect(typeof ptData.bbox.x1).toEqual('number'); + expect(typeof ptData.bbox.y0).toEqual('number'); + expect(typeof ptData.bbox.y1).toEqual('number'); + Object.keys(extra || {}).forEach(function(k) { expect(ptData[k]).toEqual(extra[k], k + ' val'); }); diff --git a/test/jasmine/tests/icicle_test.js b/test/jasmine/tests/icicle_test.js index 143165feb80..339e3ce4928 100644 --- a/test/jasmine/tests/icicle_test.js +++ b/test/jasmine/tests/icicle_test.js @@ -526,6 +526,12 @@ describe('Test icicle hover:', function() { expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k); } + expect(typeof ptData.bbox).toEqual('object'); + expect(typeof ptData.bbox.x0).toEqual('number'); + expect(typeof ptData.bbox.x1).toEqual('number'); + expect(typeof ptData.bbox.y0).toEqual('number'); + expect(typeof ptData.bbox.y1).toEqual('number'); + if(exp.style) { var gd3 = d3Select(gd); assertHoverLabelStyle(gd3.select('.hovertext'), exp.style); diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js index d39400f70f3..ef4f4d1f53a 100644 --- a/test/jasmine/tests/mapbox_test.js +++ b/test/jasmine/tests/mapbox_test.js @@ -19,6 +19,12 @@ var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; var assertHoverLabelContent = customAssertions.assertHoverLabelContent; +var SORTED_EVENT_KEYS = [ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'lon', 'lat', + 'bbox' +].sort(); + var MAPBOX_ACCESS_TOKEN = require('@build/credentials.json').MAPBOX_ACCESS_TOKEN; var TRANSITION_DELAY = 500; var MOUSE_DELAY = 100; @@ -1243,9 +1249,7 @@ describe('mapbox plots', function() { .then(function() { return _mouseEvent('mousemove', pointPos, function() { expect(hoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(hoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ], 'returning the correct event data keys'); + expect(Object.keys(hoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(hoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(hoverData.pointNumber).toEqual(0, 'returning the correct point number'); }); @@ -1253,9 +1257,7 @@ describe('mapbox plots', function() { .then(function() { return _mouseEvent('mousemove', blankPos, function() { expect(unhoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(unhoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ], 'returning the correct event data keys'); + expect(Object.keys(unhoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(unhoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(unhoverData.pointNumber).toEqual(0, 'returning the correct point number'); }); @@ -1400,9 +1402,7 @@ describe('mapbox plots', function() { .then(function() { return click(pointPos[0], pointPos[1]); }) .then(function() { expect(ptData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ], 'returning the correct event data keys'); + expect(Object.keys(ptData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(ptData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(ptData.pointNumber).toEqual(0, 'returning the correct point number'); }) diff --git a/test/jasmine/tests/pie_test.js b/test/jasmine/tests/pie_test.js index eedb6974d26..f70d80e44bb 100644 --- a/test/jasmine/tests/pie_test.js +++ b/test/jasmine/tests/pie_test.js @@ -1103,9 +1103,16 @@ describe('pie hovering', function() { 'curveNumber', 'pointNumber', 'pointNumbers', 'data', 'fullData', 'label', 'color', 'value', - 'i', 'v', 'percent', 'text' + 'i', 'v', 'percent', 'text', + 'bbox' ]; + expect(typeof hoverData.points[0].bbox).toEqual('object'); + expect(typeof hoverData.points[0].bbox.x0).toEqual('number'); + expect(typeof hoverData.points[0].bbox.x1).toEqual('number'); + expect(typeof hoverData.points[0].bbox.y0).toEqual('number'); + expect(typeof hoverData.points[0].bbox.y1).toEqual('number'); + expect(Object.keys(hoverData.points[0]).sort()).toEqual(fields.sort()); expect(hoverData.points[0].pointNumber).toEqual(3); diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js index 89c7955851b..aaeb28d0a4e 100644 --- a/test/jasmine/tests/scattermapbox_test.js +++ b/test/jasmine/tests/scattermapbox_test.js @@ -952,9 +952,9 @@ describe('Test plotly events on a scattermapbox plot:', function() { var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -999,9 +999,9 @@ describe('Test plotly events on a scattermapbox plot:', function() { // var pt = futureData.points[0], // evt = futureData.event; - // expect(Object.keys(pt)).toEqual([ - // 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - // ]); + // expect(Object.keys(pt).sort()).toEqual([ + // 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + // ].sort()); // expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); // expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1033,9 +1033,9 @@ describe('Test plotly events on a scattermapbox plot:', function() { var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1061,9 +1061,9 @@ describe('Test plotly events on a scattermapbox plot:', function() { move(pointPos[0], pointPos[1], nearPos[0], nearPos[1], HOVERMINTIME + 10).then(function() { var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1133,9 +1133,9 @@ describe('Test plotly events on a scattermapbox plot when css transform is prese var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1163,9 +1163,9 @@ describe('Test plotly events on a scattermapbox plot when css transform is prese var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1191,9 +1191,9 @@ describe('Test plotly events on a scattermapbox plot when css transform is prese move(pointPos[0], pointPos[1], nearPos[0], nearPos[1], HOVERMINTIME + 10).then(function() { var pt = futureData.points[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat' - ]); + expect(Object.keys(pt).sort()).toEqual([ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', 'lon', 'lat', 'bbox' + ].sort()); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); diff --git a/test/jasmine/tests/streamtube_test.js b/test/jasmine/tests/streamtube_test.js index deb9322b428..2eb6088be01 100644 --- a/test/jasmine/tests/streamtube_test.js +++ b/test/jasmine/tests/streamtube_test.js @@ -593,7 +593,7 @@ describe('Test streamtube hover', function() { .then(delay(20)) .then(function() { if(ptData) { - expect(Object.keys(ptData).length).toBe(12, 'key cnt'); + expect(Object.keys(ptData).length).toBe(13, 'key cnt'); expect(ptData.tubex).toBeCloseTo(2.19, TOL, 'tubex'); expect(ptData.tubey).toBeCloseTo(0.55, TOL, 'tubey'); diff --git a/test/jasmine/tests/sunburst_test.js b/test/jasmine/tests/sunburst_test.js index 28876802534..019eca82be6 100644 --- a/test/jasmine/tests/sunburst_test.js +++ b/test/jasmine/tests/sunburst_test.js @@ -539,6 +539,12 @@ describe('Test sunburst hover:', function() { expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k); } + expect(typeof ptData.bbox).toEqual('object'); + expect(typeof ptData.bbox.x0).toEqual('number'); + expect(typeof ptData.bbox.x1).toEqual('number'); + expect(typeof ptData.bbox.y0).toEqual('number'); + expect(typeof ptData.bbox.y1).toEqual('number'); + if(exp.style) { var gd3 = d3Select(gd); assertHoverLabelStyle(gd3.select('.hovertext'), exp.style); diff --git a/test/jasmine/tests/ternary_test.js b/test/jasmine/tests/ternary_test.js index 27f6136994d..151a818edab 100644 --- a/test/jasmine/tests/ternary_test.js +++ b/test/jasmine/tests/ternary_test.js @@ -19,6 +19,12 @@ var customAssertions = require('../assets/custom_assertions'); var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle; var assertHoverLabelContent = customAssertions.assertHoverLabelContent; +var SORTED_EVENT_KEYS = [ + 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', + 'xaxis', 'yaxis', 'a', 'b', 'c', + 'bbox' +].sort(); + describe('ternary plots', function() { 'use strict'; @@ -195,19 +201,13 @@ describe('ternary plots', function() { mouseEvent('mousemove', pointPos[0], pointPos[1]); expect(hoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(hoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(hoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(hoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(hoverData.pointNumber).toEqual(0, 'returning the correct point number'); mouseEvent('mouseout', pointPos[0], pointPos[1]); expect(unhoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(unhoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(unhoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(unhoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(unhoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -227,10 +227,7 @@ describe('ternary plots', function() { click(pointPos[0], pointPos[1]); expect(ptData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(ptData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(ptData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(ptData.pointNumber).toEqual(0, 'returning the correct point number'); }); @@ -678,19 +675,13 @@ describe('ternary plots when css transform is present', function() { mouseEvent('mousemove', pointPos[0], pointPos[1]); expect(hoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(hoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(hoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(hoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(hoverData.pointNumber).toEqual(0, 'returning the correct point number'); mouseEvent('mouseout', pointPos[0], pointPos[1]); expect(unhoverData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(unhoverData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(unhoverData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(unhoverData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(unhoverData.pointNumber).toEqual(0, 'returning the correct point number'); @@ -710,10 +701,7 @@ describe('ternary plots when css transform is present', function() { click(pointPos[0], pointPos[1]); expect(ptData).not.toBe(undefined, 'firing on data points'); - expect(Object.keys(ptData)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ], 'returning the correct event data keys'); + expect(Object.keys(ptData).sort()).toEqual(SORTED_EVENT_KEYS, 'returning the correct event data keys'); expect(ptData.curveNumber).toEqual(0, 'returning the correct curve number'); expect(ptData.pointNumber).toEqual(0, 'returning the correct point number'); }); @@ -843,10 +831,7 @@ describe('Test event property of interactions on a ternary plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ]); + expect(Object.keys(pt).sort()).toEqual(SORTED_EVENT_KEYS); expect(pt.curveNumber).toBe(0, 'points[0].curveNumber'); expect(typeof pt.data).toBe(typeof {}, 'points[0].data'); @@ -912,10 +897,7 @@ describe('Test event property of interactions on a ternary plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ]); + expect(Object.keys(pt).sort()).toEqual(SORTED_EVENT_KEYS); expect(pt.curveNumber).toBe(0, 'points[0].curveNumber: ' + i); expect(typeof pt.data).toBe(typeof {}, 'points[0].data: ' + i); @@ -964,10 +946,7 @@ describe('Test event property of interactions on a ternary plot:', function() { var yaxes0 = futureData.yaxes[0]; var yvals0 = futureData.yvals[0]; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ]); + expect(Object.keys(pt).sort()).toEqual(SORTED_EVENT_KEYS); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); @@ -1012,10 +991,7 @@ describe('Test event property of interactions on a ternary plot:', function() { var pt = futureData.points[0]; var evt = futureData.event; - expect(Object.keys(pt)).toEqual([ - 'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex', - 'xaxis', 'yaxis', 'a', 'b', 'c' - ]); + expect(Object.keys(pt).sort()).toEqual(SORTED_EVENT_KEYS); expect(pt.curveNumber).toEqual(0, 'points[0].curveNumber'); expect(typeof pt.data).toEqual(typeof {}, 'points[0].data'); diff --git a/test/jasmine/tests/treemap_test.js b/test/jasmine/tests/treemap_test.js index 425a9fd528e..af3f5f098d5 100644 --- a/test/jasmine/tests/treemap_test.js +++ b/test/jasmine/tests/treemap_test.js @@ -628,6 +628,12 @@ describe('Test treemap hover:', function() { expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k); } + expect(typeof ptData.bbox).toEqual('object'); + expect(typeof ptData.bbox.x0).toEqual('number'); + expect(typeof ptData.bbox.x1).toEqual('number'); + expect(typeof ptData.bbox.y0).toEqual('number'); + expect(typeof ptData.bbox.y1).toEqual('number'); + if(exp.style) { var gd3 = d3Select(gd); assertHoverLabelStyle(gd3.select('.hovertext'), exp.style);