@coderline/alphatab 1.8.0-alpha.1650 → 1.8.0-alpha.1653
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alphaTab.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +486 -131
- package/dist/alphaTab.d.ts +106 -4
- package/dist/alphaTab.js +486 -131
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +2 -2
package/dist/alphaTab.core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.0-alpha.
|
|
2
|
+
* alphaTab v1.8.0-alpha.1653 (develop, build 1653)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -203,9 +203,9 @@ class AlphaTabError extends Error {
|
|
|
203
203
|
* @internal
|
|
204
204
|
*/
|
|
205
205
|
class VersionInfo {
|
|
206
|
-
static version = '1.8.0-alpha.
|
|
207
|
-
static date = '2025-12-
|
|
208
|
-
static commit = '
|
|
206
|
+
static version = '1.8.0-alpha.1653';
|
|
207
|
+
static date = '2025-12-23T02:21:29.054Z';
|
|
208
|
+
static commit = 'b85546e1908f06f3bd049e35e881c4856fb92846';
|
|
209
209
|
static print(print) {
|
|
210
210
|
print(`alphaTab ${VersionInfo.version}`);
|
|
211
211
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -13089,7 +13089,7 @@ class Bounds {
|
|
|
13089
13089
|
*/
|
|
13090
13090
|
class MasterBarBounds {
|
|
13091
13091
|
/**
|
|
13092
|
-
*
|
|
13092
|
+
* The MasterBar index within the data model represented by these bounds.
|
|
13093
13093
|
*/
|
|
13094
13094
|
index = 0;
|
|
13095
13095
|
/**
|
|
@@ -13297,6 +13297,7 @@ class BoundsLookup {
|
|
|
13297
13297
|
mb.visualBounds = this._boundsToJson(masterBar.visualBounds);
|
|
13298
13298
|
mb.realBounds = this._boundsToJson(masterBar.realBounds);
|
|
13299
13299
|
mb.index = masterBar.index;
|
|
13300
|
+
mb.isFirstOfLine = masterBar.isFirstOfLine;
|
|
13300
13301
|
mb.bars = [];
|
|
13301
13302
|
for (const bar of masterBar.bars) {
|
|
13302
13303
|
const b = {};
|
|
@@ -13353,7 +13354,7 @@ class BoundsLookup {
|
|
|
13353
13354
|
mb.lineAlignedBounds = BoundsLookup._boundsFromJson(masterBar.lineAlignedBounds);
|
|
13354
13355
|
mb.visualBounds = BoundsLookup._boundsFromJson(masterBar.visualBounds);
|
|
13355
13356
|
mb.realBounds = BoundsLookup._boundsFromJson(masterBar.realBounds);
|
|
13356
|
-
|
|
13357
|
+
lookup.addMasterBar(mb);
|
|
13357
13358
|
for (const bar of masterBar.bars) {
|
|
13358
13359
|
const b = new BarBounds();
|
|
13359
13360
|
b.visualBounds = BoundsLookup._boundsFromJson(bar.visualBounds);
|
|
@@ -43657,6 +43658,12 @@ var ScrollMode;
|
|
|
43657
43658
|
* Scrolling happens as soon the cursors exceed the displayed range.
|
|
43658
43659
|
*/
|
|
43659
43660
|
ScrollMode[ScrollMode["OffScreen"] = 2] = "OffScreen";
|
|
43661
|
+
/**
|
|
43662
|
+
* Scrolling happens constantly in a smooth fashion.
|
|
43663
|
+
* This will disable the use of any native scroll optimizations but
|
|
43664
|
+
* manually scroll the scroll container in the required speed.
|
|
43665
|
+
*/
|
|
43666
|
+
ScrollMode[ScrollMode["Smooth"] = 3] = "Smooth";
|
|
43660
43667
|
})(ScrollMode || (ScrollMode = {}));
|
|
43661
43668
|
/**
|
|
43662
43669
|
* This object defines the details on how to generate the vibrato effects.
|
|
@@ -48587,6 +48594,25 @@ class MidiFileGenerator {
|
|
|
48587
48594
|
}
|
|
48588
48595
|
}
|
|
48589
48596
|
|
|
48597
|
+
/**
|
|
48598
|
+
* Represents the information related to a resize event.
|
|
48599
|
+
* @public
|
|
48600
|
+
*/
|
|
48601
|
+
class ResizeEventArgs {
|
|
48602
|
+
/**
|
|
48603
|
+
* Gets the size before the resizing happened.
|
|
48604
|
+
*/
|
|
48605
|
+
oldWidth = 0;
|
|
48606
|
+
/**
|
|
48607
|
+
* Gets the size after the resize was complete.
|
|
48608
|
+
*/
|
|
48609
|
+
newWidth = 0;
|
|
48610
|
+
/**
|
|
48611
|
+
* Gets the settings currently used for rendering.
|
|
48612
|
+
*/
|
|
48613
|
+
settings = null;
|
|
48614
|
+
}
|
|
48615
|
+
|
|
48590
48616
|
/**
|
|
48591
48617
|
* Lists the different position modes for {@link BarRendererBase.getBeatX}
|
|
48592
48618
|
* @internal
|
|
@@ -49013,22 +49039,262 @@ class ScoreRendererWrapper {
|
|
|
49013
49039
|
}
|
|
49014
49040
|
|
|
49015
49041
|
/**
|
|
49016
|
-
*
|
|
49017
|
-
* @
|
|
49042
|
+
* Some basic scroll handler checking for changed offsets and scroll if changed.
|
|
49043
|
+
* @internal
|
|
49018
49044
|
*/
|
|
49019
|
-
class
|
|
49020
|
-
|
|
49021
|
-
|
|
49022
|
-
|
|
49023
|
-
|
|
49024
|
-
|
|
49025
|
-
|
|
49026
|
-
|
|
49027
|
-
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49045
|
+
class BasicScrollHandler {
|
|
49046
|
+
api;
|
|
49047
|
+
lastScroll = -1;
|
|
49048
|
+
constructor(api) {
|
|
49049
|
+
this.api = api;
|
|
49050
|
+
}
|
|
49051
|
+
[Symbol.dispose]() {
|
|
49052
|
+
}
|
|
49053
|
+
forceScrollTo(currentBeatBounds) {
|
|
49054
|
+
this._scrollToBeat(currentBeatBounds, true);
|
|
49055
|
+
this.lastScroll = -1; // force new scroll on next update
|
|
49056
|
+
}
|
|
49057
|
+
_scrollToBeat(currentBeatBounds, force) {
|
|
49058
|
+
const newLastScroll = this.calculateLastScroll(currentBeatBounds);
|
|
49059
|
+
// no change, and no instant/force scroll
|
|
49060
|
+
if (newLastScroll === this.lastScroll && !force) {
|
|
49061
|
+
return;
|
|
49062
|
+
}
|
|
49063
|
+
this.lastScroll = newLastScroll;
|
|
49064
|
+
this.doScroll(currentBeatBounds);
|
|
49065
|
+
}
|
|
49066
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, _actualBeatCursorTransitionDuration) {
|
|
49067
|
+
this._scrollToBeat(startBeat, false);
|
|
49068
|
+
}
|
|
49069
|
+
}
|
|
49070
|
+
/**
|
|
49071
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Continuous}.
|
|
49072
|
+
* Whenever the system changes, we scroll to the new system position vertically.
|
|
49073
|
+
* @internal
|
|
49074
|
+
*/
|
|
49075
|
+
class VerticalContinuousScrollHandler extends BasicScrollHandler {
|
|
49076
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49077
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49078
|
+
}
|
|
49079
|
+
doScroll(currentBeatBounds) {
|
|
49080
|
+
const ui = this.api.uiFacade;
|
|
49081
|
+
const settings = this.api.settings;
|
|
49082
|
+
const scroll = ui.getScrollContainer();
|
|
49083
|
+
const elementOffset = ui.getOffset(scroll, this.api.container);
|
|
49084
|
+
const y = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49085
|
+
ui.scrollToY(scroll, elementOffset.y + y, this.api.settings.player.scrollSpeed);
|
|
49086
|
+
}
|
|
49087
|
+
}
|
|
49088
|
+
/**
|
|
49089
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.OffScreen}.
|
|
49090
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49091
|
+
* @internal
|
|
49092
|
+
*/
|
|
49093
|
+
class VerticalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49094
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49095
|
+
// check for system change
|
|
49096
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49097
|
+
}
|
|
49098
|
+
doScroll(currentBeatBounds) {
|
|
49099
|
+
const ui = this.api.uiFacade;
|
|
49100
|
+
const settings = this.api.settings;
|
|
49101
|
+
const scroll = ui.getScrollContainer();
|
|
49102
|
+
const elementBottom = scroll.scrollTop + ui.getOffset(null, scroll).h;
|
|
49103
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49104
|
+
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
49105
|
+
barBoundings.visualBounds.y < scroll.scrollTop) {
|
|
49106
|
+
const scrollTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49107
|
+
ui.scrollToY(scroll, scrollTop, settings.player.scrollSpeed);
|
|
49108
|
+
}
|
|
49109
|
+
}
|
|
49110
|
+
}
|
|
49111
|
+
/**
|
|
49112
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Smooth}.
|
|
49113
|
+
* vertical smooth scrolling aims to place the on-time position
|
|
49114
|
+
* at scrollOffsetY **at the time when a system starts**
|
|
49115
|
+
* this means when a system starts, it is at scrollOffsetY,
|
|
49116
|
+
* then gradually scrolls down the system height reaching the bottom
|
|
49117
|
+
* when the system completes.
|
|
49118
|
+
* @internal
|
|
49119
|
+
*/
|
|
49120
|
+
class VerticalSmoothScrollHandler {
|
|
49121
|
+
_api;
|
|
49122
|
+
_lastScroll = -1;
|
|
49123
|
+
_scrollContainerResizeUnregister;
|
|
49124
|
+
constructor(api) {
|
|
49125
|
+
this._api = api;
|
|
49126
|
+
// we need a resize listener for the overflow calculation
|
|
49127
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49128
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49129
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49130
|
+
const viewPortSize = scrollContainer.width;
|
|
49131
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49132
|
+
// that's why we need the whole width as additional overflow
|
|
49133
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49134
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, true);
|
|
49135
|
+
});
|
|
49136
|
+
}
|
|
49137
|
+
[Symbol.dispose]() {
|
|
49138
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, true);
|
|
49139
|
+
this._scrollContainerResizeUnregister();
|
|
49140
|
+
}
|
|
49141
|
+
forceScrollTo(currentBeatBounds) {
|
|
49142
|
+
const ui = this._api.uiFacade;
|
|
49143
|
+
const settings = this._api.settings;
|
|
49144
|
+
const scroll = ui.getScrollContainer();
|
|
49145
|
+
const systemTop = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49146
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49147
|
+
this._lastScroll = -1;
|
|
49148
|
+
}
|
|
49149
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49150
|
+
const ui = this._api.uiFacade;
|
|
49151
|
+
const settings = this._api.settings;
|
|
49152
|
+
const barBoundings = startBeat.barBounds.masterBarBounds;
|
|
49153
|
+
const systemTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49154
|
+
if (systemTop === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49155
|
+
return;
|
|
49156
|
+
}
|
|
49157
|
+
// jump to start of new system
|
|
49158
|
+
const scroll = ui.getScrollContainer();
|
|
49159
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49160
|
+
// instant scroll
|
|
49161
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49162
|
+
this._lastScroll = -1;
|
|
49163
|
+
return;
|
|
49164
|
+
}
|
|
49165
|
+
// dynamic scrolling
|
|
49166
|
+
this._lastScroll = systemTop;
|
|
49167
|
+
// scroll to bottom over time
|
|
49168
|
+
const systemBottom = systemTop + barBoundings.realBounds.h;
|
|
49169
|
+
// NOTE: this calculation is a bit more expensive, but we only do it once per system
|
|
49170
|
+
// so we should be good:
|
|
49171
|
+
// * the more bars we have, the longer the system will play, hence the duration can take a bit longer
|
|
49172
|
+
// * if we have less bars, we calculate more often, but the calculation will be faster because we sum up less bars.
|
|
49173
|
+
const systemDuration = this._calculateSystemDuration(barBoundings);
|
|
49174
|
+
ui.scrollToY(scroll, systemBottom, systemDuration);
|
|
49175
|
+
}
|
|
49176
|
+
_calculateSystemDuration(barBoundings) {
|
|
49177
|
+
const systemBars = barBoundings.staffSystemBounds.bars;
|
|
49178
|
+
const tickCache = this._api.tickCache;
|
|
49179
|
+
let duration = 0;
|
|
49180
|
+
const masterBars = this._api.score.masterBars;
|
|
49181
|
+
for (const bar of systemBars) {
|
|
49182
|
+
const mb = masterBars[bar.index];
|
|
49183
|
+
const mbInfo = tickCache.getMasterBar(mb);
|
|
49184
|
+
const tempoChanges = tickCache.getMasterBar(mb).tempoChanges;
|
|
49185
|
+
let tempo = tempoChanges[0].tempo;
|
|
49186
|
+
let tick = tempoChanges[0].tick;
|
|
49187
|
+
for (let i = 1; i < tempoChanges.length; i++) {
|
|
49188
|
+
const diff = tempoChanges[i].tick - tick;
|
|
49189
|
+
duration += MidiUtils.ticksToMillis(diff, tempo);
|
|
49190
|
+
tempo = tempoChanges[i].tempo;
|
|
49191
|
+
tick = tempoChanges[i].tick;
|
|
49192
|
+
}
|
|
49193
|
+
const toEnd = mbInfo.end - tick;
|
|
49194
|
+
duration += MidiUtils.ticksToMillis(toEnd, tempo);
|
|
49195
|
+
}
|
|
49196
|
+
return duration;
|
|
49197
|
+
}
|
|
49198
|
+
}
|
|
49199
|
+
/**
|
|
49200
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Continuous}.
|
|
49201
|
+
* Whenever the master bar changes, we scroll to the position horizontally.
|
|
49202
|
+
* @internal
|
|
49203
|
+
*/
|
|
49204
|
+
class HorizontalContinuousScrollHandler extends BasicScrollHandler {
|
|
49205
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49206
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49207
|
+
}
|
|
49208
|
+
doScroll(currentBeatBounds) {
|
|
49209
|
+
const ui = this.api.uiFacade;
|
|
49210
|
+
const settings = this.api.settings;
|
|
49211
|
+
const scroll = ui.getScrollContainer();
|
|
49212
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49213
|
+
const scrollLeftContinuous = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49214
|
+
ui.scrollToX(scroll, scrollLeftContinuous, settings.player.scrollSpeed);
|
|
49215
|
+
}
|
|
49216
|
+
}
|
|
49217
|
+
/**
|
|
49218
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.OffScreen}.
|
|
49219
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49220
|
+
* @internal
|
|
49221
|
+
*/
|
|
49222
|
+
class HorizontalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49223
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49224
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49225
|
+
}
|
|
49226
|
+
doScroll(currentBeatBounds) {
|
|
49227
|
+
const ui = this.api.uiFacade;
|
|
49228
|
+
const settings = this.api.settings;
|
|
49229
|
+
const scroll = ui.getScrollContainer();
|
|
49230
|
+
const elementRight = scroll.scrollLeft + ui.getOffset(null, scroll).w;
|
|
49231
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49232
|
+
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
49233
|
+
barBoundings.visualBounds.x < scroll.scrollLeft) {
|
|
49234
|
+
const scrollLeftOffScreen = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49235
|
+
ui.scrollToX(scroll, scrollLeftOffScreen, settings.player.scrollSpeed);
|
|
49236
|
+
}
|
|
49237
|
+
}
|
|
49238
|
+
}
|
|
49239
|
+
/**
|
|
49240
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Smooth}.
|
|
49241
|
+
* horiontal smooth scrolling aims to place the on-time position
|
|
49242
|
+
* at scrollOffsetX from a beat-to-beat perspective.
|
|
49243
|
+
* This achieves an steady cursor at the same position with rather the music sheet scrolling past it.
|
|
49244
|
+
* Due to some animation inconsistencies (e.g. CSS animation vs scrolling) there might be a slight
|
|
49245
|
+
* flickering of the cursor.
|
|
49246
|
+
*
|
|
49247
|
+
* To get a fully steady cursor the beat cursor can simply be visually hidden and a cursor can be placed at
|
|
49248
|
+
* `scrollOffsetX` by the integrator.
|
|
49249
|
+
* @internal
|
|
49250
|
+
*/
|
|
49251
|
+
class HorizontalSmoothScrollHandler {
|
|
49252
|
+
_api;
|
|
49253
|
+
_lastScroll = -1;
|
|
49254
|
+
_scrollContainerResizeUnregister;
|
|
49255
|
+
constructor(api) {
|
|
49256
|
+
this._api = api;
|
|
49257
|
+
// we need a resize listener for the overflow calculation
|
|
49258
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49259
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49260
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49261
|
+
const viewPortSize = scrollContainer.width;
|
|
49262
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49263
|
+
// that's why we need the whole width as additional overflow
|
|
49264
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49265
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, false);
|
|
49266
|
+
});
|
|
49267
|
+
}
|
|
49268
|
+
[Symbol.dispose]() {
|
|
49269
|
+
this._scrollContainerResizeUnregister();
|
|
49270
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, false);
|
|
49271
|
+
}
|
|
49272
|
+
forceScrollTo(currentBeatBounds) {
|
|
49273
|
+
const ui = this._api.uiFacade;
|
|
49274
|
+
const settings = this._api.settings;
|
|
49275
|
+
const scroll = ui.getScrollContainer();
|
|
49276
|
+
const barStartX = currentBeatBounds.onNotesX + settings.player.scrollOffsetY;
|
|
49277
|
+
ui.scrollToY(scroll, barStartX, 0);
|
|
49278
|
+
this._lastScroll = -1;
|
|
49279
|
+
}
|
|
49280
|
+
onBeatCursorUpdating(_startBeat, _endBeat, _cursorMode, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49281
|
+
const ui = this._api.uiFacade;
|
|
49282
|
+
if (actualBeatCursorEndX === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49283
|
+
return;
|
|
49284
|
+
}
|
|
49285
|
+
// jump to start of new system
|
|
49286
|
+
const settings = this._api.settings;
|
|
49287
|
+
const scroll = ui.getScrollContainer();
|
|
49288
|
+
ui.scrollToX(scroll, actualBeatCursorStartX + settings.player.scrollOffsetX, 0);
|
|
49289
|
+
// instant scroll
|
|
49290
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49291
|
+
this._lastScroll = -1;
|
|
49292
|
+
return;
|
|
49293
|
+
}
|
|
49294
|
+
this._lastScroll = actualBeatCursorEndX;
|
|
49295
|
+
const scrollX = actualBeatCursorEndX + settings.player.scrollOffsetX;
|
|
49296
|
+
ui.scrollToX(scroll, scrollX, actualBeatCursorTransitionDuration);
|
|
49297
|
+
}
|
|
49032
49298
|
}
|
|
49033
49299
|
|
|
49034
49300
|
/**
|
|
@@ -49671,6 +49937,7 @@ class AlphaTabApiBase {
|
|
|
49671
49937
|
_actualPlayerMode = PlayerMode.Disabled;
|
|
49672
49938
|
_player;
|
|
49673
49939
|
_renderer;
|
|
49940
|
+
_defaultScrollHandler;
|
|
49674
49941
|
/**
|
|
49675
49942
|
* An indicator by how many midi-ticks the song contents are shifted.
|
|
49676
49943
|
* Grace beats at start might require a shift for the first beat to start at 0.
|
|
@@ -50440,6 +50707,42 @@ class AlphaTabApiBase {
|
|
|
50440
50707
|
}
|
|
50441
50708
|
}
|
|
50442
50709
|
_tickCache = null;
|
|
50710
|
+
/**
|
|
50711
|
+
* A custom scroll handler which will be used to handle scrolling operations during playback.
|
|
50712
|
+
*
|
|
50713
|
+
* @category Properties - Player
|
|
50714
|
+
* @since 1.8.0
|
|
50715
|
+
* @example
|
|
50716
|
+
* JavaScript
|
|
50717
|
+
* ```js
|
|
50718
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
50719
|
+
* api.customScrollHandler = {
|
|
50720
|
+
* forceScrollTo(currentBeatBounds) {
|
|
50721
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50722
|
+
* api.uiFacade.scrollToY(scroll, currentBeatBounds.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50723
|
+
* },
|
|
50724
|
+
* onBeatCursorUpdating(startBeat, endBeat, cursorMode, relativePosition, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
50725
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50726
|
+
* api.uiFacade.scrollToY(scroll, startBeat.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50727
|
+
* }
|
|
50728
|
+
* }
|
|
50729
|
+
* ```
|
|
50730
|
+
*
|
|
50731
|
+
* @example
|
|
50732
|
+
* C#
|
|
50733
|
+
* ```cs
|
|
50734
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
50735
|
+
* api.CustomScrollHandler = new CustomScrollHandler();
|
|
50736
|
+
* ```
|
|
50737
|
+
*
|
|
50738
|
+
* @example
|
|
50739
|
+
* Android
|
|
50740
|
+
* ```kotlin
|
|
50741
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
50742
|
+
* api.customScrollHandler = CustomScrollHandler();
|
|
50743
|
+
* ```
|
|
50744
|
+
*/
|
|
50745
|
+
customScrollHandler;
|
|
50443
50746
|
/**
|
|
50444
50747
|
* The tick cache allowing lookup of midi ticks to beats.
|
|
50445
50748
|
* @remarks
|
|
@@ -51418,7 +51721,6 @@ class AlphaTabApiBase {
|
|
|
51418
51721
|
_isInitialBeatCursorUpdate = true;
|
|
51419
51722
|
_previousStateForCursor = PlayerState.Paused;
|
|
51420
51723
|
_previousCursorCache = null;
|
|
51421
|
-
_lastScroll = 0;
|
|
51422
51724
|
_destroyCursors() {
|
|
51423
51725
|
if (!this._cursorWrapper) {
|
|
51424
51726
|
return;
|
|
@@ -51429,28 +51731,79 @@ class AlphaTabApiBase {
|
|
|
51429
51731
|
this._beatCursor = null;
|
|
51430
51732
|
this._selectionWrapper = null;
|
|
51431
51733
|
}
|
|
51734
|
+
_createCursors() {
|
|
51735
|
+
if (this._cursorWrapper) {
|
|
51736
|
+
return;
|
|
51737
|
+
}
|
|
51738
|
+
const cursors = this.uiFacade.createCursors();
|
|
51739
|
+
if (cursors) {
|
|
51740
|
+
// store options and created elements for fast access
|
|
51741
|
+
this._cursorWrapper = cursors.cursorWrapper;
|
|
51742
|
+
this._barCursor = cursors.barCursor;
|
|
51743
|
+
this._beatCursor = cursors.beatCursor;
|
|
51744
|
+
this._selectionWrapper = cursors.selectionWrapper;
|
|
51745
|
+
this._isInitialBeatCursorUpdate = true;
|
|
51746
|
+
}
|
|
51747
|
+
if (this._currentBeat !== null) {
|
|
51748
|
+
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51749
|
+
}
|
|
51750
|
+
}
|
|
51432
51751
|
_updateCursors() {
|
|
51752
|
+
this._updateScrollHandler();
|
|
51433
51753
|
const enable = this._hasCursor;
|
|
51434
|
-
if (enable
|
|
51435
|
-
|
|
51436
|
-
// Create cursors
|
|
51437
|
-
const cursors = this.uiFacade.createCursors();
|
|
51438
|
-
if (cursors) {
|
|
51439
|
-
// store options and created elements for fast access
|
|
51440
|
-
this._cursorWrapper = cursors.cursorWrapper;
|
|
51441
|
-
this._barCursor = cursors.barCursor;
|
|
51442
|
-
this._beatCursor = cursors.beatCursor;
|
|
51443
|
-
this._selectionWrapper = cursors.selectionWrapper;
|
|
51444
|
-
this._isInitialBeatCursorUpdate = true;
|
|
51445
|
-
}
|
|
51446
|
-
if (this._currentBeat !== null) {
|
|
51447
|
-
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51448
|
-
}
|
|
51754
|
+
if (enable) {
|
|
51755
|
+
this._createCursors();
|
|
51449
51756
|
}
|
|
51450
51757
|
else if (!enable && this._cursorWrapper) {
|
|
51451
51758
|
this._destroyCursors();
|
|
51452
51759
|
}
|
|
51453
51760
|
}
|
|
51761
|
+
_scrollHandlerMode = ScrollMode.Off;
|
|
51762
|
+
_scrollHandlerVertical = true;
|
|
51763
|
+
_updateScrollHandler() {
|
|
51764
|
+
const currentHandler = this._defaultScrollHandler;
|
|
51765
|
+
const scrollMode = this.settings.player.scrollMode;
|
|
51766
|
+
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51767
|
+
// no change
|
|
51768
|
+
if (this._scrollHandlerMode === scrollMode && this._scrollHandlerVertical === isVertical) {
|
|
51769
|
+
return;
|
|
51770
|
+
}
|
|
51771
|
+
// destroy current handler in favor of new one
|
|
51772
|
+
if (currentHandler) {
|
|
51773
|
+
currentHandler[Symbol.dispose]();
|
|
51774
|
+
const scroll = this.uiFacade.getScrollContainer();
|
|
51775
|
+
this.uiFacade.stopScrolling(scroll);
|
|
51776
|
+
}
|
|
51777
|
+
switch (scrollMode) {
|
|
51778
|
+
case ScrollMode.Off:
|
|
51779
|
+
this._defaultScrollHandler = undefined;
|
|
51780
|
+
break;
|
|
51781
|
+
case ScrollMode.Continuous:
|
|
51782
|
+
if (isVertical) {
|
|
51783
|
+
this._defaultScrollHandler = new VerticalContinuousScrollHandler(this);
|
|
51784
|
+
}
|
|
51785
|
+
else {
|
|
51786
|
+
this._defaultScrollHandler = new HorizontalContinuousScrollHandler(this);
|
|
51787
|
+
}
|
|
51788
|
+
break;
|
|
51789
|
+
case ScrollMode.OffScreen:
|
|
51790
|
+
if (isVertical) {
|
|
51791
|
+
this._defaultScrollHandler = new VerticalOffScreenScrollHandler(this);
|
|
51792
|
+
}
|
|
51793
|
+
else {
|
|
51794
|
+
this._defaultScrollHandler = new HorizontalOffScreenScrollHandler(this);
|
|
51795
|
+
}
|
|
51796
|
+
break;
|
|
51797
|
+
case ScrollMode.Smooth:
|
|
51798
|
+
if (isVertical) {
|
|
51799
|
+
this._defaultScrollHandler = new VerticalSmoothScrollHandler(this);
|
|
51800
|
+
}
|
|
51801
|
+
else {
|
|
51802
|
+
this._defaultScrollHandler = new HorizontalSmoothScrollHandler(this);
|
|
51803
|
+
}
|
|
51804
|
+
break;
|
|
51805
|
+
}
|
|
51806
|
+
}
|
|
51454
51807
|
/**
|
|
51455
51808
|
* updates the cursors to highlight the beat at the specified tick position
|
|
51456
51809
|
* @param tick
|
|
@@ -51513,57 +51866,9 @@ class AlphaTabApiBase {
|
|
|
51513
51866
|
scrollToCursor() {
|
|
51514
51867
|
const beatBounds = this._currentBeatBounds;
|
|
51515
51868
|
if (beatBounds) {
|
|
51516
|
-
this.
|
|
51517
|
-
|
|
51518
|
-
|
|
51519
|
-
_internalScrollToCursor(barBoundings) {
|
|
51520
|
-
const scrollElement = this.uiFacade.getScrollContainer();
|
|
51521
|
-
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51522
|
-
const mode = this.settings.player.scrollMode;
|
|
51523
|
-
if (isVertical) {
|
|
51524
|
-
// when scrolling on the y-axis, we preliminary check if the new beat/bar have
|
|
51525
|
-
// moved on the y-axis
|
|
51526
|
-
const y = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51527
|
-
if (y !== this._lastScroll) {
|
|
51528
|
-
this._lastScroll = y;
|
|
51529
|
-
switch (mode) {
|
|
51530
|
-
case ScrollMode.Continuous:
|
|
51531
|
-
const elementOffset = this.uiFacade.getOffset(scrollElement, this.container);
|
|
51532
|
-
this.uiFacade.scrollToY(scrollElement, elementOffset.y + y, this.settings.player.scrollSpeed);
|
|
51533
|
-
break;
|
|
51534
|
-
case ScrollMode.OffScreen:
|
|
51535
|
-
const elementBottom = scrollElement.scrollTop + this.uiFacade.getOffset(null, scrollElement).h;
|
|
51536
|
-
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
51537
|
-
barBoundings.visualBounds.y < scrollElement.scrollTop) {
|
|
51538
|
-
const scrollTop = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51539
|
-
this.uiFacade.scrollToY(scrollElement, scrollTop, this.settings.player.scrollSpeed);
|
|
51540
|
-
}
|
|
51541
|
-
break;
|
|
51542
|
-
}
|
|
51543
|
-
}
|
|
51544
|
-
}
|
|
51545
|
-
else {
|
|
51546
|
-
// when scrolling on the x-axis, we preliminary check if the new bar has
|
|
51547
|
-
// moved on the x-axis
|
|
51548
|
-
const x = barBoundings.visualBounds.x;
|
|
51549
|
-
if (x !== this._lastScroll) {
|
|
51550
|
-
this._lastScroll = x;
|
|
51551
|
-
switch (mode) {
|
|
51552
|
-
case ScrollMode.Continuous:
|
|
51553
|
-
const scrollLeftContinuous = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51554
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51555
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftContinuous, this.settings.player.scrollSpeed);
|
|
51556
|
-
break;
|
|
51557
|
-
case ScrollMode.OffScreen:
|
|
51558
|
-
const elementRight = scrollElement.scrollLeft + this.uiFacade.getOffset(null, scrollElement).w;
|
|
51559
|
-
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
51560
|
-
barBoundings.visualBounds.x < scrollElement.scrollLeft) {
|
|
51561
|
-
const scrollLeftOffScreen = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51562
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51563
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftOffScreen, this.settings.player.scrollSpeed);
|
|
51564
|
-
}
|
|
51565
|
-
break;
|
|
51566
|
-
}
|
|
51869
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51870
|
+
if (handler) {
|
|
51871
|
+
handler.forceScrollTo(beatBounds);
|
|
51567
51872
|
}
|
|
51568
51873
|
}
|
|
51569
51874
|
}
|
|
@@ -51579,11 +51884,12 @@ class AlphaTabApiBase {
|
|
|
51579
51884
|
}
|
|
51580
51885
|
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
51581
51886
|
let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
|
|
51887
|
+
let nextBeatBoundings = null;
|
|
51582
51888
|
// get position of next beat on same system
|
|
51583
51889
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
51584
51890
|
// if we are moving within the same bar or to the next bar
|
|
51585
51891
|
// transition to the next beat, otherwise transition to the end of the bar.
|
|
51586
|
-
|
|
51892
|
+
nextBeatBoundings = cache.findBeat(nextBeat);
|
|
51587
51893
|
if (nextBeatBoundings &&
|
|
51588
51894
|
nextBeatBoundings.barBounds.masterBarBounds.staffSystemBounds === barBoundings.staffSystemBounds) {
|
|
51589
51895
|
nextBeatX = nextBeatBoundings.onNotesX;
|
|
@@ -51609,25 +51915,29 @@ class AlphaTabApiBase {
|
|
|
51609
51915
|
beatCursor.transitionToX(0, startBeatX);
|
|
51610
51916
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51611
51917
|
}
|
|
51918
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
51919
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51920
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51921
|
+
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51922
|
+
nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51923
|
+
duration = (duration / cursorSpeed) * factor;
|
|
51612
51924
|
// we need to put the transition to an own animation frame
|
|
51613
51925
|
// otherwise the stop animation above is not applied.
|
|
51614
51926
|
this.uiFacade.beginInvoke(() => {
|
|
51615
|
-
|
|
51616
|
-
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51617
|
-
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51618
|
-
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51619
|
-
const doubleEndBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51620
|
-
beatCursor.transitionToX((duration / cursorSpeed) * factor, doubleEndBeatX);
|
|
51927
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51621
51928
|
});
|
|
51622
51929
|
}
|
|
51623
51930
|
else {
|
|
51624
|
-
|
|
51931
|
+
duration = 0;
|
|
51932
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51625
51933
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51626
51934
|
}
|
|
51627
51935
|
}
|
|
51628
51936
|
else {
|
|
51629
51937
|
// ticking cursor
|
|
51630
|
-
|
|
51938
|
+
duration = 0;
|
|
51939
|
+
nextBeatX = startBeatX;
|
|
51940
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51631
51941
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51632
51942
|
}
|
|
51633
51943
|
this._isInitialBeatCursorUpdate = false;
|
|
@@ -51650,7 +51960,10 @@ class AlphaTabApiBase {
|
|
|
51650
51960
|
shouldNotifyBeatChange = true;
|
|
51651
51961
|
}
|
|
51652
51962
|
if (shouldScroll && !this._isBeatMouseDown && this.settings.player.scrollMode !== ScrollMode.Off) {
|
|
51653
|
-
this.
|
|
51963
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51964
|
+
if (handler) {
|
|
51965
|
+
handler.onBeatCursorUpdating(beatBoundings, nextBeatBoundings === null ? undefined : nextBeatBoundings, cursorMode, startBeatX, nextBeatX, duration);
|
|
51966
|
+
}
|
|
51654
51967
|
}
|
|
51655
51968
|
// trigger an event for others to indicate which beat/bar is played
|
|
51656
51969
|
if (shouldNotifyBeatChange) {
|
|
@@ -53024,6 +53337,7 @@ class AlphaTabApiBase {
|
|
|
53024
53337
|
const tickCache = this._tickCache;
|
|
53025
53338
|
if (currentBeat && tickCache) {
|
|
53026
53339
|
this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
53340
|
+
this.scrollToCursor();
|
|
53027
53341
|
}
|
|
53028
53342
|
}
|
|
53029
53343
|
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
|
|
@@ -54984,6 +55298,22 @@ class BrowserUiFacade {
|
|
|
54984
55298
|
canvasElement.style.position = 'relative';
|
|
54985
55299
|
return new HtmlElementContainer(canvasElement);
|
|
54986
55300
|
}
|
|
55301
|
+
setCanvasOverflow(canvasElement, overflow, isVertical) {
|
|
55302
|
+
const html = canvasElement.element;
|
|
55303
|
+
if (overflow === 0) {
|
|
55304
|
+
html.style.boxSizing = '';
|
|
55305
|
+
html.style.paddingRight = '';
|
|
55306
|
+
html.style.paddingBottom = '';
|
|
55307
|
+
}
|
|
55308
|
+
else if (isVertical) {
|
|
55309
|
+
html.style.boxSizing = 'content-box';
|
|
55310
|
+
html.style.paddingBottom = `${overflow}px`;
|
|
55311
|
+
}
|
|
55312
|
+
else {
|
|
55313
|
+
html.style.boxSizing = 'content-box';
|
|
55314
|
+
html.style.paddingRight = `${overflow}px`;
|
|
55315
|
+
}
|
|
55316
|
+
}
|
|
54987
55317
|
triggerEvent(container, name, details = null, originalEvent) {
|
|
54988
55318
|
const element = container.element;
|
|
54989
55319
|
name = `alphaTab.${name}`;
|
|
@@ -55541,54 +55871,79 @@ class BrowserUiFacade {
|
|
|
55541
55871
|
scrollToX(element, scrollTargetY, speed) {
|
|
55542
55872
|
this._internalScrollToX(element.element, scrollTargetY, speed);
|
|
55543
55873
|
}
|
|
55874
|
+
stopScrolling(scrollElement) {
|
|
55875
|
+
// stop any current animation
|
|
55876
|
+
const currentAnimation = this._scrollAnimationLookup.get(scrollElement.element);
|
|
55877
|
+
if (currentAnimation !== undefined) {
|
|
55878
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55879
|
+
}
|
|
55880
|
+
}
|
|
55881
|
+
get _nativeBrowserSmoothScroll() {
|
|
55882
|
+
const settings = this._api.settings.player;
|
|
55883
|
+
return settings.nativeBrowserSmoothScroll && settings.scrollMode !== ScrollMode.Smooth;
|
|
55884
|
+
}
|
|
55885
|
+
_scrollAnimationId = 0;
|
|
55886
|
+
_activeScrollAnimations = new Set();
|
|
55887
|
+
_scrollAnimationLookup = new Map();
|
|
55544
55888
|
_internalScrollToY(element, scrollTargetY, speed) {
|
|
55545
|
-
if (this.
|
|
55889
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55546
55890
|
element.scrollTo({
|
|
55547
55891
|
top: scrollTargetY,
|
|
55548
55892
|
behavior: 'smooth'
|
|
55549
55893
|
});
|
|
55550
55894
|
}
|
|
55551
55895
|
else {
|
|
55552
|
-
|
|
55553
|
-
|
|
55554
|
-
|
|
55555
|
-
|
|
55556
|
-
|
|
55557
|
-
|
|
55558
|
-
|
|
55559
|
-
|
|
55560
|
-
|
|
55561
|
-
|
|
55562
|
-
|
|
55563
|
-
|
|
55564
|
-
|
|
55565
|
-
|
|
55566
|
-
window.requestAnimationFrame(step);
|
|
55896
|
+
this._internalScrollTo(element, element.scrollTop, scrollTargetY, speed, scroll => {
|
|
55897
|
+
element.scrollTop = scroll;
|
|
55898
|
+
});
|
|
55899
|
+
}
|
|
55900
|
+
}
|
|
55901
|
+
_internalScrollTo(element, startScroll, endScroll, scrollDuration, setValue) {
|
|
55902
|
+
// stop any current animation
|
|
55903
|
+
const currentAnimation = this._scrollAnimationLookup.get(element);
|
|
55904
|
+
if (currentAnimation !== undefined) {
|
|
55905
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55906
|
+
}
|
|
55907
|
+
if (scrollDuration === 0) {
|
|
55908
|
+
setValue(endScroll);
|
|
55909
|
+
return;
|
|
55567
55910
|
}
|
|
55911
|
+
// start new animation
|
|
55912
|
+
const animationId = this._scrollAnimationId++;
|
|
55913
|
+
this._scrollAnimationLookup.set(element, animationId);
|
|
55914
|
+
this._activeScrollAnimations.add(animationId);
|
|
55915
|
+
const diff = endScroll - startScroll;
|
|
55916
|
+
let start = 0;
|
|
55917
|
+
const step = (x) => {
|
|
55918
|
+
if (!this._activeScrollAnimations.has(animationId)) {
|
|
55919
|
+
return;
|
|
55920
|
+
}
|
|
55921
|
+
if (start === 0) {
|
|
55922
|
+
start = x;
|
|
55923
|
+
}
|
|
55924
|
+
const time = x - start;
|
|
55925
|
+
const percent = Math.min(time / scrollDuration, 1);
|
|
55926
|
+
setValue((startScroll + diff * percent) | 0);
|
|
55927
|
+
if (time < scrollDuration) {
|
|
55928
|
+
window.requestAnimationFrame(step);
|
|
55929
|
+
}
|
|
55930
|
+
else {
|
|
55931
|
+
this._activeScrollAnimations.delete(animationId);
|
|
55932
|
+
}
|
|
55933
|
+
};
|
|
55934
|
+
window.requestAnimationFrame(step);
|
|
55568
55935
|
}
|
|
55569
55936
|
_internalScrollToX(element, scrollTargetX, speed) {
|
|
55570
|
-
if (this.
|
|
55937
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55571
55938
|
element.scrollTo({
|
|
55572
55939
|
left: scrollTargetX,
|
|
55573
55940
|
behavior: 'smooth'
|
|
55574
55941
|
});
|
|
55575
55942
|
}
|
|
55576
55943
|
else {
|
|
55577
|
-
|
|
55578
|
-
|
|
55579
|
-
|
|
55580
|
-
const step = (t) => {
|
|
55581
|
-
if (start === 0) {
|
|
55582
|
-
start = t;
|
|
55583
|
-
}
|
|
55584
|
-
const time = t - start;
|
|
55585
|
-
const percent = Math.min(time / speed, 1);
|
|
55586
|
-
element.scrollLeft = (startX + diff * percent) | 0;
|
|
55587
|
-
if (time < speed) {
|
|
55588
|
-
window.requestAnimationFrame(step);
|
|
55589
|
-
}
|
|
55590
|
-
};
|
|
55591
|
-
window.requestAnimationFrame(step);
|
|
55944
|
+
this._internalScrollTo(element, element.scrollLeft, scrollTargetX, speed, scroll => {
|
|
55945
|
+
element.scrollLeft = scroll;
|
|
55946
|
+
});
|
|
55592
55947
|
}
|
|
55593
55948
|
}
|
|
55594
55949
|
createBackingTrackPlayer() {
|
|
@@ -61701,8 +62056,8 @@ class StaffSystem {
|
|
|
61701
62056
|
}
|
|
61702
62057
|
}
|
|
61703
62058
|
}
|
|
62059
|
+
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61704
62060
|
if (hasAnyTrackName) {
|
|
61705
|
-
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61706
62061
|
this.accoladeWidth += settings.display.systemLabelPaddingRight;
|
|
61707
62062
|
}
|
|
61708
62063
|
}
|