diff --git a/draftlogs/5856_add.md b/draftlogs/5856_add.md new file mode 100644 index 00000000000..e1b72c99550 --- /dev/null +++ b/draftlogs/5856_add.md @@ -0,0 +1,2 @@ +- Add touch support to `slider` component [[#5856](https://github.com/plotly/plotly.js/pull/5856)], + with thanks to @keul for the contribution! \ No newline at end of file diff --git a/src/components/sliders/draw.js b/src/components/sliders/draw.js index 5ab3521d572..1ad51536c9b 100644 --- a/src/components/sliders/draw.js +++ b/src/components/sliders/draw.js @@ -461,7 +461,7 @@ function attachGripEvents(item, gd, sliderGroup) { return sliderGroup.data()[0]; } - item.on('mousedown', function() { + function mouseDownHandler() { var sliderOpts = getSliderOpts(); gd.emit('plotly_sliderstart', {slider: sliderOpts}); @@ -475,25 +475,36 @@ function attachGripEvents(item, gd, sliderGroup) { handleInput(gd, sliderGroup, sliderOpts, normalizedPosition, true); sliderOpts._dragging = true; - $gd.on('mousemove', function() { + function mouseMoveHandler() { var sliderOpts = getSliderOpts(); var normalizedPosition = positionToNormalizedValue(sliderOpts, d3.mouse(node)[0]); handleInput(gd, sliderGroup, sliderOpts, normalizedPosition, false); - }); + } + + $gd.on('mousemove', mouseMoveHandler); + $gd.on('touchmove', mouseMoveHandler); - $gd.on('mouseup', function() { + function mouseUpHandler() { var sliderOpts = getSliderOpts(); sliderOpts._dragging = false; grip.call(Color.fill, sliderOpts.bgcolor); $gd.on('mouseup', null); $gd.on('mousemove', null); + $gd.on('touchend', null); + $gd.on('touchmove', null); gd.emit('plotly_sliderend', { slider: sliderOpts, step: sliderOpts.steps[sliderOpts.active] }); - }); - }); + } + + $gd.on('mouseup', mouseUpHandler); + $gd.on('touchend', mouseUpHandler); + } + + item.on('mousedown', mouseDownHandler); + item.on('touchstart', mouseDownHandler); } function drawTicks(sliderGroup, sliderOpts) { diff --git a/test/jasmine/assets/touch_event.js b/test/jasmine/assets/touch_event.js index dbd299ae05e..1d8ed68c428 100644 --- a/test/jasmine/assets/touch_event.js +++ b/test/jasmine/assets/touch_event.js @@ -9,6 +9,10 @@ module.exports = function(type, x, y, opts) { target: el, clientX: x, clientY: y, + screenX: x, + screenY: y, + pageX: x, + pageY: y, radiusX: 2.5, radiusY: 2.5, rotationAngle: 10, diff --git a/test/jasmine/tests/sliders_test.js b/test/jasmine/tests/sliders_test.js index 85021d3d51d..907c2b12fe1 100644 --- a/test/jasmine/tests/sliders_test.js +++ b/test/jasmine/tests/sliders_test.js @@ -7,6 +7,7 @@ var Plotly = require('@lib/index'); var Lib = require('@src/lib'); var createGraphDiv = require('../assets/create_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); +var touchEvent = require('../assets/touch_event'); var delay = require('../assets/delay'); var assertPlotSize = require('../assets/custom_assertions').assertPlotSize; @@ -507,6 +508,44 @@ describe('sliders interactions', function() { .then(done, done.fail); }); + it('should respond to touch interactions', function(done) { + var firstGroup = gd._fullLayout._infolayer.select('.' + constants.railTouchRectClass); + var firstGrip = gd._fullLayout._infolayer.select('.' + constants.gripRectClass); + var railNode = firstGroup.node(); + var gripNode = firstGrip.node(); + var touchRect = railNode.getBoundingClientRect(); + var gripRect = gripNode.getBoundingClientRect(); + + var originalFill = gripNode.style.fill; + + expect(mockCopy.layout.sliders[0].active).toEqual(2); + + // Dispatch start of touch where the grip control is + touchEvent('touchstart', gripRect.left + 5, gripRect.top + 5); + + expect(mockCopy.layout.sliders[0].active).toEqual(2); + var touchdownFill = gripNode.style.fill; + expect(touchdownFill).not.toEqual(originalFill); + + // Drag to the right side: + touchEvent('touchmove', touchRect.left + touchRect.width - 5, gripRect.top + 5); + + var touchmoveFill = gripNode.style.fill; + expect(touchmoveFill).toEqual(touchdownFill); + + delay(100)() + .then(function() { + expect(mockCopy.layout.sliders[0].active).toEqual(5); + + touchEvent('touchend', touchRect.left + touchRect.width - 5, gripRect.top + 5); + + var touchupFill = gripNode.style.fill; + expect(touchupFill).toEqual(originalFill); + expect(mockCopy.layout.sliders[0].active).toEqual(5); + }) + .then(done, done.fail); + }); + it('should issue events on interaction', function(done) { var cntStart = 0; var cntInteraction = 0;