@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.js
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
|
*
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
* @internal
|
|
210
210
|
*/
|
|
211
211
|
class VersionInfo {
|
|
212
|
-
static version = '1.8.0-alpha.
|
|
213
|
-
static date = '2025-12-
|
|
214
|
-
static commit = '
|
|
212
|
+
static version = '1.8.0-alpha.1653';
|
|
213
|
+
static date = '2025-12-23T02:21:29.054Z';
|
|
214
|
+
static commit = 'b85546e1908f06f3bd049e35e881c4856fb92846';
|
|
215
215
|
static print(print) {
|
|
216
216
|
print(`alphaTab ${VersionInfo.version}`);
|
|
217
217
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -13095,7 +13095,7 @@
|
|
|
13095
13095
|
*/
|
|
13096
13096
|
class MasterBarBounds {
|
|
13097
13097
|
/**
|
|
13098
|
-
*
|
|
13098
|
+
* The MasterBar index within the data model represented by these bounds.
|
|
13099
13099
|
*/
|
|
13100
13100
|
index = 0;
|
|
13101
13101
|
/**
|
|
@@ -13303,6 +13303,7 @@
|
|
|
13303
13303
|
mb.visualBounds = this._boundsToJson(masterBar.visualBounds);
|
|
13304
13304
|
mb.realBounds = this._boundsToJson(masterBar.realBounds);
|
|
13305
13305
|
mb.index = masterBar.index;
|
|
13306
|
+
mb.isFirstOfLine = masterBar.isFirstOfLine;
|
|
13306
13307
|
mb.bars = [];
|
|
13307
13308
|
for (const bar of masterBar.bars) {
|
|
13308
13309
|
const b = {};
|
|
@@ -13359,7 +13360,7 @@
|
|
|
13359
13360
|
mb.lineAlignedBounds = BoundsLookup._boundsFromJson(masterBar.lineAlignedBounds);
|
|
13360
13361
|
mb.visualBounds = BoundsLookup._boundsFromJson(masterBar.visualBounds);
|
|
13361
13362
|
mb.realBounds = BoundsLookup._boundsFromJson(masterBar.realBounds);
|
|
13362
|
-
|
|
13363
|
+
lookup.addMasterBar(mb);
|
|
13363
13364
|
for (const bar of masterBar.bars) {
|
|
13364
13365
|
const b = new BarBounds();
|
|
13365
13366
|
b.visualBounds = BoundsLookup._boundsFromJson(bar.visualBounds);
|
|
@@ -43663,6 +43664,12 @@
|
|
|
43663
43664
|
* Scrolling happens as soon the cursors exceed the displayed range.
|
|
43664
43665
|
*/
|
|
43665
43666
|
ScrollMode[ScrollMode["OffScreen"] = 2] = "OffScreen";
|
|
43667
|
+
/**
|
|
43668
|
+
* Scrolling happens constantly in a smooth fashion.
|
|
43669
|
+
* This will disable the use of any native scroll optimizations but
|
|
43670
|
+
* manually scroll the scroll container in the required speed.
|
|
43671
|
+
*/
|
|
43672
|
+
ScrollMode[ScrollMode["Smooth"] = 3] = "Smooth";
|
|
43666
43673
|
})(exports.ScrollMode || (exports.ScrollMode = {}));
|
|
43667
43674
|
/**
|
|
43668
43675
|
* This object defines the details on how to generate the vibrato effects.
|
|
@@ -48593,6 +48600,25 @@
|
|
|
48593
48600
|
}
|
|
48594
48601
|
}
|
|
48595
48602
|
|
|
48603
|
+
/**
|
|
48604
|
+
* Represents the information related to a resize event.
|
|
48605
|
+
* @public
|
|
48606
|
+
*/
|
|
48607
|
+
class ResizeEventArgs {
|
|
48608
|
+
/**
|
|
48609
|
+
* Gets the size before the resizing happened.
|
|
48610
|
+
*/
|
|
48611
|
+
oldWidth = 0;
|
|
48612
|
+
/**
|
|
48613
|
+
* Gets the size after the resize was complete.
|
|
48614
|
+
*/
|
|
48615
|
+
newWidth = 0;
|
|
48616
|
+
/**
|
|
48617
|
+
* Gets the settings currently used for rendering.
|
|
48618
|
+
*/
|
|
48619
|
+
settings = null;
|
|
48620
|
+
}
|
|
48621
|
+
|
|
48596
48622
|
/**
|
|
48597
48623
|
* Lists the different position modes for {@link BarRendererBase.getBeatX}
|
|
48598
48624
|
* @internal
|
|
@@ -49019,22 +49045,262 @@
|
|
|
49019
49045
|
}
|
|
49020
49046
|
|
|
49021
49047
|
/**
|
|
49022
|
-
*
|
|
49023
|
-
* @
|
|
49048
|
+
* Some basic scroll handler checking for changed offsets and scroll if changed.
|
|
49049
|
+
* @internal
|
|
49024
49050
|
*/
|
|
49025
|
-
class
|
|
49026
|
-
|
|
49027
|
-
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49032
|
-
|
|
49033
|
-
|
|
49034
|
-
|
|
49035
|
-
|
|
49036
|
-
|
|
49037
|
-
|
|
49051
|
+
class BasicScrollHandler {
|
|
49052
|
+
api;
|
|
49053
|
+
lastScroll = -1;
|
|
49054
|
+
constructor(api) {
|
|
49055
|
+
this.api = api;
|
|
49056
|
+
}
|
|
49057
|
+
[Symbol.dispose]() {
|
|
49058
|
+
}
|
|
49059
|
+
forceScrollTo(currentBeatBounds) {
|
|
49060
|
+
this._scrollToBeat(currentBeatBounds, true);
|
|
49061
|
+
this.lastScroll = -1; // force new scroll on next update
|
|
49062
|
+
}
|
|
49063
|
+
_scrollToBeat(currentBeatBounds, force) {
|
|
49064
|
+
const newLastScroll = this.calculateLastScroll(currentBeatBounds);
|
|
49065
|
+
// no change, and no instant/force scroll
|
|
49066
|
+
if (newLastScroll === this.lastScroll && !force) {
|
|
49067
|
+
return;
|
|
49068
|
+
}
|
|
49069
|
+
this.lastScroll = newLastScroll;
|
|
49070
|
+
this.doScroll(currentBeatBounds);
|
|
49071
|
+
}
|
|
49072
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, _actualBeatCursorTransitionDuration) {
|
|
49073
|
+
this._scrollToBeat(startBeat, false);
|
|
49074
|
+
}
|
|
49075
|
+
}
|
|
49076
|
+
/**
|
|
49077
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Continuous}.
|
|
49078
|
+
* Whenever the system changes, we scroll to the new system position vertically.
|
|
49079
|
+
* @internal
|
|
49080
|
+
*/
|
|
49081
|
+
class VerticalContinuousScrollHandler extends BasicScrollHandler {
|
|
49082
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49083
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49084
|
+
}
|
|
49085
|
+
doScroll(currentBeatBounds) {
|
|
49086
|
+
const ui = this.api.uiFacade;
|
|
49087
|
+
const settings = this.api.settings;
|
|
49088
|
+
const scroll = ui.getScrollContainer();
|
|
49089
|
+
const elementOffset = ui.getOffset(scroll, this.api.container);
|
|
49090
|
+
const y = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49091
|
+
ui.scrollToY(scroll, elementOffset.y + y, this.api.settings.player.scrollSpeed);
|
|
49092
|
+
}
|
|
49093
|
+
}
|
|
49094
|
+
/**
|
|
49095
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.OffScreen}.
|
|
49096
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49097
|
+
* @internal
|
|
49098
|
+
*/
|
|
49099
|
+
class VerticalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49100
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49101
|
+
// check for system change
|
|
49102
|
+
return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
|
|
49103
|
+
}
|
|
49104
|
+
doScroll(currentBeatBounds) {
|
|
49105
|
+
const ui = this.api.uiFacade;
|
|
49106
|
+
const settings = this.api.settings;
|
|
49107
|
+
const scroll = ui.getScrollContainer();
|
|
49108
|
+
const elementBottom = scroll.scrollTop + ui.getOffset(null, scroll).h;
|
|
49109
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49110
|
+
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
49111
|
+
barBoundings.visualBounds.y < scroll.scrollTop) {
|
|
49112
|
+
const scrollTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49113
|
+
ui.scrollToY(scroll, scrollTop, settings.player.scrollSpeed);
|
|
49114
|
+
}
|
|
49115
|
+
}
|
|
49116
|
+
}
|
|
49117
|
+
/**
|
|
49118
|
+
* This is the default scroll handler for vertical layouts using {@link ScrollMode.Smooth}.
|
|
49119
|
+
* vertical smooth scrolling aims to place the on-time position
|
|
49120
|
+
* at scrollOffsetY **at the time when a system starts**
|
|
49121
|
+
* this means when a system starts, it is at scrollOffsetY,
|
|
49122
|
+
* then gradually scrolls down the system height reaching the bottom
|
|
49123
|
+
* when the system completes.
|
|
49124
|
+
* @internal
|
|
49125
|
+
*/
|
|
49126
|
+
class VerticalSmoothScrollHandler {
|
|
49127
|
+
_api;
|
|
49128
|
+
_lastScroll = -1;
|
|
49129
|
+
_scrollContainerResizeUnregister;
|
|
49130
|
+
constructor(api) {
|
|
49131
|
+
this._api = api;
|
|
49132
|
+
// we need a resize listener for the overflow calculation
|
|
49133
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49134
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49135
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49136
|
+
const viewPortSize = scrollContainer.width;
|
|
49137
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49138
|
+
// that's why we need the whole width as additional overflow
|
|
49139
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49140
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, true);
|
|
49141
|
+
});
|
|
49142
|
+
}
|
|
49143
|
+
[Symbol.dispose]() {
|
|
49144
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, true);
|
|
49145
|
+
this._scrollContainerResizeUnregister();
|
|
49146
|
+
}
|
|
49147
|
+
forceScrollTo(currentBeatBounds) {
|
|
49148
|
+
const ui = this._api.uiFacade;
|
|
49149
|
+
const settings = this._api.settings;
|
|
49150
|
+
const scroll = ui.getScrollContainer();
|
|
49151
|
+
const systemTop = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
|
|
49152
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49153
|
+
this._lastScroll = -1;
|
|
49154
|
+
}
|
|
49155
|
+
onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49156
|
+
const ui = this._api.uiFacade;
|
|
49157
|
+
const settings = this._api.settings;
|
|
49158
|
+
const barBoundings = startBeat.barBounds.masterBarBounds;
|
|
49159
|
+
const systemTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
|
|
49160
|
+
if (systemTop === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49161
|
+
return;
|
|
49162
|
+
}
|
|
49163
|
+
// jump to start of new system
|
|
49164
|
+
const scroll = ui.getScrollContainer();
|
|
49165
|
+
ui.scrollToY(scroll, systemTop, 0);
|
|
49166
|
+
// instant scroll
|
|
49167
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49168
|
+
this._lastScroll = -1;
|
|
49169
|
+
return;
|
|
49170
|
+
}
|
|
49171
|
+
// dynamic scrolling
|
|
49172
|
+
this._lastScroll = systemTop;
|
|
49173
|
+
// scroll to bottom over time
|
|
49174
|
+
const systemBottom = systemTop + barBoundings.realBounds.h;
|
|
49175
|
+
// NOTE: this calculation is a bit more expensive, but we only do it once per system
|
|
49176
|
+
// so we should be good:
|
|
49177
|
+
// * the more bars we have, the longer the system will play, hence the duration can take a bit longer
|
|
49178
|
+
// * if we have less bars, we calculate more often, but the calculation will be faster because we sum up less bars.
|
|
49179
|
+
const systemDuration = this._calculateSystemDuration(barBoundings);
|
|
49180
|
+
ui.scrollToY(scroll, systemBottom, systemDuration);
|
|
49181
|
+
}
|
|
49182
|
+
_calculateSystemDuration(barBoundings) {
|
|
49183
|
+
const systemBars = barBoundings.staffSystemBounds.bars;
|
|
49184
|
+
const tickCache = this._api.tickCache;
|
|
49185
|
+
let duration = 0;
|
|
49186
|
+
const masterBars = this._api.score.masterBars;
|
|
49187
|
+
for (const bar of systemBars) {
|
|
49188
|
+
const mb = masterBars[bar.index];
|
|
49189
|
+
const mbInfo = tickCache.getMasterBar(mb);
|
|
49190
|
+
const tempoChanges = tickCache.getMasterBar(mb).tempoChanges;
|
|
49191
|
+
let tempo = tempoChanges[0].tempo;
|
|
49192
|
+
let tick = tempoChanges[0].tick;
|
|
49193
|
+
for (let i = 1; i < tempoChanges.length; i++) {
|
|
49194
|
+
const diff = tempoChanges[i].tick - tick;
|
|
49195
|
+
duration += MidiUtils.ticksToMillis(diff, tempo);
|
|
49196
|
+
tempo = tempoChanges[i].tempo;
|
|
49197
|
+
tick = tempoChanges[i].tick;
|
|
49198
|
+
}
|
|
49199
|
+
const toEnd = mbInfo.end - tick;
|
|
49200
|
+
duration += MidiUtils.ticksToMillis(toEnd, tempo);
|
|
49201
|
+
}
|
|
49202
|
+
return duration;
|
|
49203
|
+
}
|
|
49204
|
+
}
|
|
49205
|
+
/**
|
|
49206
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Continuous}.
|
|
49207
|
+
* Whenever the master bar changes, we scroll to the position horizontally.
|
|
49208
|
+
* @internal
|
|
49209
|
+
*/
|
|
49210
|
+
class HorizontalContinuousScrollHandler extends BasicScrollHandler {
|
|
49211
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49212
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49213
|
+
}
|
|
49214
|
+
doScroll(currentBeatBounds) {
|
|
49215
|
+
const ui = this.api.uiFacade;
|
|
49216
|
+
const settings = this.api.settings;
|
|
49217
|
+
const scroll = ui.getScrollContainer();
|
|
49218
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49219
|
+
const scrollLeftContinuous = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49220
|
+
ui.scrollToX(scroll, scrollLeftContinuous, settings.player.scrollSpeed);
|
|
49221
|
+
}
|
|
49222
|
+
}
|
|
49223
|
+
/**
|
|
49224
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.OffScreen}.
|
|
49225
|
+
* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
|
|
49226
|
+
* @internal
|
|
49227
|
+
*/
|
|
49228
|
+
class HorizontalOffScreenScrollHandler extends BasicScrollHandler {
|
|
49229
|
+
calculateLastScroll(currentBeatBounds) {
|
|
49230
|
+
return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
|
|
49231
|
+
}
|
|
49232
|
+
doScroll(currentBeatBounds) {
|
|
49233
|
+
const ui = this.api.uiFacade;
|
|
49234
|
+
const settings = this.api.settings;
|
|
49235
|
+
const scroll = ui.getScrollContainer();
|
|
49236
|
+
const elementRight = scroll.scrollLeft + ui.getOffset(null, scroll).w;
|
|
49237
|
+
const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
|
|
49238
|
+
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
49239
|
+
barBoundings.visualBounds.x < scroll.scrollLeft) {
|
|
49240
|
+
const scrollLeftOffScreen = barBoundings.realBounds.x + settings.player.scrollOffsetX;
|
|
49241
|
+
ui.scrollToX(scroll, scrollLeftOffScreen, settings.player.scrollSpeed);
|
|
49242
|
+
}
|
|
49243
|
+
}
|
|
49244
|
+
}
|
|
49245
|
+
/**
|
|
49246
|
+
* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Smooth}.
|
|
49247
|
+
* horiontal smooth scrolling aims to place the on-time position
|
|
49248
|
+
* at scrollOffsetX from a beat-to-beat perspective.
|
|
49249
|
+
* This achieves an steady cursor at the same position with rather the music sheet scrolling past it.
|
|
49250
|
+
* Due to some animation inconsistencies (e.g. CSS animation vs scrolling) there might be a slight
|
|
49251
|
+
* flickering of the cursor.
|
|
49252
|
+
*
|
|
49253
|
+
* To get a fully steady cursor the beat cursor can simply be visually hidden and a cursor can be placed at
|
|
49254
|
+
* `scrollOffsetX` by the integrator.
|
|
49255
|
+
* @internal
|
|
49256
|
+
*/
|
|
49257
|
+
class HorizontalSmoothScrollHandler {
|
|
49258
|
+
_api;
|
|
49259
|
+
_lastScroll = -1;
|
|
49260
|
+
_scrollContainerResizeUnregister;
|
|
49261
|
+
constructor(api) {
|
|
49262
|
+
this._api = api;
|
|
49263
|
+
// we need a resize listener for the overflow calculation
|
|
49264
|
+
this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
|
|
49265
|
+
const scrollContainer = api.uiFacade.getScrollContainer();
|
|
49266
|
+
const overflowNeeded = api.settings.player.scrollOffsetX;
|
|
49267
|
+
const viewPortSize = scrollContainer.width;
|
|
49268
|
+
// the content needs to shift out of screen (and back into screen with the offset)
|
|
49269
|
+
// that's why we need the whole width as additional overflow
|
|
49270
|
+
const overflowNeededAbsolute = viewPortSize + overflowNeeded;
|
|
49271
|
+
api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, false);
|
|
49272
|
+
});
|
|
49273
|
+
}
|
|
49274
|
+
[Symbol.dispose]() {
|
|
49275
|
+
this._scrollContainerResizeUnregister();
|
|
49276
|
+
this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, false);
|
|
49277
|
+
}
|
|
49278
|
+
forceScrollTo(currentBeatBounds) {
|
|
49279
|
+
const ui = this._api.uiFacade;
|
|
49280
|
+
const settings = this._api.settings;
|
|
49281
|
+
const scroll = ui.getScrollContainer();
|
|
49282
|
+
const barStartX = currentBeatBounds.onNotesX + settings.player.scrollOffsetY;
|
|
49283
|
+
ui.scrollToY(scroll, barStartX, 0);
|
|
49284
|
+
this._lastScroll = -1;
|
|
49285
|
+
}
|
|
49286
|
+
onBeatCursorUpdating(_startBeat, _endBeat, _cursorMode, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
49287
|
+
const ui = this._api.uiFacade;
|
|
49288
|
+
if (actualBeatCursorEndX === this._lastScroll && actualBeatCursorTransitionDuration > 0) {
|
|
49289
|
+
return;
|
|
49290
|
+
}
|
|
49291
|
+
// jump to start of new system
|
|
49292
|
+
const settings = this._api.settings;
|
|
49293
|
+
const scroll = ui.getScrollContainer();
|
|
49294
|
+
ui.scrollToX(scroll, actualBeatCursorStartX + settings.player.scrollOffsetX, 0);
|
|
49295
|
+
// instant scroll
|
|
49296
|
+
if (actualBeatCursorTransitionDuration === 0) {
|
|
49297
|
+
this._lastScroll = -1;
|
|
49298
|
+
return;
|
|
49299
|
+
}
|
|
49300
|
+
this._lastScroll = actualBeatCursorEndX;
|
|
49301
|
+
const scrollX = actualBeatCursorEndX + settings.player.scrollOffsetX;
|
|
49302
|
+
ui.scrollToX(scroll, scrollX, actualBeatCursorTransitionDuration);
|
|
49303
|
+
}
|
|
49038
49304
|
}
|
|
49039
49305
|
|
|
49040
49306
|
/**
|
|
@@ -49677,6 +49943,7 @@
|
|
|
49677
49943
|
_actualPlayerMode = exports.PlayerMode.Disabled;
|
|
49678
49944
|
_player;
|
|
49679
49945
|
_renderer;
|
|
49946
|
+
_defaultScrollHandler;
|
|
49680
49947
|
/**
|
|
49681
49948
|
* An indicator by how many midi-ticks the song contents are shifted.
|
|
49682
49949
|
* Grace beats at start might require a shift for the first beat to start at 0.
|
|
@@ -50446,6 +50713,42 @@
|
|
|
50446
50713
|
}
|
|
50447
50714
|
}
|
|
50448
50715
|
_tickCache = null;
|
|
50716
|
+
/**
|
|
50717
|
+
* A custom scroll handler which will be used to handle scrolling operations during playback.
|
|
50718
|
+
*
|
|
50719
|
+
* @category Properties - Player
|
|
50720
|
+
* @since 1.8.0
|
|
50721
|
+
* @example
|
|
50722
|
+
* JavaScript
|
|
50723
|
+
* ```js
|
|
50724
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
50725
|
+
* api.customScrollHandler = {
|
|
50726
|
+
* forceScrollTo(currentBeatBounds) {
|
|
50727
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50728
|
+
* api.uiFacade.scrollToY(scroll, currentBeatBounds.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50729
|
+
* },
|
|
50730
|
+
* onBeatCursorUpdating(startBeat, endBeat, cursorMode, relativePosition, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
|
|
50731
|
+
* const scroll = api.uiFacade.getScrollElement();
|
|
50732
|
+
* api.uiFacade.scrollToY(scroll, startBeat.barBounds.masterBarBounds.realBounds.y, 0);
|
|
50733
|
+
* }
|
|
50734
|
+
* }
|
|
50735
|
+
* ```
|
|
50736
|
+
*
|
|
50737
|
+
* @example
|
|
50738
|
+
* C#
|
|
50739
|
+
* ```cs
|
|
50740
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
50741
|
+
* api.CustomScrollHandler = new CustomScrollHandler();
|
|
50742
|
+
* ```
|
|
50743
|
+
*
|
|
50744
|
+
* @example
|
|
50745
|
+
* Android
|
|
50746
|
+
* ```kotlin
|
|
50747
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
50748
|
+
* api.customScrollHandler = CustomScrollHandler();
|
|
50749
|
+
* ```
|
|
50750
|
+
*/
|
|
50751
|
+
customScrollHandler;
|
|
50449
50752
|
/**
|
|
50450
50753
|
* The tick cache allowing lookup of midi ticks to beats.
|
|
50451
50754
|
* @remarks
|
|
@@ -51424,7 +51727,6 @@
|
|
|
51424
51727
|
_isInitialBeatCursorUpdate = true;
|
|
51425
51728
|
_previousStateForCursor = PlayerState.Paused;
|
|
51426
51729
|
_previousCursorCache = null;
|
|
51427
|
-
_lastScroll = 0;
|
|
51428
51730
|
_destroyCursors() {
|
|
51429
51731
|
if (!this._cursorWrapper) {
|
|
51430
51732
|
return;
|
|
@@ -51435,28 +51737,79 @@
|
|
|
51435
51737
|
this._beatCursor = null;
|
|
51436
51738
|
this._selectionWrapper = null;
|
|
51437
51739
|
}
|
|
51740
|
+
_createCursors() {
|
|
51741
|
+
if (this._cursorWrapper) {
|
|
51742
|
+
return;
|
|
51743
|
+
}
|
|
51744
|
+
const cursors = this.uiFacade.createCursors();
|
|
51745
|
+
if (cursors) {
|
|
51746
|
+
// store options and created elements for fast access
|
|
51747
|
+
this._cursorWrapper = cursors.cursorWrapper;
|
|
51748
|
+
this._barCursor = cursors.barCursor;
|
|
51749
|
+
this._beatCursor = cursors.beatCursor;
|
|
51750
|
+
this._selectionWrapper = cursors.selectionWrapper;
|
|
51751
|
+
this._isInitialBeatCursorUpdate = true;
|
|
51752
|
+
}
|
|
51753
|
+
if (this._currentBeat !== null) {
|
|
51754
|
+
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51755
|
+
}
|
|
51756
|
+
}
|
|
51438
51757
|
_updateCursors() {
|
|
51758
|
+
this._updateScrollHandler();
|
|
51439
51759
|
const enable = this._hasCursor;
|
|
51440
|
-
if (enable
|
|
51441
|
-
|
|
51442
|
-
// Create cursors
|
|
51443
|
-
const cursors = this.uiFacade.createCursors();
|
|
51444
|
-
if (cursors) {
|
|
51445
|
-
// store options and created elements for fast access
|
|
51446
|
-
this._cursorWrapper = cursors.cursorWrapper;
|
|
51447
|
-
this._barCursor = cursors.barCursor;
|
|
51448
|
-
this._beatCursor = cursors.beatCursor;
|
|
51449
|
-
this._selectionWrapper = cursors.selectionWrapper;
|
|
51450
|
-
this._isInitialBeatCursorUpdate = true;
|
|
51451
|
-
}
|
|
51452
|
-
if (this._currentBeat !== null) {
|
|
51453
|
-
this._cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
51454
|
-
}
|
|
51760
|
+
if (enable) {
|
|
51761
|
+
this._createCursors();
|
|
51455
51762
|
}
|
|
51456
51763
|
else if (!enable && this._cursorWrapper) {
|
|
51457
51764
|
this._destroyCursors();
|
|
51458
51765
|
}
|
|
51459
51766
|
}
|
|
51767
|
+
_scrollHandlerMode = exports.ScrollMode.Off;
|
|
51768
|
+
_scrollHandlerVertical = true;
|
|
51769
|
+
_updateScrollHandler() {
|
|
51770
|
+
const currentHandler = this._defaultScrollHandler;
|
|
51771
|
+
const scrollMode = this.settings.player.scrollMode;
|
|
51772
|
+
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51773
|
+
// no change
|
|
51774
|
+
if (this._scrollHandlerMode === scrollMode && this._scrollHandlerVertical === isVertical) {
|
|
51775
|
+
return;
|
|
51776
|
+
}
|
|
51777
|
+
// destroy current handler in favor of new one
|
|
51778
|
+
if (currentHandler) {
|
|
51779
|
+
currentHandler[Symbol.dispose]();
|
|
51780
|
+
const scroll = this.uiFacade.getScrollContainer();
|
|
51781
|
+
this.uiFacade.stopScrolling(scroll);
|
|
51782
|
+
}
|
|
51783
|
+
switch (scrollMode) {
|
|
51784
|
+
case exports.ScrollMode.Off:
|
|
51785
|
+
this._defaultScrollHandler = undefined;
|
|
51786
|
+
break;
|
|
51787
|
+
case exports.ScrollMode.Continuous:
|
|
51788
|
+
if (isVertical) {
|
|
51789
|
+
this._defaultScrollHandler = new VerticalContinuousScrollHandler(this);
|
|
51790
|
+
}
|
|
51791
|
+
else {
|
|
51792
|
+
this._defaultScrollHandler = new HorizontalContinuousScrollHandler(this);
|
|
51793
|
+
}
|
|
51794
|
+
break;
|
|
51795
|
+
case exports.ScrollMode.OffScreen:
|
|
51796
|
+
if (isVertical) {
|
|
51797
|
+
this._defaultScrollHandler = new VerticalOffScreenScrollHandler(this);
|
|
51798
|
+
}
|
|
51799
|
+
else {
|
|
51800
|
+
this._defaultScrollHandler = new HorizontalOffScreenScrollHandler(this);
|
|
51801
|
+
}
|
|
51802
|
+
break;
|
|
51803
|
+
case exports.ScrollMode.Smooth:
|
|
51804
|
+
if (isVertical) {
|
|
51805
|
+
this._defaultScrollHandler = new VerticalSmoothScrollHandler(this);
|
|
51806
|
+
}
|
|
51807
|
+
else {
|
|
51808
|
+
this._defaultScrollHandler = new HorizontalSmoothScrollHandler(this);
|
|
51809
|
+
}
|
|
51810
|
+
break;
|
|
51811
|
+
}
|
|
51812
|
+
}
|
|
51460
51813
|
/**
|
|
51461
51814
|
* updates the cursors to highlight the beat at the specified tick position
|
|
51462
51815
|
* @param tick
|
|
@@ -51519,57 +51872,9 @@
|
|
|
51519
51872
|
scrollToCursor() {
|
|
51520
51873
|
const beatBounds = this._currentBeatBounds;
|
|
51521
51874
|
if (beatBounds) {
|
|
51522
|
-
this.
|
|
51523
|
-
|
|
51524
|
-
|
|
51525
|
-
_internalScrollToCursor(barBoundings) {
|
|
51526
|
-
const scrollElement = this.uiFacade.getScrollContainer();
|
|
51527
|
-
const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
|
|
51528
|
-
const mode = this.settings.player.scrollMode;
|
|
51529
|
-
if (isVertical) {
|
|
51530
|
-
// when scrolling on the y-axis, we preliminary check if the new beat/bar have
|
|
51531
|
-
// moved on the y-axis
|
|
51532
|
-
const y = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51533
|
-
if (y !== this._lastScroll) {
|
|
51534
|
-
this._lastScroll = y;
|
|
51535
|
-
switch (mode) {
|
|
51536
|
-
case exports.ScrollMode.Continuous:
|
|
51537
|
-
const elementOffset = this.uiFacade.getOffset(scrollElement, this.container);
|
|
51538
|
-
this.uiFacade.scrollToY(scrollElement, elementOffset.y + y, this.settings.player.scrollSpeed);
|
|
51539
|
-
break;
|
|
51540
|
-
case exports.ScrollMode.OffScreen:
|
|
51541
|
-
const elementBottom = scrollElement.scrollTop + this.uiFacade.getOffset(null, scrollElement).h;
|
|
51542
|
-
if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
|
|
51543
|
-
barBoundings.visualBounds.y < scrollElement.scrollTop) {
|
|
51544
|
-
const scrollTop = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
|
|
51545
|
-
this.uiFacade.scrollToY(scrollElement, scrollTop, this.settings.player.scrollSpeed);
|
|
51546
|
-
}
|
|
51547
|
-
break;
|
|
51548
|
-
}
|
|
51549
|
-
}
|
|
51550
|
-
}
|
|
51551
|
-
else {
|
|
51552
|
-
// when scrolling on the x-axis, we preliminary check if the new bar has
|
|
51553
|
-
// moved on the x-axis
|
|
51554
|
-
const x = barBoundings.visualBounds.x;
|
|
51555
|
-
if (x !== this._lastScroll) {
|
|
51556
|
-
this._lastScroll = x;
|
|
51557
|
-
switch (mode) {
|
|
51558
|
-
case exports.ScrollMode.Continuous:
|
|
51559
|
-
const scrollLeftContinuous = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51560
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51561
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftContinuous, this.settings.player.scrollSpeed);
|
|
51562
|
-
break;
|
|
51563
|
-
case exports.ScrollMode.OffScreen:
|
|
51564
|
-
const elementRight = scrollElement.scrollLeft + this.uiFacade.getOffset(null, scrollElement).w;
|
|
51565
|
-
if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
|
|
51566
|
-
barBoundings.visualBounds.x < scrollElement.scrollLeft) {
|
|
51567
|
-
const scrollLeftOffScreen = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
|
|
51568
|
-
this._lastScroll = barBoundings.visualBounds.x;
|
|
51569
|
-
this.uiFacade.scrollToX(scrollElement, scrollLeftOffScreen, this.settings.player.scrollSpeed);
|
|
51570
|
-
}
|
|
51571
|
-
break;
|
|
51572
|
-
}
|
|
51875
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51876
|
+
if (handler) {
|
|
51877
|
+
handler.forceScrollTo(beatBounds);
|
|
51573
51878
|
}
|
|
51574
51879
|
}
|
|
51575
51880
|
}
|
|
@@ -51585,11 +51890,12 @@
|
|
|
51585
51890
|
}
|
|
51586
51891
|
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
51587
51892
|
let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
|
|
51893
|
+
let nextBeatBoundings = null;
|
|
51588
51894
|
// get position of next beat on same system
|
|
51589
51895
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
51590
51896
|
// if we are moving within the same bar or to the next bar
|
|
51591
51897
|
// transition to the next beat, otherwise transition to the end of the bar.
|
|
51592
|
-
|
|
51898
|
+
nextBeatBoundings = cache.findBeat(nextBeat);
|
|
51593
51899
|
if (nextBeatBoundings &&
|
|
51594
51900
|
nextBeatBoundings.barBounds.masterBarBounds.staffSystemBounds === barBoundings.staffSystemBounds) {
|
|
51595
51901
|
nextBeatX = nextBeatBoundings.onNotesX;
|
|
@@ -51615,25 +51921,29 @@
|
|
|
51615
51921
|
beatCursor.transitionToX(0, startBeatX);
|
|
51616
51922
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51617
51923
|
}
|
|
51924
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
51925
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51926
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51927
|
+
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51928
|
+
nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51929
|
+
duration = (duration / cursorSpeed) * factor;
|
|
51618
51930
|
// we need to put the transition to an own animation frame
|
|
51619
51931
|
// otherwise the stop animation above is not applied.
|
|
51620
51932
|
this.uiFacade.beginInvoke(() => {
|
|
51621
|
-
|
|
51622
|
-
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
51623
|
-
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
51624
|
-
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
51625
|
-
const doubleEndBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
51626
|
-
beatCursor.transitionToX((duration / cursorSpeed) * factor, doubleEndBeatX);
|
|
51933
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51627
51934
|
});
|
|
51628
51935
|
}
|
|
51629
51936
|
else {
|
|
51630
|
-
|
|
51937
|
+
duration = 0;
|
|
51938
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51631
51939
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51632
51940
|
}
|
|
51633
51941
|
}
|
|
51634
51942
|
else {
|
|
51635
51943
|
// ticking cursor
|
|
51636
|
-
|
|
51944
|
+
duration = 0;
|
|
51945
|
+
nextBeatX = startBeatX;
|
|
51946
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
51637
51947
|
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51638
51948
|
}
|
|
51639
51949
|
this._isInitialBeatCursorUpdate = false;
|
|
@@ -51656,7 +51966,10 @@
|
|
|
51656
51966
|
shouldNotifyBeatChange = true;
|
|
51657
51967
|
}
|
|
51658
51968
|
if (shouldScroll && !this._isBeatMouseDown && this.settings.player.scrollMode !== exports.ScrollMode.Off) {
|
|
51659
|
-
this.
|
|
51969
|
+
const handler = this.customScrollHandler ?? this._defaultScrollHandler;
|
|
51970
|
+
if (handler) {
|
|
51971
|
+
handler.onBeatCursorUpdating(beatBoundings, nextBeatBoundings === null ? undefined : nextBeatBoundings, cursorMode, startBeatX, nextBeatX, duration);
|
|
51972
|
+
}
|
|
51660
51973
|
}
|
|
51661
51974
|
// trigger an event for others to indicate which beat/bar is played
|
|
51662
51975
|
if (shouldNotifyBeatChange) {
|
|
@@ -53030,6 +53343,7 @@
|
|
|
53030
53343
|
const tickCache = this._tickCache;
|
|
53031
53344
|
if (currentBeat && tickCache) {
|
|
53032
53345
|
this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
53346
|
+
this.scrollToCursor();
|
|
53033
53347
|
}
|
|
53034
53348
|
}
|
|
53035
53349
|
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
|
|
@@ -54990,6 +55304,22 @@
|
|
|
54990
55304
|
canvasElement.style.position = 'relative';
|
|
54991
55305
|
return new HtmlElementContainer(canvasElement);
|
|
54992
55306
|
}
|
|
55307
|
+
setCanvasOverflow(canvasElement, overflow, isVertical) {
|
|
55308
|
+
const html = canvasElement.element;
|
|
55309
|
+
if (overflow === 0) {
|
|
55310
|
+
html.style.boxSizing = '';
|
|
55311
|
+
html.style.paddingRight = '';
|
|
55312
|
+
html.style.paddingBottom = '';
|
|
55313
|
+
}
|
|
55314
|
+
else if (isVertical) {
|
|
55315
|
+
html.style.boxSizing = 'content-box';
|
|
55316
|
+
html.style.paddingBottom = `${overflow}px`;
|
|
55317
|
+
}
|
|
55318
|
+
else {
|
|
55319
|
+
html.style.boxSizing = 'content-box';
|
|
55320
|
+
html.style.paddingRight = `${overflow}px`;
|
|
55321
|
+
}
|
|
55322
|
+
}
|
|
54993
55323
|
triggerEvent(container, name, details = null, originalEvent) {
|
|
54994
55324
|
const element = container.element;
|
|
54995
55325
|
name = `alphaTab.${name}`;
|
|
@@ -55547,54 +55877,79 @@
|
|
|
55547
55877
|
scrollToX(element, scrollTargetY, speed) {
|
|
55548
55878
|
this._internalScrollToX(element.element, scrollTargetY, speed);
|
|
55549
55879
|
}
|
|
55880
|
+
stopScrolling(scrollElement) {
|
|
55881
|
+
// stop any current animation
|
|
55882
|
+
const currentAnimation = this._scrollAnimationLookup.get(scrollElement.element);
|
|
55883
|
+
if (currentAnimation !== undefined) {
|
|
55884
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55885
|
+
}
|
|
55886
|
+
}
|
|
55887
|
+
get _nativeBrowserSmoothScroll() {
|
|
55888
|
+
const settings = this._api.settings.player;
|
|
55889
|
+
return settings.nativeBrowserSmoothScroll && settings.scrollMode !== exports.ScrollMode.Smooth;
|
|
55890
|
+
}
|
|
55891
|
+
_scrollAnimationId = 0;
|
|
55892
|
+
_activeScrollAnimations = new Set();
|
|
55893
|
+
_scrollAnimationLookup = new Map();
|
|
55550
55894
|
_internalScrollToY(element, scrollTargetY, speed) {
|
|
55551
|
-
if (this.
|
|
55895
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55552
55896
|
element.scrollTo({
|
|
55553
55897
|
top: scrollTargetY,
|
|
55554
55898
|
behavior: 'smooth'
|
|
55555
55899
|
});
|
|
55556
55900
|
}
|
|
55557
55901
|
else {
|
|
55558
|
-
|
|
55559
|
-
|
|
55560
|
-
|
|
55561
|
-
|
|
55562
|
-
|
|
55563
|
-
|
|
55564
|
-
|
|
55565
|
-
|
|
55566
|
-
|
|
55567
|
-
|
|
55568
|
-
|
|
55569
|
-
|
|
55570
|
-
|
|
55571
|
-
|
|
55572
|
-
window.requestAnimationFrame(step);
|
|
55902
|
+
this._internalScrollTo(element, element.scrollTop, scrollTargetY, speed, scroll => {
|
|
55903
|
+
element.scrollTop = scroll;
|
|
55904
|
+
});
|
|
55905
|
+
}
|
|
55906
|
+
}
|
|
55907
|
+
_internalScrollTo(element, startScroll, endScroll, scrollDuration, setValue) {
|
|
55908
|
+
// stop any current animation
|
|
55909
|
+
const currentAnimation = this._scrollAnimationLookup.get(element);
|
|
55910
|
+
if (currentAnimation !== undefined) {
|
|
55911
|
+
this._activeScrollAnimations.delete(currentAnimation);
|
|
55912
|
+
}
|
|
55913
|
+
if (scrollDuration === 0) {
|
|
55914
|
+
setValue(endScroll);
|
|
55915
|
+
return;
|
|
55573
55916
|
}
|
|
55917
|
+
// start new animation
|
|
55918
|
+
const animationId = this._scrollAnimationId++;
|
|
55919
|
+
this._scrollAnimationLookup.set(element, animationId);
|
|
55920
|
+
this._activeScrollAnimations.add(animationId);
|
|
55921
|
+
const diff = endScroll - startScroll;
|
|
55922
|
+
let start = 0;
|
|
55923
|
+
const step = (x) => {
|
|
55924
|
+
if (!this._activeScrollAnimations.has(animationId)) {
|
|
55925
|
+
return;
|
|
55926
|
+
}
|
|
55927
|
+
if (start === 0) {
|
|
55928
|
+
start = x;
|
|
55929
|
+
}
|
|
55930
|
+
const time = x - start;
|
|
55931
|
+
const percent = Math.min(time / scrollDuration, 1);
|
|
55932
|
+
setValue((startScroll + diff * percent) | 0);
|
|
55933
|
+
if (time < scrollDuration) {
|
|
55934
|
+
window.requestAnimationFrame(step);
|
|
55935
|
+
}
|
|
55936
|
+
else {
|
|
55937
|
+
this._activeScrollAnimations.delete(animationId);
|
|
55938
|
+
}
|
|
55939
|
+
};
|
|
55940
|
+
window.requestAnimationFrame(step);
|
|
55574
55941
|
}
|
|
55575
55942
|
_internalScrollToX(element, scrollTargetX, speed) {
|
|
55576
|
-
if (this.
|
|
55943
|
+
if (this._nativeBrowserSmoothScroll) {
|
|
55577
55944
|
element.scrollTo({
|
|
55578
55945
|
left: scrollTargetX,
|
|
55579
55946
|
behavior: 'smooth'
|
|
55580
55947
|
});
|
|
55581
55948
|
}
|
|
55582
55949
|
else {
|
|
55583
|
-
|
|
55584
|
-
|
|
55585
|
-
|
|
55586
|
-
const step = (t) => {
|
|
55587
|
-
if (start === 0) {
|
|
55588
|
-
start = t;
|
|
55589
|
-
}
|
|
55590
|
-
const time = t - start;
|
|
55591
|
-
const percent = Math.min(time / speed, 1);
|
|
55592
|
-
element.scrollLeft = (startX + diff * percent) | 0;
|
|
55593
|
-
if (time < speed) {
|
|
55594
|
-
window.requestAnimationFrame(step);
|
|
55595
|
-
}
|
|
55596
|
-
};
|
|
55597
|
-
window.requestAnimationFrame(step);
|
|
55950
|
+
this._internalScrollTo(element, element.scrollLeft, scrollTargetX, speed, scroll => {
|
|
55951
|
+
element.scrollLeft = scroll;
|
|
55952
|
+
});
|
|
55598
55953
|
}
|
|
55599
55954
|
}
|
|
55600
55955
|
createBackingTrackPlayer() {
|
|
@@ -61707,8 +62062,8 @@
|
|
|
61707
62062
|
}
|
|
61708
62063
|
}
|
|
61709
62064
|
}
|
|
62065
|
+
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61710
62066
|
if (hasAnyTrackName) {
|
|
61711
|
-
this.accoladeWidth += settings.display.systemLabelPaddingLeft;
|
|
61712
62067
|
this.accoladeWidth += settings.display.systemLabelPaddingRight;
|
|
61713
62068
|
}
|
|
61714
62069
|
}
|