From 65c26783bd2b95e0bf2eae6ee331fcd6e1e5fdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 22 Mar 2019 12:56:45 -0400 Subject: [PATCH 1/2] fix visible true|false toggle for pie traces - probably a side-effect from a splom-perf PR --- src/traces/pie/base_plot.js | 3 +-- test/jasmine/tests/pie_test.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/traces/pie/base_plot.js b/src/traces/pie/base_plot.js index cfc415501f0..af1d15543a1 100644 --- a/src/traces/pie/base_plot.js +++ b/src/traces/pie/base_plot.js @@ -16,8 +16,7 @@ exports.name = 'pie'; exports.plot = function(gd) { var Pie = Registry.getModule('pie'); var cdPie = getModuleCalcData(gd.calcdata, Pie)[0]; - - if(cdPie.length) Pie.plot(gd, cdPie); + Pie.plot(gd, cdPie); }; exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { diff --git a/test/jasmine/tests/pie_test.js b/test/jasmine/tests/pie_test.js index 773bfbd2564..76583ffba3d 100644 --- a/test/jasmine/tests/pie_test.js +++ b/test/jasmine/tests/pie_test.js @@ -818,6 +818,26 @@ describe('Pie traces', function() { .catch(failTest) .then(done); }); + + it('should be able to toggle visibility', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/pie_title_multiple.json')); + + function _assert(msg, exp) { + return function() { + var layer = d3.select(gd).select('.pielayer'); + expect(layer.selectAll('.trace').size()).toBe(exp, msg); + }; + } + + Plotly.plot(gd, mock) + .then(_assert('base', 4)) + .then(function() { return Plotly.restyle(gd, 'visible', false); }) + .then(_assert('both visible:false', 0)) + .then(function() { return Plotly.restyle(gd, 'visible', true); }) + .then(_assert('back to visible:true', 4)) + .catch(failTest) + .then(done); + }); }); describe('pie hovering', function() { From e1084fa698a1dbbbf589b38d71d4c05b151589e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 22 Mar 2019 12:58:23 -0400 Subject: [PATCH 2/2] fix #3618 edge for pie and sunburst --- src/traces/pie/plot.js | 16 +++--- src/traces/sunburst/plot.js | 16 +++--- test/jasmine/tests/pie_test.js | 82 +++++++++++++++++++++++++++++ test/jasmine/tests/sunburst_test.js | 67 +++++++++++++++++++++++ 4 files changed, 165 insertions(+), 16 deletions(-) diff --git a/src/traces/pie/plot.js b/src/traces/pie/plot.js index 47321269f17..8ca0f20f1ba 100644 --- a/src/traces/pie/plot.js +++ b/src/traces/pie/plot.js @@ -313,12 +313,12 @@ function attachFxHandlers(sliceTop, gd, cd) { // hover state vars // have we drawn a hover label, so it should be cleared later - var hasHoverLabel = false; + if(!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false; // have we emitted a hover event, so later an unhover event should be emitted // note that click events do not depend on this - you can still get them // with hovermode: false or if you were earlier dragging, then clicked // in the same slice that you moused up in - var hasHoverEvent = false; + if(!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false; sliceTop.on('mouseover', function(pt) { // in case fullLayout or fullData has changed without a replot @@ -390,14 +390,14 @@ function attachFxHandlers(sliceTop, gd, cd) { gd: gd }); - hasHoverLabel = true; + trace._hasHoverLabel = true; } + trace._hasHoverEvent = true; gd.emit('plotly_hover', { points: [eventData(pt, trace2)], event: d3.event }); - hasHoverEvent = true; }); sliceTop.on('mouseout', function(evt) { @@ -405,18 +405,18 @@ function attachFxHandlers(sliceTop, gd, cd) { var trace2 = gd._fullData[trace.index]; var pt = d3.select(this).datum(); - if(hasHoverEvent) { + if(trace._hasHoverEvent) { evt.originalEvent = d3.event; gd.emit('plotly_unhover', { points: [eventData(pt, trace2)], event: d3.event }); - hasHoverEvent = false; + trace._hasHoverEvent = false; } - if(hasHoverLabel) { + if(trace._hasHoverLabel) { Fx.loneUnhover(fullLayout2._hoverlayer.node()); - hasHoverLabel = false; + trace._hasHoverLabel = false; } }); diff --git a/src/traces/sunburst/plot.js b/src/traces/sunburst/plot.js index 930f634ca2f..bdee7443036 100644 --- a/src/traces/sunburst/plot.js +++ b/src/traces/sunburst/plot.js @@ -530,12 +530,12 @@ function attachFxHandlers(sliceTop, gd, cd) { // hover state vars // have we drawn a hover label, so it should be cleared later - var hasHoverLabel = false; + if(!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false; // have we emitted a hover event, so later an unhover event should be emitted // note that click events do not depend on this - you can still get them // with hovermode: false or if you were earlier dragging, then clicked // in the same slice that you moused up in - var hasHoverEvent = false; + if(!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false; sliceTop.on('mouseover', function(pt) { var fullLayoutNow = gd._fullLayout; @@ -603,14 +603,14 @@ function attachFxHandlers(sliceTop, gd, cd) { gd: gd }); - hasHoverLabel = true; + trace._hasHoverLabel = true; } + trace._hasHoverEvent = true; gd.emit('plotly_hover', { points: [makeEventData(pt, traceNow)], event: d3.event }); - hasHoverEvent = true; }); sliceTop.on('mouseout', function(evt) { @@ -618,18 +618,18 @@ function attachFxHandlers(sliceTop, gd, cd) { var traceNow = gd._fullData[trace.index]; var pt = d3.select(this).datum(); - if(hasHoverEvent) { + if(trace._hasHoverEvent) { evt.originalEvent = d3.event; gd.emit('plotly_unhover', { points: [makeEventData(pt, traceNow)], event: d3.event }); - hasHoverEvent = false; + trace._hasHoverEvent = false; } - if(hasHoverLabel) { + if(trace._hasHoverLabel) { Fx.loneUnhover(fullLayoutNow._hoverlayer.node()); - hasHoverLabel = false; + trace._hasHoverLabel = false; } }); diff --git a/test/jasmine/tests/pie_test.js b/test/jasmine/tests/pie_test.js index 76583ffba3d..572d7a909ef 100644 --- a/test/jasmine/tests/pie_test.js +++ b/test/jasmine/tests/pie_test.js @@ -1404,3 +1404,85 @@ describe('pie relayout', function() { .then(done); }); }); + +describe('Test pie interactions edge cases:', function() { + var gd; + + beforeEach(function() { gd = createGraphDiv(); }); + + afterEach(destroyGraphDiv); + + function _mouseEvent(type, v) { + return function() { + var el = d3.select(gd).select('.slice:nth-child(' + v + ')').node(); + mouseEvent(type, 0, 0, {element: el}); + }; + } + + function hover(v) { + return _mouseEvent('mouseover', v); + } + + function unhover(v) { + return _mouseEvent('mouseout', v); + } + + it('should keep tracking hover labels and hover events after *calc* edits', function(done) { + var mock = Lib.extendFlat({}, require('@mocks/pie_simple.json')); + var hoverCnt = 0; + var unhoverCnt = 0; + + // see https://github.com/plotly/plotly.js/issues/3618 + + function _assert(msg, exp) { + expect(hoverCnt).toBe(exp.hoverCnt, msg + ' - hover cnt'); + expect(unhoverCnt).toBe(exp.unhoverCnt, msg + ' - unhover cnt'); + + var label = d3.select(gd).select('g.hovertext'); + expect(label.size()).toBe(exp.hoverLabel, msg + ' - hover label cnt'); + + hoverCnt = 0; + unhoverCnt = 0; + } + + Plotly.plot(gd, mock) + .then(function() { + gd.on('plotly_hover', function() { + hoverCnt++; + // N.B. trigger a 'calc' edit + Plotly.restyle(gd, 'textinfo', 'percent'); + }); + gd.on('plotly_unhover', function() { + unhoverCnt++; + // N.B. trigger a 'calc' edit + Plotly.restyle(gd, 'textinfo', null); + }); + }) + .then(hover(1)) + .then(function() { + _assert('after hovering on first sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .then(unhover(1)) + .then(function() { + _assert('after un-hovering from first sector', { + hoverCnt: 0, + unhoverCnt: 1, + hoverLabel: 0 + }); + }) + .then(hover(2)) + .then(function() { + _assert('after hovering onto second sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .catch(failTest) + .then(done); + }); +}); diff --git a/test/jasmine/tests/sunburst_test.js b/test/jasmine/tests/sunburst_test.js index e7c1664b418..f1190a994cb 100644 --- a/test/jasmine/tests/sunburst_test.js +++ b/test/jasmine/tests/sunburst_test.js @@ -1031,3 +1031,70 @@ describe('Test sunburst tweening:', function() { .then(done); }); }); + +describe('Test sunburst interactions edge cases', function() { + var gd; + + beforeEach(function() { gd = createGraphDiv(); }); + + afterEach(destroyGraphDiv); + + it('should keep tracking hover labels and hover events after *calc* edits', function(done) { + var mock = Lib.extendFlat({}, require('@mocks/sunburst_first.json')); + var hoverCnt = 0; + var unhoverCnt = 0; + + // see https://github.com/plotly/plotly.js/issues/3618 + + function _assert(msg, exp) { + expect(hoverCnt).toBe(exp.hoverCnt, msg + ' - hover cnt'); + expect(unhoverCnt).toBe(exp.unhoverCnt, msg + ' - unhover cnt'); + + var label = d3.select(gd).select('g.hovertext'); + expect(label.size()).toBe(exp.hoverLabel, msg + ' - hover label cnt'); + + hoverCnt = 0; + unhoverCnt = 0; + } + + Plotly.plot(gd, mock) + .then(function() { + gd.on('plotly_hover', function() { + hoverCnt++; + // N.B. trigger a 'plot' edit + Plotly.restyle(gd, 'textinfo', 'none'); + }); + gd.on('plotly_unhover', function() { + unhoverCnt++; + // N.B. trigger a 'plot' edit + Plotly.restyle(gd, 'textinfo', null); + }); + }) + .then(hover(gd, 1)) + .then(function() { + _assert('after hovering on first sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .then(unhover(gd, 1)) + .then(function() { + _assert('after un-hovering from first sector', { + hoverCnt: 0, + unhoverCnt: 1, + hoverLabel: 0 + }); + }) + .then(hover(gd, 2)) + .then(function() { + _assert('after hovering onto second sector', { + hoverCnt: 1, + unhoverCnt: 0, + hoverLabel: 1 + }); + }) + .catch(failTest) + .then(done); + }); +});