Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Touch move fire only once when implementing "less" like scrolling on mobile

I'm trying to to implement touch scroll in less extension to jQuery Terminal. It work similar to less unix command.

I have this code:

self.touch_scroll(function(event) {
    // how much difference changed since last touch move
    var delta = event.current.clientY - event.previous.clientY;
    var ret;
    var interpreter = interpreters.top();
    if (is_function(interpreter.touchscroll)) {
        ret = interpreter.touchscroll(event, delta, self);
    } else if (is_function(settings.touchscroll)) {
        ret = settings.touchscroll(event, delta, self);
    }
    if (ret === true) {
        return;
    }
    return false;
});
// make_callback_plugin is helper that use $.Callbacks and make sure that there is only
// one handler on the element
$.fn.touch_scroll = make_callback_plugin({
    name: 'touch',
    init: function(handler) {
        var origin;
        var previous;
        $(this).on('touchstart.scroll', function(e) {
            e = e.originalEvent;
            if (e.touches.length === 1) {
                previous = origin = e.touches[0];
            }
        }).on('touchmove.scroll', function(e) {
            e = e.originalEvent;
            console.log(!!origin + ' && ' + (e.touches.length) + ' === 1');
            if (origin && e.touches.length === 1) {
                var current = e.touches[0];
                var ret = handler({
                    origin: origin,
                    previous: previous,
                    current: current
                });
                if (ret === false) {
                    // this don't change anything
                    e.preventDefault();
                }
                previous = current;
            }
        }).on('touchend.scroll', function() {
            if (origin || previous) {
                origin = previous = null;
            }
        });
    },
    destroy: function() {
        $(this).off('touchstart.scroll touchmove.scroll touchend.scroll');
    }
});

and inside less I have:

    function scroll(delta, scroll_by) {
        if (delta > 0) {
            pos -= scroll_by;
            if (pos < 0) {
                pos = 0;
            }
        } else {
            pos += scroll_by;
            if (pos - 1 > lines.length - rows) {
                pos = lines.length - rows + 1;
            }
        }
        print();
        return true;
    }
    term.push($.noop, {
        onResize: refresh_view,
        touchscroll: function(event, delta) {
            console.log({delta});
            var offset = Math.abs(delta);
            // 14 is default height of single line in pixels
            scroll(delta, Math.ceil(offset / 14));
            return false;
        },
        mousewheel: function(event, delta) {
            return scroll(delta, scroll_by);
        }, 

I also have this css:

.terminal-less {
    touch-action: none;
    overscroll-behavior-y: contain;
}

on Mousewheel scrolling works good it scroll with the same amount of scroll_by which is by default 3 (seems about right). (pos is lines offset so if I use pos++ it move/scroll by one line, delta in touchscroll is positive or negative from about -20 to 20 pixels.

The problem I have and the question is, how can I make it scroll with the finger? it don't feel right. Also it scroll only once it don't move with the finger. touchmove fire only once, shoudn't it fire while I move the finger while touching the phone?

Anyone have experience with this type of touch scroll behavior?

I was searching for similar problem and didn't found solution. Do you know why touchmove could fire once? The only thing I can think of was textarea that is used as clipboard (on mobile it's also used to enable virtual keyboard), but I've set background to red and it don't move on Android. I was testing other code from this drawing demo:

https://zipso.net/a-simple-touchscreen-sketchpad-using-javascript-and-html5/

and it works fine, touch move keeps firing while you move the finger.

Any ideas? It will be hard to replicate but if somone is interested in investigation I can put all my code on github in jQuery Terminal repo (in some branch).

What's weird is that touchend don't fire after touchmove, it fire once only when I click on the terminal to enable keyboard.

I've tried to monkey patch jQuery on and log each time it fire but I didn't have any other event (that may prevent default behavior) also according to docs mouse events fire after touchend and those don't fire.

like image 976
jcubic Avatar asked Feb 26 '20 10:02

jcubic


1 Answers

What you need is simple .terminal-wrapper { pointer-events: none; } (based on the devel branch). But with this rule you can't select the text, that's why you need to use it only for mobile devices.

I'm not sure if this will block the selection of text on mobile, but if so, you can try to add this on touchstart (or even on touchmove as the first instruction) and remove it on touchend.

Also, I had to add some JS code, because without it interpreter.touchScroll is undefined. But this is not the main cause of the problem.

interpreters = new Stack($.extend({}, settings.extra, {
    name: settings.name,
    prompt: prompt,
    keypress: settings.keypress,
    keydown: settings.keydown,
    resize: settings.onResize,
    greetings: settings.greetings,
    mousewheel: settings.mousewheel,
    touchScroll: settings.touchScroll, // NEW LINE
    history: settings.history,
    keymap: new_keymap
}, interpreter));
self.touch_scroll(function(event) {
    var delta = event.current.clientY - event.previous.clientY;
    var ret;
    var interpreter = interpreters.top(); // NEW LINE
    if (is_function(interpreter.touchScroll)) {
        ret = interpreter.touchScroll(event, delta, self);
    } else if (is_function(settings.touchScroll)) {
        ret = settings.touchScroll(event, delta, self);
    }
    if (ret === true) {
        return;
    }
});

Without pointer-events: none;

enter image description here

With pointer-events: none;

enter image description here

like image 53
artanik Avatar answered Oct 20 '22 07:10

artanik