EN
                                
                            
                        JavaScript - check for scrollTo() method got finished
                                    10
                                    points
                                
                                In this article, we would like to show how to detect when scrollTo() method finished execution in JavaScript.
There is not available event that signals when scrollTo() method ends execution, so there is needed to use some trick to solve the problem. In the example solution we provide reusable logic that checks state once per some time.
Example solution:
function SmoothScroller(element, interval = 100, chances = 3, tolerance = 1.0) {
    const bound = tolerance * tolerance;
    let id = null;
    this.scroll = (x, y, callback) => {
        if (id) {
            clearTimeout(id);
            id = null;
        }
        const options = {
            left: x,
            top: y,
            behavior: 'smooth'
        };
        element.scrollTo(options);
        if (callback) {
            let state = +Infinity;
            const action = () => {
                const elementX = element.scrollLeft;
                const elementY = element.scrollTop;
                const dx = x - elementX;
                const dy = y - elementY;
                const square = dx * dx + dy * dy;
                if (square < bound) {
                    callback('done');
                } else {
                    if (square === state) {
                        if (chances > 0) {
                            state = square;
                            chances -= 1;
                            id = setTimeout(action, interval);
                        } else {
                            callback('canceled');
                        }
                    } else {
                        state = square;
                        id = setTimeout(action, interval);
                    }
                }
            };
            id = setTimeout(action, interval);
        }
    };
    this.stop = () => {
        if (id) {
            clearTimeout(id);
            id = null;
        }
    };
}
// Usage example:
const element = ...  // e.g. document.querySelector('#element');
const scroller = new SmoothScroller(element);
scroller.scroll(50, 100, (status) => console.log(`status: ${status}`));  // scrolls into (x, y) = (50, 100) position
Where:
- in
 SmoothScrollerclass constructor:
elementrepresents handle to HTML element that is scrolled,intervalmeans how often state checking is done, e.g.100means once per 100ms,chancesmeans how many state failing checks are accepted, e.g. when something or someone tries to stop scrolling ro changes scrolling destination point,tolerancewas introduced to makes possible floating-point values usage by web browser when window has sets zoom,- in
 scroll()method:
xandymeans scrolling destination point,callbackmeans function called when scrolling is done or canceled.
Practical example
// ONLINE-RUNNER:browser;
<style>
    div.element {
        border: 1px solid silver;
        width: 400px;
        height: 300px;
        white-space: nowrap;
        overflow: auto;
    }
</style>
<script>
    // Common reusable logic:
    function SmoothScroller(element, interval = 100, chances = 3, tolerance = 1.0) {
        const bound = tolerance * tolerance;
        let id = null;
        this.scroll = (x, y, callback) => {
            if (id) {
                clearTimeout(id);
                id = null;
            }
            const options = {
                left: x,
                top: y,
                behavior: 'smooth'
            };
            element.scrollTo(options);
            if (callback) {
                let state = +Infinity;
                const action = () => {
                    const elementX = element.scrollLeft;
                    const elementY = element.scrollTop;
                    const dx = x - elementX;
                    const dy = y - elementY;
                    const square = dx * dx + dy * dy;
                    if (square < bound) {
                        callback('done');
                    } else {
                        if (square === state) {
                            if (chances > 0) {
                                state = square;
                                chances -= 1;
                                id = setTimeout(action, interval);
                            } else {
                                callback('canceled');
                            }
                        } else {
                            state = square;
                            id = setTimeout(action, interval);
                        }
                    }
                };
                id = setTimeout(action, interval);
            }
        };
        this.stop = () => {
            if (id) {
                clearTimeout(id);
                id = null;
            }
        };
    }
</script>
<button onclick="scrollElement(0, 0)">Scroll to (0, 0)</button>
<button onclick="scrollElement(400, 500)">Scroll to (400, 500)</button>
<button onclick="scrollElement(0, 1000)">Scroll to (0, 1000)</button>
<br /><br />
<div class="element" id="element">
    <!-- Automatically generated text is placed here ... -->
</div>
<script>
    const handle = document.querySelector('#element');
    // Element content preparation:
    let text = '';
    for (let i = 0; i < 100; ++i) {
        for (let j = 0; j < 10; ++j) {
            text += 'Verry long line ...';
        }
        text += '\n';
    }
    handle.innerText = text;
    // Element scroller usage:
    const scroller = new SmoothScroller(handle);
    function scrollElement(x, y) {
        const callback = (status) => {
            console.log(`status: ${status}`);
        };
        scroller.scroll(x, y, callback);
    }
</script>