-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Legend scroll fix #2426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Legend scroll fix #2426
Changes from 4 commits
f75f5ba
ec42784
246b77f
569b378
5660bf5
f2d8cfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,9 @@ var DBLCLICKDELAY = require('@src/constants/interactions').DBLCLICKDELAY; | |
var d3 = require('d3'); | ||
var createGraph = require('../assets/create_graph_div'); | ||
var destroyGraph = require('../assets/destroy_graph_div'); | ||
var failTest = require('../assets/fail_test'); | ||
var getBBox = require('../assets/get_bbox'); | ||
var mouseEvent = require('../assets/mouse_event'); | ||
var mock = require('../../image/mocks/legend_scroll.json'); | ||
|
||
describe('The legend', function() { | ||
|
@@ -47,6 +49,17 @@ describe('The legend', function() { | |
return d3.select('g.legend').select('.legendtoggle').node(); | ||
} | ||
|
||
function getScroll(gd) { | ||
return gd._fullLayout.legend._scrollY; | ||
} | ||
|
||
function hasScrollBar() { | ||
var scrollBar = getScrollBar(); | ||
return scrollBar && | ||
+scrollBar.getAttribute('width') > 0 && | ||
+scrollBar.getAttribute('height') > 0; | ||
} | ||
|
||
describe('when plotted with many traces', function() { | ||
var gd; | ||
|
||
|
@@ -76,26 +89,153 @@ describe('The legend', function() { | |
}); | ||
|
||
it('should scroll when there\'s a wheel event', function() { | ||
var legend = getLegend(), | ||
scrollBox = getScrollBox(), | ||
legendHeight = getLegendHeight(gd), | ||
scrollBoxYMax = gd._fullLayout.legend._height - legendHeight, | ||
scrollBarYMax = legendHeight - | ||
constants.scrollBarHeight - | ||
2 * constants.scrollBarMargin, | ||
initialDataScroll = scrollBox.getAttribute('data-scroll'), | ||
wheelDeltaY = 100, | ||
finalDataScroll = '' + Lib.constrain(initialDataScroll - | ||
wheelDeltaY / scrollBarYMax * scrollBoxYMax, | ||
-scrollBoxYMax, 0); | ||
var legend = getLegend(); | ||
var scrollBox = getScrollBox(); | ||
var scrollBar = getScrollBar(); | ||
var legendHeight = getLegendHeight(gd); | ||
var scrollBoxYMax = gd._fullLayout.legend._height - legendHeight; | ||
var scrollBarYMax = legendHeight - | ||
scrollBar.getBoundingClientRect().height - | ||
2 * constants.scrollBarMargin; | ||
var initialDataScroll = getScroll(gd); | ||
var wheelDeltaY = 100; | ||
var finalDataScroll = Lib.constrain(initialDataScroll - | ||
wheelDeltaY / scrollBarYMax * scrollBoxYMax, | ||
-scrollBoxYMax, 0); | ||
|
||
legend.dispatchEvent(scrollTo(wheelDeltaY)); | ||
|
||
expect(scrollBox.getAttribute('data-scroll')).toBe(finalDataScroll); | ||
expect(getScroll(gd)).toBe(finalDataScroll); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + finalDataScroll + ')'); | ||
}); | ||
|
||
function dragScroll(element, rightClick) { | ||
var scrollBar = getScrollBar(); | ||
var scrollBarBB = scrollBar.getBoundingClientRect(); | ||
var legendHeight = getLegendHeight(gd); | ||
var scrollBoxYMax = gd._fullLayout.legend._height - legendHeight; | ||
var scrollBarYMax = legendHeight - | ||
scrollBarBB.height - | ||
2 * constants.scrollBarMargin; | ||
var initialDataScroll = getScroll(gd); | ||
var dy = 50; | ||
var finalDataScroll = Lib.constrain(initialDataScroll - | ||
dy / scrollBarYMax * scrollBoxYMax, | ||
-scrollBoxYMax, 0); | ||
|
||
var y0 = scrollBarBB.top + scrollBarBB.height / 5; | ||
var y1 = y0 + dy; | ||
|
||
var elBB = element.getBoundingClientRect(); | ||
var x = elBB.left + elBB.width / 2; | ||
|
||
var opts = {element: element}; | ||
if(rightClick) { | ||
opts.button = 2; | ||
opts.buttons = 2; | ||
} | ||
|
||
mouseEvent('mousedown', x, y0, opts); | ||
mouseEvent('mousemove', x, y1, opts); | ||
mouseEvent('mouseup', x, y1, opts); | ||
|
||
expect(finalDataScroll).not.toBe(initialDataScroll); | ||
|
||
return finalDataScroll; | ||
} | ||
|
||
it('should scroll on dragging the scrollbar', function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, these do test #2387, if I'm interpreting it correctly. What I think was happening in #2387 is that somehow the |
||
var finalDataScroll = dragScroll(getScrollBar()); | ||
var scrollBox = getScrollBox(); | ||
|
||
var dataScroll = getScroll(gd); | ||
expect(dataScroll).toBeCloseTo(finalDataScroll, 3); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + dataScroll + ')'); | ||
}); | ||
|
||
it('should not scroll on dragging the scrollbox', function() { | ||
var scrollBox = getScrollBox(); | ||
var finalDataScroll = dragScroll(scrollBox); | ||
|
||
var dataScroll = getScroll(gd); | ||
expect(dataScroll).not.toBeCloseTo(finalDataScroll, 3); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + dataScroll + ')'); | ||
}); | ||
|
||
it('should not scroll on dragging the scrollbar with a right click', function() { | ||
var finalDataScroll = dragScroll(getScrollBar(), true); | ||
var scrollBox = getScrollBox(); | ||
|
||
var dataScroll = getScroll(gd); | ||
expect(dataScroll).not.toBeCloseTo(finalDataScroll, 3); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + dataScroll + ')'); | ||
}); | ||
|
||
it('removes scroll bar and handlers when switching to horizontal', function(done) { | ||
expect(hasScrollBar()).toBe(true); | ||
|
||
Plotly.relayout(gd, {'legend.orientation': 'h'}) | ||
.then(function() { | ||
expect(hasScrollBar()).toBe(false); | ||
expect(getScroll(gd)).toBeUndefined(); | ||
|
||
getLegend().dispatchEvent(scrollTo(100)); | ||
expect(hasScrollBar()).toBe(false); | ||
expect(getScroll(gd)).toBeUndefined(); | ||
|
||
return Plotly.relayout(gd, {'legend.orientation': 'v'}); | ||
}) | ||
.then(function() { | ||
expect(hasScrollBar()).toBe(true); | ||
expect(getScroll(gd)).toBe(0); | ||
|
||
getLegend().dispatchEvent(scrollTo(100)); | ||
expect(hasScrollBar()).toBe(true); | ||
expect(getScroll(gd)).not.toBe(0); | ||
}) | ||
.catch(failTest) | ||
.then(done); | ||
}); | ||
|
||
it('updates scrollBar size/existence on deleteTraces', function(done) { | ||
expect(hasScrollBar()).toBe(true); | ||
var dataScroll = dragScroll(getScrollBar()); | ||
var scrollBarHeight = getScrollBar().getBoundingClientRect().height; | ||
var scrollBarHeight1; | ||
|
||
Plotly.deleteTraces(gd, [0]) | ||
.then(function() { | ||
expect(getScroll(gd)).toBeCloseTo(dataScroll, 3); | ||
scrollBarHeight1 = getScrollBar().getBoundingClientRect().height; | ||
expect(scrollBarHeight1).toBeGreaterThan(scrollBarHeight); | ||
|
||
// we haven't quite removed the scrollbar, but we should have clipped the scroll value | ||
return Plotly.deleteTraces(gd, [0, 1, 2, 3, 4, 5, 6, 7]); | ||
}) | ||
.then(function() { | ||
expect(getScroll(gd)).toBeGreaterThan(dataScroll + 1); | ||
var scrollBarHeight2 = getScrollBar().getBoundingClientRect().height; | ||
expect(scrollBarHeight2).toBeGreaterThan(scrollBarHeight1); | ||
|
||
// now no more scrollBar | ||
return Plotly.deleteTraces(gd, [0, 1]); | ||
}) | ||
.then(function() { | ||
expect(hasScrollBar()).toBe(false); | ||
expect(getScroll(gd)).toBeUndefined(); | ||
|
||
getLegend().dispatchEvent(scrollTo(100)); | ||
expect(hasScrollBar()).toBe(false); | ||
expect(getScroll(gd)).toBeUndefined(); | ||
}) | ||
.catch(failTest) | ||
.then(done); | ||
}); | ||
|
||
it('should keep the scrollbar position after a toggle event', function(done) { | ||
var legend = getLegend(), | ||
scrollBox = getScrollBox(), | ||
|
@@ -104,12 +244,12 @@ describe('The legend', function() { | |
|
||
legend.dispatchEvent(scrollTo(wheelDeltaY)); | ||
|
||
var dataScroll = scrollBox.getAttribute('data-scroll'); | ||
var dataScroll = getScroll(gd); | ||
toggle.dispatchEvent(new MouseEvent('mousedown')); | ||
toggle.dispatchEvent(new MouseEvent('mouseup')); | ||
setTimeout(function() { | ||
expect(+toggle.parentNode.style.opacity).toBeLessThan(1); | ||
expect(scrollBox.getAttribute('data-scroll')).toBe(dataScroll); | ||
expect(getScroll(gd)).toBe(dataScroll); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + dataScroll + ')'); | ||
done(); | ||
|
@@ -142,12 +282,12 @@ describe('The legend', function() { | |
expect(scrollBar.getAttribute('x')).toBe(scrollBarX); | ||
expect(scrollBar.getAttribute('y')).toBe(scrollBarY); | ||
|
||
var dataScroll = scrollBox.getAttribute('data-scroll'); | ||
var dataScroll = getScroll(gd); | ||
toggle.dispatchEvent(new MouseEvent('mousedown')); | ||
toggle.dispatchEvent(new MouseEvent('mouseup')); | ||
setTimeout(function() { | ||
expect(+toggle.parentNode.style.opacity).toBeLessThan(1); | ||
expect(scrollBox.getAttribute('data-scroll')).toBe(dataScroll); | ||
expect(getScroll(gd)).toBe(dataScroll); | ||
expect(scrollBox.getAttribute('transform')).toBe( | ||
'translate(0, ' + dataScroll + ')'); | ||
expect(scrollBar.getAttribute('width')).toBeGreaterThan(0); | ||
|
@@ -172,13 +312,18 @@ describe('The legend', function() { | |
scrollBar = getScrollBar(), | ||
legendHeight = getLegendHeight(gd); | ||
|
||
// The scrollbar is 20px tall and has 4px margins | ||
// The scrollbar is >20px tall and has 4px margins | ||
var scrollBarHeight = scrollBar.getBoundingClientRect().height; | ||
// in this mock there are 22 traces, and 13 are visible in the legend | ||
// at any given time | ||
expect(scrollBarHeight).toBeCloseTo(legendHeight * 13 / 22, -1); | ||
|
||
legend.dispatchEvent(scrollTo(-1000)); | ||
expect(+scrollBar.getAttribute('y')).toBe(4); | ||
expect(+scrollBar.getAttribute('y')).toBeCloseTo(4, 3); | ||
|
||
legend.dispatchEvent(scrollTo(10000)); | ||
expect(+scrollBar.getAttribute('y')).toBe(legendHeight - 4 - 20); | ||
expect(+scrollBar.getAttribute('y')) | ||
.toBeCloseTo(legendHeight - 4 - scrollBarHeight, 3); | ||
}); | ||
|
||
it('should be removed from DOM when \'showlegend\' is relayout\'ed to false', function(done) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notice that I moved the drag point away from the center of the
scrollBar
, thereby testing that it drags from where you grab it rather than snapping to the center.