Skip to content

Selection highlight uses stale bounds after resize/re-render #2567

@gisenberg

Description

@gisenberg

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

When a selection range is active (via click-drag or playbackRange) and the browser/container is resized, the selection highlight rectangles remain at their pre-resize positions. The highlight becomes visually misaligned with the re-rendered score, where the selection is offset horizontally, the wrong width, or on the wrong staff system line.

Expected Behavior

After a resize triggers a re-render, the selection highlight should reposition to match the new layout coordinates.

Steps To Reproduce

  1. Load a GuitarPro file
  2. Click-drag to select a range of measures (or set playbackRange)
  3. Resize the browser window or container so AlphaTab re-renders the score
  4. Observe: the selection highlight rectangles are at the old positions, not aligned with the re-rendered measures

Link to jsFiddle, CodePen, Project

No response

Version and Environment

alphaTab 1.8.1
Browser: Electron 40 / Chrome 144 (also reproducible in standard browsers)
Windows 11

Platform

Web

Anything else?

Root cause is in AlphaTabApiBase. The postRenderFinished handler calls _cursorSelectRange(this._selectionStart, this._selectionEnd) to re-apply the selection after re-render. However, _cursorSelectRange caches beat bounds on the selection objects:

if (!startBeat.bounds) {
    startBeat.bounds = cache.findBeat(startBeat.beat) ?? undefined;
}
if (!endBeat.bounds) {
    endBeat.bounds = cache.findBeat(endBeat.beat) ?? undefined;
}

Since bounds was populated from the pre-resize layout, it's still truthy, so cache.findBeat() is never called, and the stale coordinates (realBounds.x, realBounds.w, visualBounds.y, etc.) are used to position the highlight rectangles.

Suggested fix is to clear the cached bounds before re-applying the selection in postRenderFinished:

this._renderer.postRenderFinished.on(() => {
    if (!this._selectionStart || !this._hasCursor || !this.settings.player.enableUserInteraction) {
        return;
    }
    // Force fresh coordinate lookup from the new boundsLookup cache
    if (this._selectionStart) {
        this._selectionStart.bounds = undefined;
    }
    if (this._selectionEnd) {
        this._selectionEnd.bounds = undefined;
    }
    this._cursorSelectRange(this._selectionStart, this._selectionEnd);
});

Metadata

Metadata

Assignees

Labels

area-playerRelated to the audio playback engine.platform-allAffects all platformsstate-acceptedThis is a valid topic to work on.

Type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions