Skip to content

Add Touch Support to RangeSlider #1098

Closed
@cristiantx

Description

@cristiantx

Range Slider should support touch events so users are able to interact with that component as expected. Otherwise it feels broken on mobile devices.

This is related with #480, but not the same. I think this one is more important since the expected behaviour of the component is not achieved with this issue.

I've managed to add the events to the method in charge of this (https://github.com/plotly/plotly.js/blob/master/src/components/rangeslider/draw.js#L158) but seems like I need to do two taps for it to work. I suspect that the touchmove doesn't trigger just after the touchstart. Like mousemove and mousedown does.

My code:

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
    var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
        grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
        grabAreaMax = rangeSlider.select('rect.' + constants.grabAreaMaxClassName).node();

    function mouseDownHandler() {
        var event = d3.event,
            target = event.target,
            startX = event.clientX || event.touches[0].clientX,
            offsetX = startX - rangeSlider.node().getBoundingClientRect().left,
            minVal = opts.d2p(axisOpts.range[0]),
            maxVal = opts.d2p(axisOpts.range[1]);

        var dragCover = dragElement.coverSlip();

        dragCover.addEventListener('mousemove', mouseMove);
        dragCover.addEventListener('touchmove', mouseMove);
        dragCover.addEventListener('mouseup', mouseUp);
        dragCover.addEventListener('touchend', mouseUp);

        function mouseMove(e) {
            var clientX = e.clientX || e.touches[0].clientX;
            var delta = +clientX - startX;
            var pixelMin, pixelMax, cursor;

            switch(target) {
                case slideBox:
                    cursor = 'ew-resize';
                    pixelMin = minVal + delta;
                    pixelMax = maxVal + delta;
                    break;

                case grabAreaMin:
                    cursor = 'col-resize';
                    pixelMin = minVal + delta;
                    pixelMax = maxVal;
                    break;

                case grabAreaMax:
                    cursor = 'col-resize';
                    pixelMin = minVal;
                    pixelMax = maxVal + delta;
                    break;

                default:
                    cursor = 'ew-resize';
                    pixelMin = offsetX;
                    pixelMax = offsetX + delta;
                    break;
            }

            if(pixelMax < pixelMin) {
                var tmp = pixelMax;
                pixelMax = pixelMin;
                pixelMin = tmp;
            }

            opts._pixelMin = pixelMin;
            opts._pixelMax = pixelMax;

            setCursor(d3.select(dragCover), cursor);
            setDataRange(rangeSlider, gd, axisOpts, opts);
        }

        function mouseUp() {
            dragCover.removeEventListener('mousemove', mouseMove);
            dragCover.removeEventListener('mouseup', mouseUp);
            dragCover.removeEventListener('touchmove', mouseMove);
            dragCover.removeEventListener('touchend', mouseUp);
            Lib.removeElement(dragCover);
        }

    }

    rangeSlider.on('mousedown', mouseDownHandler );
    rangeSlider.on('touchstart', mouseDownHandler );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    communitycommunity contributionfeaturesomething new

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions