diff --git a/src/components/sliders/draw.js b/src/components/sliders/draw.js index 953d131ad17..6679dcb408f 100644 --- a/src/components/sliders/draw.js +++ b/src/components/sliders/draw.js @@ -366,6 +366,7 @@ function handleInput(gd, sliderGroup, sliderOpts, normalizedPosition, doTransiti } function setActive(gd, sliderGroup, sliderOpts, index, doCallback, doTransition) { + var previousActive = sliderOpts.active; sliderOpts._input.active = sliderOpts.active = index; var step = sliderOpts.steps[sliderOpts.active]; @@ -373,6 +374,13 @@ function setActive(gd, sliderGroup, sliderOpts, index, doCallback, doTransition) sliderGroup.call(setGripPosition, sliderOpts, sliderOpts.active / (sliderOpts.steps.length - 1), doTransition); sliderGroup.call(drawCurrentValue, sliderOpts); + gd.emit('plotly_sliderchange', { + slider: sliderOpts, + step: sliderOpts.steps[sliderOpts.active], + interaction: doCallback, + previousActive: previousActive + }); + if(step && step.method && doCallback) { if(sliderGroup._nextMethod) { // If we've already queued up an update, just overwrite it with the most recent: @@ -399,6 +407,8 @@ function attachGripEvents(item, gd, sliderGroup, sliderOpts) { var $gd = d3.select(gd); item.on('mousedown', function() { + gd.emit('plotly_sliderstart', {slider: sliderOpts}); + var grip = sliderGroup.select('.' + constants.gripRectClass); d3.event.stopPropagation(); @@ -419,6 +429,11 @@ function attachGripEvents(item, gd, sliderGroup, sliderOpts) { grip.call(Color.fill, sliderOpts.bgcolor); $gd.on('mouseup', null); $gd.on('mousemove', null); + + gd.emit('plotly_sliderend', { + slider: sliderOpts, + step: sliderOpts.steps[sliderOpts.active] + }); }); }); } diff --git a/test/jasmine/tests/sliders_test.js b/test/jasmine/tests/sliders_test.js index 1f7fa4b8a79..0e7c8a0bbcb 100644 --- a/test/jasmine/tests/sliders_test.js +++ b/test/jasmine/tests/sliders_test.js @@ -319,6 +319,70 @@ describe('sliders interactions', function() { }, 100); }); + it('should issue events on interaction', function(done) { + var cntStart = 0; + var cntInteraction = 0; + var cntNonInteraction = 0; + var cntEnd = 0; + + gd.on('plotly_sliderstart', function() { + cntStart++; + }).on('plotly_sliderchange', function(datum) { + if(datum.interaction) { + cntInteraction++; + } else { + cntNonInteraction++; + } + }).on('plotly_sliderend', function() { + cntEnd++; + }); + + function assertEventCounts(starts, interactions, noninteractions, ends) { + expect( + [cntStart, cntInteraction, cntNonInteraction, cntEnd] + ).toEqual( + [starts, interactions, noninteractions, ends] + ); + } + + assertEventCounts(0, 0, 0, 0); + + var firstGroup = gd._fullLayout._infolayer.select('.' + constants.railTouchRectClass); + var railNode = firstGroup.node(); + var touchRect = railNode.getBoundingClientRect(); + + // Dispatch a click on the right side of the bar: + railNode.dispatchEvent(new MouseEvent('mousedown', { + clientY: touchRect.top + 5, + clientX: touchRect.left + touchRect.width - 5, + })); + + setTimeout(function() { + // One slider received a mousedown, one received an interaction, and one received a change: + assertEventCounts(1, 1, 1, 0); + + // Drag to the left side: + gd.dispatchEvent(new MouseEvent('mousemove', { + clientY: touchRect.top + 5, + clientX: touchRect.left + 5, + })); + + setTimeout(function() { + // On move, now to changes for the each slider, and no ends: + assertEventCounts(1, 2, 2, 0); + + gd.dispatchEvent(new MouseEvent('mouseup')); + + setTimeout(function() { + // Now an end: + assertEventCounts(1, 2, 2, 1); + + done(); + }, 50); + }, 50); + }, 50); + }); + function assertNodeCount(query, cnt) { expect(d3.selectAll(query).size()).toEqual(cnt); }