Skip to content

IroComponentWrapper performance improvement #266

Description

@dcog989

Hi. I'll leave this as an issue as I don't time to backtrack and apply to the tsx code and raise PR.

"The function element.getBoundingClientRect() calculates the size and position of an element relative to the viewport. Calling it repeatedly, especially within event handlers like mousemove or touchmove (which can fire many times per second during a drag), is a performance concern. Each call can potentially trigger a "reflow" or "layout" in the browser, where the browser has to recalculate the positions and geometries of elements on the page. This is computationally expensive and can lead to janky or unresponsive UI."

IroComponentWrapper.prototype.handleEvent = function handleEvent (e) {
    var this$1 = this;
    var inputHandler = this.props.onInput;
    var point = e.touches ? e.changedTouches[0] : e;
    var x, y;

    // Prevent default browser action for events where we are handling interaction
    // (touchstart, touchmove, mousedown, mousemove).
    // mouseup and touchend don't typically need preventDefault unless they cause unwanted clicks.
    if (e.type === "touchstart" || e.type === "touchmove" || e.type === "mousedown" || e.type === "mousemove") {
        e.preventDefault();
    }

    switch (e.type) {
        case "mousedown": /* MouseDown */
        case "touchstart": /* TouchStart */
            // Cache the bounds at the start of an interaction
            this._interactionBounds = this.base.getBoundingClientRect(); // <<<<< CACHE HERE
            x = point.clientX - this._interactionBounds.left;
            y = point.clientY - this._interactionBounds.top;

            var result = inputHandler(x, y, 0 /* Start */);
            if (result !== false) {
                SECONDARY_EVENTS.forEach(function (event) {
                    document.addEventListener(event, this$1, { passive: false });
                });
            }
            break;
        case "mousemove": /* MouseMove */
        case "touchmove": /* TouchMove */
            // Use cached bounds if they exist (they should after mousedown/touchstart)
            if (!this._interactionBounds) { break; } // Safety break
            x = point.clientX - this._interactionBounds.left; // <<<<< USE CACHED BOUNDS
            y = point.clientY - this._interactionBounds.top;  // <<<<< USE CACHED BOUNDS
            inputHandler(x, y, 1 /* Move */);
            break;
        case "mouseup": /* MouseUp */
        case "touchend": /* TouchEnd */
            // Use cached bounds for the final position
            if (!this._interactionBounds) { break; } // Safety break
            x = point.clientX - this._interactionBounds.left; // <<<<< USE CACHED BOUNDS
            y = point.clientY - this._interactionBounds.top;  // <<<<< USE CACHED BOUNDS
            inputHandler(x, y, 2 /* End */);

            // Clear the cached bounds now that the interaction has ended
            this._interactionBounds = null; // <<<<< CLEAR CACHE

            SECONDARY_EVENTS.forEach(function (event) {
                document.removeEventListener(event, this$1, { passive: false });
            });
            break;
    }
};

I've briefly tested the amended code and it seems to work OK and improve smoothness.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions