@coderline/alphatab 1.3.0-alpha.411 → 1.3.0-alpha.418

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * alphaTab v1.3.0-alpha.411 (develop, build 411)
2
+ * alphaTab v1.3.0-alpha.418 (develop, build 418)
3
3
  *
4
4
  * Copyright © 2022, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
@@ -24150,6 +24150,10 @@
24150
24150
  get onTimeX() {
24151
24151
  return this.onNotes.x + this.onNotes.centerX;
24152
24152
  }
24153
+ addTie(tie) {
24154
+ tie.renderer = this.renderer;
24155
+ this.ties.push(tie);
24156
+ }
24153
24157
  registerLayoutingInfo(layoutings) {
24154
24158
  let preBeatStretch = this.preNotes.computedWidth + this.onNotes.centerX;
24155
24159
  if (this.beat.graceGroup && !this.beat.graceGroup.isComplete) {
@@ -24158,8 +24162,11 @@
24158
24162
  let postBeatStretch = this.onNotes.computedWidth - this.onNotes.centerX;
24159
24163
  // make space for flag
24160
24164
  const helper = this.renderer.helpers.getBeamingHelperForBeat(this.beat);
24161
- if (helper && helper.hasFlag || this.beat.graceType !== GraceType.None) {
24162
- postBeatStretch += (FlagGlyph.FlagWidth * this.scale * (this.beat.graceType !== GraceType.None ? NoteHeadGlyph.GraceScale : 1));
24165
+ if ((helper && helper.hasFlag) || this.beat.graceType !== GraceType.None) {
24166
+ postBeatStretch +=
24167
+ FlagGlyph.FlagWidth *
24168
+ this.scale *
24169
+ (this.beat.graceType !== GraceType.None ? NoteHeadGlyph.GraceScale : 1);
24163
24170
  }
24164
24171
  for (const tie of this.ties) {
24165
24172
  postBeatStretch += tie.width;
@@ -24199,6 +24206,7 @@
24199
24206
  while (i >= 0) {
24200
24207
  this.createTies(this.beat.notes[i--]);
24201
24208
  }
24209
+ this.renderer.registerTies(this.ties);
24202
24210
  this.updateWidth();
24203
24211
  }
24204
24212
  updateWidth() {
@@ -24230,9 +24238,6 @@
24230
24238
  this.width = this.minWidth;
24231
24239
  }
24232
24240
  scaleToWidth(beatWidth) {
24233
- for (let tie of this.ties) {
24234
- tie.doLayout();
24235
- }
24236
24241
  this.onNotes.updateBeamingHelper();
24237
24242
  this.width = beatWidth;
24238
24243
  }
@@ -25030,6 +25035,7 @@
25030
25035
  this._playerState = PlayerState.Paused;
25031
25036
  // we need to update our position caches if we render a tablature
25032
25037
  this.renderer.postRenderFinished.on(() => {
25038
+ this._currentBeat = null;
25033
25039
  this.cursorUpdateTick(this._previousTick, false, this._previousTick > 10);
25034
25040
  });
25035
25041
  if (this.player) {
@@ -25753,7 +25759,7 @@
25753
25759
  class HtmlElementContainer {
25754
25760
  constructor(element) {
25755
25761
  this._resizeListeners = 0;
25756
- this._lastBounds = new Bounds();
25762
+ this.lastBounds = new Bounds();
25757
25763
  this.element = element;
25758
25764
  this.mouseDown = {
25759
25765
  on: (value) => {
@@ -25844,23 +25850,23 @@
25844
25850
  }
25845
25851
  setBounds(x, y, w, h) {
25846
25852
  if (isNaN(x)) {
25847
- x = this._lastBounds.x;
25853
+ x = this.lastBounds.x;
25848
25854
  }
25849
25855
  if (isNaN(y)) {
25850
- y = this._lastBounds.y;
25856
+ y = this.lastBounds.y;
25851
25857
  }
25852
25858
  if (isNaN(w)) {
25853
- w = this._lastBounds.w;
25859
+ w = this.lastBounds.w;
25854
25860
  }
25855
25861
  if (isNaN(h)) {
25856
- h = this._lastBounds.h;
25862
+ h = this.lastBounds.h;
25857
25863
  }
25858
25864
  this.element.style.transform = `translate(${x}px, ${y}px) scale(${w}, ${h})`;
25859
25865
  this.element.style.transformOrigin = 'top left';
25860
- this._lastBounds.x = x;
25861
- this._lastBounds.y = y;
25862
- this._lastBounds.w = w;
25863
- this._lastBounds.h = h;
25866
+ this.lastBounds.x = x;
25867
+ this.lastBounds.y = y;
25868
+ this.lastBounds.w = w;
25869
+ this.lastBounds.h = h;
25864
25870
  }
25865
25871
  appendChild(child) {
25866
25872
  this.element.appendChild(child.element);
@@ -26939,6 +26945,71 @@
26939
26945
  }
26940
26946
  }
26941
26947
 
26948
+ /**
26949
+ * An IContainer implementation which can be used for cursors and select ranges
26950
+ * where browser scaling is relevant.
26951
+ *
26952
+ * The problem is that with having 1x1 pixel elements which are sized then to the actual size with a
26953
+ * scale transform this cannot be combined properly with a browser zoom.
26954
+ *
26955
+ * The browser will apply first the browser zoom to the 1x1px element and then apply the scale leaving it always
26956
+ * at full scale instead of a 50% browser zoom.
26957
+ *
26958
+ * This is solved in this container by scaling the element first up to a higher degree (as specified)
26959
+ * so that the browser can do a scaling according to typical zoom levels and then the scaling will work.
26960
+ * @target web
26961
+ */
26962
+ class ScalableHtmlElementContainer extends HtmlElementContainer {
26963
+ constructor(element, xscale, yscale) {
26964
+ super(element);
26965
+ this._xscale = xscale;
26966
+ this._yscale = yscale;
26967
+ }
26968
+ get width() {
26969
+ return this.element.offsetWidth / this._xscale;
26970
+ }
26971
+ set width(value) {
26972
+ this.element.style.width = value * this._xscale + 'px';
26973
+ }
26974
+ get height() {
26975
+ return this.element.offsetHeight / this._yscale;
26976
+ }
26977
+ set height(value) {
26978
+ if (value >= 0) {
26979
+ this.element.style.height = value * this._yscale + 'px';
26980
+ }
26981
+ else {
26982
+ this.element.style.height = '100%';
26983
+ }
26984
+ }
26985
+ setBounds(x, y, w, h) {
26986
+ if (isNaN(x)) {
26987
+ x = this.lastBounds.x;
26988
+ }
26989
+ if (isNaN(y)) {
26990
+ y = this.lastBounds.y;
26991
+ }
26992
+ if (isNaN(w)) {
26993
+ w = this.lastBounds.w;
26994
+ }
26995
+ else {
26996
+ w = w / this._xscale;
26997
+ }
26998
+ if (isNaN(h)) {
26999
+ h = this.lastBounds.h;
27000
+ }
27001
+ else {
27002
+ h = h / this._yscale;
27003
+ }
27004
+ this.element.style.transform = `translate(${x}px, ${y}px) scale(${w}, ${h})`;
27005
+ this.element.style.transformOrigin = 'top left';
27006
+ this.lastBounds.x = x;
27007
+ this.lastBounds.y = y;
27008
+ this.lastBounds.w = w;
27009
+ this.lastBounds.h = h;
27010
+ }
27011
+ }
27012
+
26942
27013
  /**
26943
27014
  * @target web
26944
27015
  */
@@ -27423,9 +27494,11 @@
27423
27494
  cursorWrapper.classList.add('at-cursors');
27424
27495
  let selectionWrapper = document.createElement('div');
27425
27496
  selectionWrapper.classList.add('at-selection');
27426
- let barCursor = document.createElement('div');
27497
+ const barCursorContainer = this.createScalingElement();
27498
+ const beatCursorContainer = this.createScalingElement();
27499
+ let barCursor = barCursorContainer.element;
27427
27500
  barCursor.classList.add('at-cursor-bar');
27428
- let beatCursor = document.createElement('div');
27501
+ let beatCursor = beatCursorContainer.element;
27429
27502
  beatCursor.classList.add('at-cursor-beat');
27430
27503
  // required css styles
27431
27504
  element.style.position = 'relative';
@@ -27439,21 +27512,23 @@
27439
27512
  barCursor.style.left = '0';
27440
27513
  barCursor.style.top = '0';
27441
27514
  barCursor.style.willChange = 'transform';
27442
- barCursor.style.width = '1px';
27443
- barCursor.style.height = '1px';
27515
+ barCursorContainer.width = 1;
27516
+ barCursorContainer.height = 1;
27517
+ barCursorContainer.setBounds(0, 0, 1, 1);
27444
27518
  beatCursor.style.position = 'absolute';
27445
27519
  beatCursor.style.transition = 'all 0s linear';
27446
27520
  beatCursor.style.left = '0';
27447
27521
  beatCursor.style.top = '0';
27448
27522
  beatCursor.style.willChange = 'transform';
27449
- beatCursor.style.width = '3px';
27450
- beatCursor.style.height = '1px';
27523
+ beatCursorContainer.width = 3;
27524
+ beatCursorContainer.height = 1;
27525
+ beatCursorContainer.setBounds(0, 0, 1, 1);
27451
27526
  // add cursors to UI
27452
27527
  element.insertBefore(cursorWrapper, element.firstChild);
27453
27528
  cursorWrapper.appendChild(selectionWrapper);
27454
27529
  cursorWrapper.appendChild(barCursor);
27455
27530
  cursorWrapper.appendChild(beatCursor);
27456
- return new Cursors(new HtmlElementContainer(cursorWrapper), new HtmlElementContainer(barCursor), new HtmlElementContainer(beatCursor), new HtmlElementContainer(selectionWrapper));
27531
+ return new Cursors(new HtmlElementContainer(cursorWrapper), barCursorContainer, beatCursorContainer, new HtmlElementContainer(selectionWrapper));
27457
27532
  }
27458
27533
  getOffset(scrollContainer, container) {
27459
27534
  let element = container.element;
@@ -27507,11 +27582,20 @@
27507
27582
  return this._scrollContainer;
27508
27583
  }
27509
27584
  createSelectionElement() {
27510
- let element = document.createElement('div');
27585
+ return this.createScalingElement();
27586
+ }
27587
+ createScalingElement() {
27588
+ const element = document.createElement('div');
27511
27589
  element.style.position = 'absolute';
27512
- element.style.width = '1px';
27513
- element.style.height = '1px';
27514
- return new HtmlElementContainer(element);
27590
+ // to typical browser zoom levels are:
27591
+ // Chromium: 25,33,50,67,75,80,90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500
27592
+ // Firefox: 30, 50, 67, 80, 90, 100, 110, 120, 133, 150, 170, 200, 240, 300, 400, 500
27593
+ // with having a 100x100 scaling container we should be able to provide appropriate scaling
27594
+ const container = new ScalableHtmlElementContainer(element, 100, 100);
27595
+ container.width = 1;
27596
+ container.height = 1;
27597
+ container.setBounds(0, 0, 1, 1);
27598
+ return container;
27515
27599
  }
27516
27600
  scrollToY(element, scrollTargetY, speed) {
27517
27601
  this.internalScrollToY(element.element, scrollTargetY, speed);
@@ -29426,6 +29510,7 @@
29426
29510
  this._preBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
29427
29511
  this._voiceContainers = new Map();
29428
29512
  this._postBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
29513
+ this._ties = [];
29429
29514
  this.x = 0;
29430
29515
  this.y = 0;
29431
29516
  this.width = 0;
@@ -29476,18 +29561,25 @@
29476
29561
  }
29477
29562
  return this.scoreRenderer.layout.getRendererForBar(this.staff.staveId, this.bar.previousBar);
29478
29563
  }
29564
+ registerTies(ties) {
29565
+ this._ties.push(...ties);
29566
+ }
29479
29567
  get middleYPosition() {
29480
29568
  return 0;
29481
29569
  }
29482
29570
  registerOverflowTop(topOverflow) {
29483
29571
  if (topOverflow > this.topOverflow) {
29484
29572
  this.topOverflow = topOverflow;
29573
+ return true;
29485
29574
  }
29575
+ return false;
29486
29576
  }
29487
29577
  registerOverflowBottom(bottomOverflow) {
29488
29578
  if (bottomOverflow > this.bottomOverflow) {
29489
29579
  this.bottomOverflow = bottomOverflow;
29580
+ return true;
29490
29581
  }
29582
+ return false;
29491
29583
  }
29492
29584
  scaleToWidth(width) {
29493
29585
  // preBeat and postBeat glyphs do not get resized
@@ -29553,12 +29645,35 @@
29553
29645
  }
29554
29646
  finalizeRenderer() {
29555
29647
  this.isFinalized = true;
29648
+ let didChangeOverflows = false;
29649
+ // allow spacing to be used for tie overflows
29650
+ const barTop = this.y - this.staff.topSpacing;
29651
+ const barBottom = this.y + this.height + this.staff.bottomSpacing;
29652
+ for (const tie of this._ties) {
29653
+ tie.doLayout();
29654
+ if (tie.height > 0) {
29655
+ const bottomOverflow = tie.y + tie.height - barBottom;
29656
+ if (bottomOverflow > 0) {
29657
+ if (this.registerOverflowBottom(bottomOverflow)) {
29658
+ didChangeOverflows = true;
29659
+ }
29660
+ }
29661
+ const topOverflow = tie.y - barTop;
29662
+ if (topOverflow < 0) {
29663
+ if (this.registerOverflowTop(topOverflow * -1)) {
29664
+ didChangeOverflows = true;
29665
+ }
29666
+ }
29667
+ }
29668
+ }
29669
+ return didChangeOverflows;
29556
29670
  }
29557
29671
  doLayout() {
29558
29672
  if (!this.bar) {
29559
29673
  return;
29560
29674
  }
29561
29675
  this.helpers.initialize();
29676
+ this._ties = [];
29562
29677
  this._preBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
29563
29678
  this._preBeatGlyphs.renderer = this;
29564
29679
  this._voiceContainers.clear();
@@ -29647,7 +29762,7 @@
29647
29762
  paintBackground(cx, cy, canvas) {
29648
29763
  this.layoutingInfo.paint(cx + this.x + this._preBeatGlyphs.x + this._preBeatGlyphs.width, cy + this.y + this.height, canvas);
29649
29764
  // canvas.color = Color.random();
29650
- // canvas.fillRect(cx + this.x + this._preBeatGlyphs.x, cy + this.y, this._preBeatGlyphs.width, this.height);
29765
+ // canvas.fillRect(cx + this.x, cy + this.y, this.width, this.height);
29651
29766
  }
29652
29767
  buildBoundingsLookup(masterBarBounds, cx, cy) {
29653
29768
  let barBounds = new BarBounds();
@@ -30120,12 +30235,15 @@
30120
30235
  super.updateSizes();
30121
30236
  }
30122
30237
  finalizeRenderer() {
30123
- super.finalizeRenderer();
30124
- this.updateHeight();
30238
+ let didChange = super.finalizeRenderer();
30239
+ if (this.updateHeight()) {
30240
+ didChange = true;
30241
+ }
30242
+ return didChange;
30125
30243
  }
30126
30244
  updateHeight() {
30127
30245
  if (!this.sizingInfo) {
30128
- return;
30246
+ return false;
30129
30247
  }
30130
30248
  let y = 0;
30131
30249
  for (let slot of this.sizingInfo.slots) {
@@ -30136,7 +30254,11 @@
30136
30254
  }
30137
30255
  y += slot.shared.height;
30138
30256
  }
30139
- this.height = y;
30257
+ if (y !== this.height) {
30258
+ this.height = y;
30259
+ return true;
30260
+ }
30261
+ return false;
30140
30262
  }
30141
30263
  applyLayoutingInfo() {
30142
30264
  if (!super.applyLayoutingInfo()) {
@@ -31406,20 +31528,20 @@
31406
31528
  }
31407
31529
  doLayout() {
31408
31530
  super.doLayout();
31409
- this.height = 20 * this.scale;
31531
+ this.height = this.renderer.resources.markerFont.size * this.scale;
31410
31532
  }
31411
31533
  paint(cx, cy, canvas) {
31412
31534
  let res = this.renderer.resources;
31413
31535
  canvas.font = res.markerFont;
31414
31536
  let textw = canvas.measureText('tr');
31415
- canvas.fillText('tr', cx + this.x, cy + this.y + canvas.font.size / 2);
31537
+ canvas.fillText('tr', cx + this.x, cy + this.y);
31416
31538
  let startX = textw + 3 * this.scale;
31417
31539
  let endX = this.width - startX;
31418
31540
  let waveScale = 1.2;
31419
31541
  let step = 11 * this.scale * waveScale;
31420
31542
  let loops = Math.max(1, (endX - startX) / step);
31421
31543
  let loopX = startX;
31422
- let loopY = cy + this.y + this.height;
31544
+ let loopY = cy + this.y + this.height * 1.2;
31423
31545
  for (let i = 0; i < loops; i++) {
31424
31546
  canvas.fillMusicFontSymbol(cx + this.x + loopX, loopY, waveScale, MusicFontSymbol.WiggleTrill, false);
31425
31547
  loopX += step;
@@ -31978,8 +32100,15 @@
31978
32100
  // the space over the bar renderers, for now we evenly apply the space to all bars
31979
32101
  let difference = width - this.staveGroup.width;
31980
32102
  let spacePerBar = difference / this.barRenderers.length;
32103
+ let x = 0;
32104
+ let topOverflow = this.topOverflow;
31981
32105
  for (let i = 0, j = this.barRenderers.length; i < j; i++) {
31982
- this.barRenderers[i].scaleToWidth(this.barRenderers[i].width + spacePerBar);
32106
+ this.barRenderers[i].x = x;
32107
+ this.barRenderers[i].y = this.topSpacing + topOverflow;
32108
+ if (difference !== 0) {
32109
+ this.barRenderers[i].scaleToWidth(this.barRenderers[i].width + spacePerBar);
32110
+ }
32111
+ x += this.barRenderers[i].width;
31983
32112
  }
31984
32113
  }
31985
32114
  get topOverflow() {
@@ -32003,19 +32132,29 @@
32003
32132
  return m;
32004
32133
  }
32005
32134
  finalizeStaff() {
32006
- let x = 0;
32007
32135
  this.height = 0;
32136
+ // 1st pass: let all renderers finalize themselves, this might cause
32137
+ // changes in the overflows
32138
+ let needsSecondPass = false;
32008
32139
  let topOverflow = this.topOverflow;
32009
- let bottomOverflow = this.bottomOverflow;
32010
32140
  for (let i = 0; i < this.barRenderers.length; i++) {
32011
- this.barRenderers[i].x = x;
32012
32141
  this.barRenderers[i].y = this.topSpacing + topOverflow;
32013
32142
  this.height = Math.max(this.height, this.barRenderers[i].height);
32014
- this.barRenderers[i].finalizeRenderer();
32015
- x += this.barRenderers[i].width;
32143
+ if (this.barRenderers[i].finalizeRenderer()) {
32144
+ needsSecondPass = true;
32145
+ }
32146
+ }
32147
+ // 2nd pass: move renderers to correct position respecting the new overflows
32148
+ if (needsSecondPass) {
32149
+ topOverflow = this.topOverflow;
32150
+ for (let i = 0; i < this.barRenderers.length; i++) {
32151
+ this.barRenderers[i].y = this.topSpacing + topOverflow;
32152
+ this.height = Math.max(this.height, this.barRenderers[i].height);
32153
+ this.barRenderers[i].finalizeRenderer();
32154
+ }
32016
32155
  }
32017
32156
  if (this.height > 0) {
32018
- this.height += this.topSpacing + topOverflow + bottomOverflow + this.bottomSpacing;
32157
+ this.height += this.topSpacing + topOverflow + this.bottomOverflow + this.bottomSpacing;
32019
32158
  }
32020
32159
  }
32021
32160
  paint(cx, cy, canvas, startIndex, count) {
@@ -33205,7 +33344,7 @@
33205
33344
  ' to ' +
33206
33345
  currentPartial.masterBars[currentPartial.masterBars.length - 1].index, null);
33207
33346
  }
33208
- this._group.finalizeGroup();
33347
+ this.finalizeGroup();
33209
33348
  this.height = Math.floor(this._group.y + this._group.height);
33210
33349
  this.width = this._group.x + this._group.width + this._pagePadding[2];
33211
33350
  currentBarIndex = 0;
@@ -33243,6 +33382,10 @@
33243
33382
  }
33244
33383
  this.height = this.layoutAndRenderAnnotation(this.height) + this._pagePadding[3];
33245
33384
  }
33385
+ finalizeGroup() {
33386
+ this._group.scaleToWidth(this._group.width);
33387
+ this._group.finalizeGroup();
33388
+ }
33246
33389
  }
33247
33390
  HorizontalScreenLayout.PagePadding = [20, 20, 20, 20];
33248
33391
  HorizontalScreenLayout.GroupSpacing = 20;
@@ -33439,7 +33582,6 @@
33439
33582
  for (let i = 0; i < this._groups.length; i++) {
33440
33583
  let group = this._groups[i];
33441
33584
  this.fitGroup(group);
33442
- group.finalizeGroup();
33443
33585
  y += this.paintGroup(group, oldHeight);
33444
33586
  }
33445
33587
  }
@@ -33472,7 +33614,6 @@
33472
33614
  group.isLast = this.lastBarIndex === group.lastBarIndex;
33473
33615
  this._groups.push(group);
33474
33616
  this.fitGroup(group);
33475
- group.finalizeGroup();
33476
33617
  y += this.paintGroup(group, oldHeight);
33477
33618
  // note: we do not increase currentIndex here to have it added to the next group
33478
33619
  group = this.createEmptyStaveGroup();
@@ -33484,7 +33625,6 @@
33484
33625
  group.isLast = this.lastBarIndex === group.lastBarIndex;
33485
33626
  // don't forget to finish the last group
33486
33627
  this.fitGroup(group);
33487
- group.finalizeGroup();
33488
33628
  y += this.paintGroup(group, oldHeight);
33489
33629
  }
33490
33630
  return y;
@@ -33503,7 +33643,6 @@
33503
33643
  currentBarIndex = group.lastBarIndex + 1;
33504
33644
  // finalize group (sizing etc).
33505
33645
  this.fitGroup(group);
33506
- group.finalizeGroup();
33507
33646
  Logger.debug(this.name, 'Rendering partial from bar ' + group.firstBarIndex + ' to ' + group.lastBarIndex, null);
33508
33647
  y += this.paintGroup(group, y);
33509
33648
  }
@@ -33540,6 +33679,10 @@
33540
33679
  if (group.isFull || group.width > this.maxWidth) {
33541
33680
  group.scaleToWidth(this.maxWidth);
33542
33681
  }
33682
+ else {
33683
+ group.scaleToWidth(group.width);
33684
+ }
33685
+ group.finalizeGroup();
33543
33686
  }
33544
33687
  createStaveGroup(currentBarIndex, endIndex) {
33545
33688
  let group = this.createEmptyStaveGroup();
@@ -33964,27 +34107,33 @@
33964
34107
  this.startNoteRenderer = null;
33965
34108
  this.endNoteRenderer = null;
33966
34109
  this.tieDirection = BeamDirection.Up;
34110
+ this._startX = 0;
34111
+ this._startY = 0;
34112
+ this._endX = 0;
34113
+ this._endY = 0;
34114
+ this._tieHeight = 0;
34115
+ this._shouldDraw = false;
33967
34116
  this.startBeat = startBeat;
33968
34117
  this.endBeat = endBeat;
33969
34118
  this.forEnd = forEnd;
33970
34119
  }
33971
34120
  doLayout() {
33972
34121
  this.width = 0;
33973
- }
33974
- paint(cx, cy, canvas) {
34122
+ // TODO fix nullability of start/end beat,
33975
34123
  if (!this.endBeat) {
34124
+ this._shouldDraw = false;
33976
34125
  return;
33977
34126
  }
33978
- // TODO fix nullability of start/end beat,
33979
34127
  let startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staveId, this.startBeat.voice.bar);
33980
34128
  this.startNoteRenderer = startNoteRenderer;
33981
34129
  let endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staveId, this.endBeat.voice.bar);
33982
34130
  this.endNoteRenderer = endNoteRenderer;
33983
- let startX = 0;
33984
- let endX = 0;
33985
- let startY = 0;
33986
- let endY = 0;
33987
- let shouldDraw = false;
34131
+ this._startX = 0;
34132
+ this._endX = 0;
34133
+ this._startY = 0;
34134
+ this._endY = 0;
34135
+ this.height = 0;
34136
+ this._shouldDraw = false;
33988
34137
  // if we are on the tie start, we check if we
33989
34138
  // either can draw till the end note, or we just can draw till the bar end
33990
34139
  this.tieDirection = !startNoteRenderer
@@ -33993,39 +34142,54 @@
33993
34142
  if (!this.forEnd && startNoteRenderer) {
33994
34143
  // line break or bar break
33995
34144
  if (startNoteRenderer !== endNoteRenderer) {
33996
- startX = cx + startNoteRenderer.x + this.getStartX();
33997
- startY = cy + startNoteRenderer.y + this.getStartY() + this.yOffset;
34145
+ this._startX = startNoteRenderer.x + this.getStartX();
34146
+ this._startY = startNoteRenderer.y + this.getStartY() + this.yOffset;
33998
34147
  // line break: to bar end
33999
34148
  if (!endNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
34000
- endX = cx + startNoteRenderer.x + startNoteRenderer.width;
34001
- endY = startY;
34149
+ this._endX = startNoteRenderer.x + startNoteRenderer.width;
34150
+ this._endY = this._startY;
34002
34151
  }
34003
34152
  else {
34004
- endX = cx + endNoteRenderer.x + this.getEndX();
34005
- endY = cy + endNoteRenderer.y + this.getEndY() + this.yOffset;
34153
+ this._endX = endNoteRenderer.x + this.getEndX();
34154
+ this._endY = endNoteRenderer.y + this.getEndY() + this.yOffset;
34006
34155
  }
34007
34156
  }
34008
34157
  else {
34009
- startX = cx + startNoteRenderer.x + this.getStartX();
34010
- endX = cx + endNoteRenderer.x + this.getEndX();
34011
- startY = cy + startNoteRenderer.y + this.getStartY() + this.yOffset;
34012
- endY = cy + endNoteRenderer.y + this.getEndY() + this.yOffset;
34158
+ this._startX = startNoteRenderer.x + this.getStartX();
34159
+ this._endX = endNoteRenderer.x + this.getEndX();
34160
+ this._startY = startNoteRenderer.y + this.getStartY() + this.yOffset;
34161
+ this._endY = endNoteRenderer.y + this.getEndY() + this.yOffset;
34013
34162
  }
34014
- shouldDraw = true;
34163
+ this._shouldDraw = true;
34015
34164
  }
34016
34165
  else if (!startNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
34017
- startX = cx + endNoteRenderer.x;
34018
- endX = cx + endNoteRenderer.x + this.getEndX();
34019
- startY = cy + endNoteRenderer.y + this.getEndY() + this.yOffset;
34020
- endY = startY;
34021
- shouldDraw = true;
34166
+ this._startX = endNoteRenderer.x;
34167
+ this._endX = endNoteRenderer.x + this.getEndX();
34168
+ this._startY = endNoteRenderer.y + this.getEndY() + this.yOffset;
34169
+ this._endY = this._startY;
34170
+ this._shouldDraw = true;
34171
+ }
34172
+ if (this._shouldDraw) {
34173
+ this.y = Math.min(this._startY, this._endY);
34174
+ if (this.shouldDrawBendSlur()) {
34175
+ this._tieHeight = 0; // TODO: Bend slur height to be considered?
34176
+ }
34177
+ else {
34178
+ this._tieHeight = this.getTieHeight(this._startX, this._startY, this._endX, this._endY);
34179
+ this.height = TieGlyph.calculateActualTieHeight(this.renderer.scale, this._startX, this._startY, this._endX, this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, 4).h;
34180
+ }
34181
+ if (this.tieDirection === BeamDirection.Up) {
34182
+ this.y -= this.height;
34183
+ }
34022
34184
  }
34023
- if (shouldDraw) {
34185
+ }
34186
+ paint(cx, cy, canvas) {
34187
+ if (this._shouldDraw) {
34024
34188
  if (this.shouldDrawBendSlur()) {
34025
- TieGlyph.drawBendSlur(canvas, startX, startY, endX, endY, this.tieDirection === BeamDirection.Down, this.scale);
34189
+ TieGlyph.drawBendSlur(canvas, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, this.scale);
34026
34190
  }
34027
34191
  else {
34028
- TieGlyph.paintTie(canvas, this.scale, startX, startY, endX, endY, this.tieDirection === BeamDirection.Down, this.getTieHeight(startX, startY, endX, endY), 4);
34192
+ TieGlyph.paintTie(canvas, this.scale, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, 4);
34029
34193
  }
34030
34194
  }
34031
34195
  }
@@ -34050,9 +34214,42 @@
34050
34214
  getEndX() {
34051
34215
  return 0;
34052
34216
  }
34053
- static paintTie(canvas, scale, x1, y1, x2, y2, down = false, offset = 22, size = 4) {
34217
+ static calculateActualTieHeight(scale, x1, y1, x2, y2, down, offset, size) {
34218
+ const cp = TieGlyph.computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
34219
+ x1 = cp[0];
34220
+ y1 = cp[1];
34221
+ const cpx = cp[2];
34222
+ const cpy = cp[3];
34223
+ x2 = cp[6];
34224
+ y2 = cp[7];
34225
+ const tx = (x1 - cpx) / (x1 - 2 * cpx + x2);
34226
+ const ex = TieGlyph.calculateExtrema(x1, y1, cpx, cpy, x2, y2, tx);
34227
+ const xMin = ex.length > 0 ? Math.min(x1, x2, ex[0]) : Math.min(x1, x2);
34228
+ const xMax = ex.length > 0 ? Math.max(x1, x2, ex[0]) : Math.max(x1, x2);
34229
+ const ty = (y1 - cpy) / (y1 - 2 * cpy + y2);
34230
+ const ey = TieGlyph.calculateExtrema(x1, y1, cpx, cpy, x2, y2, ty);
34231
+ const yMin = ey.length > 0 ? Math.min(y1, y2, ey[1]) : Math.min(y1, y2);
34232
+ const yMax = ey.length > 0 ? Math.max(y1, y2, ey[1]) : Math.max(y1, y2);
34233
+ const b = new Bounds();
34234
+ b.x = xMin;
34235
+ b.y = yMin;
34236
+ b.w = xMax - xMin;
34237
+ b.h = yMax - yMin;
34238
+ return b;
34239
+ }
34240
+ static calculateExtrema(x1, y1, cpx, cpy, x2, y2, t) {
34241
+ if (t <= 0 || 1 <= t) {
34242
+ return [];
34243
+ }
34244
+ const c1x = x1 + (cpx - x1) * t;
34245
+ const c1y = y1 + (cpy - y1) * t;
34246
+ const c2x = cpx + (x2 - cpx) * t;
34247
+ const c2y = cpy + (y2 - cpy) * t;
34248
+ return [c1x + (c2x - c1x) * t, c1y + (c2y - c1y) * t];
34249
+ }
34250
+ static computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size) {
34054
34251
  if (x1 === x2 && y1 === y2) {
34055
- return;
34252
+ return [];
34056
34253
  }
34057
34254
  // ensure endX > startX
34058
34255
  if (x2 < x1) {
@@ -34089,12 +34286,26 @@
34089
34286
  let cp1Y = centerY + offset * normalVectorY;
34090
34287
  let cp2X = centerX + (offset - size) * normalVectorX;
34091
34288
  let cp2Y = centerY + (offset - size) * normalVectorY;
34289
+ return [x1, y1, cp1X, cp1Y, cp2X, cp2Y, x2, y2];
34290
+ }
34291
+ static paintTie(canvas, scale, x1, y1, x2, y2, down = false, offset = 22, size = 4) {
34292
+ const cps = TieGlyph.computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
34092
34293
  canvas.beginPath();
34093
- canvas.moveTo(x1, y1);
34094
- canvas.quadraticCurveTo(cp1X, cp1Y, x2, y2);
34095
- canvas.quadraticCurveTo(cp2X, cp2Y, x1, y1);
34294
+ canvas.moveTo(cps[0], cps[1]);
34295
+ canvas.quadraticCurveTo(cps[2], cps[3], cps[6], cps[7]);
34296
+ canvas.quadraticCurveTo(cps[4], cps[5], cps[0], cps[1]);
34096
34297
  canvas.closePath();
34097
34298
  canvas.fill();
34299
+ // const c = canvas.color;
34300
+ // canvas.color = Color.random(100);
34301
+ // canvas.fillCircle(cps[0], cps[1], 4);
34302
+ // canvas.fillCircle(cps[2], cps[3], 4);
34303
+ // canvas.fillCircle(cps[4], cps[5], 4);
34304
+ // canvas.fillCircle(cps[7], cps[6], 4);
34305
+ // canvas.color = Color.random(100);
34306
+ // const bbox = TieGlyph.calculateActualTieHeight(scale, x1, y1, x2, y2, down, offset, size);
34307
+ // canvas.fillRect(bbox.x, bbox.y, bbox.w, bbox.h);
34308
+ // canvas.color = c;
34098
34309
  }
34099
34310
  static drawBendSlur(canvas, x1, y1, x2, y2, down, scale, slurText) {
34100
34311
  let normalVectorX = y2 - y1;
@@ -36916,7 +37127,7 @@
36916
37127
  while (destination.nextBeat && destination.nextBeat.isLegatoDestination) {
36917
37128
  destination = destination.nextBeat;
36918
37129
  }
36919
- this.ties.push(new ScoreLegatoGlyph(this.beat, destination, false));
37130
+ this.addTie(new ScoreLegatoGlyph(this.beat, destination, false));
36920
37131
  }
36921
37132
  }
36922
37133
  else if (this.beat.isLegatoDestination) {
@@ -36926,7 +37137,7 @@
36926
37137
  while (origin.previousBeat && origin.previousBeat.isLegatoOrigin) {
36927
37138
  origin = origin.previousBeat;
36928
37139
  }
36929
- this.ties.push(new ScoreLegatoGlyph(origin, this.beat, true));
37140
+ this.addTie(new ScoreLegatoGlyph(origin, this.beat, true));
36930
37141
  }
36931
37142
  }
36932
37143
  if (this._bend) {
@@ -36950,32 +37161,32 @@
36950
37161
  n.tieDestination.isVisible) {
36951
37162
  // tslint:disable-next-line: no-unnecessary-type-assertion
36952
37163
  let tie = new ScoreTieGlyph(n, n.tieDestination, false);
36953
- this.ties.push(tie);
37164
+ this.addTie(tie);
36954
37165
  }
36955
37166
  if (n.isTieDestination && !n.tieOrigin.hasBend && !n.beat.hasWhammyBar) {
36956
37167
  let tie = new ScoreTieGlyph(n.tieOrigin, n, true);
36957
- this.ties.push(tie);
37168
+ this.addTie(tie);
36958
37169
  }
36959
37170
  // TODO: depending on the type we have other positioning
36960
37171
  // we should place glyphs in the preNotesGlyph or postNotesGlyph if needed
36961
37172
  if (n.slideInType !== SlideInType.None || n.slideOutType !== SlideOutType.None) {
36962
37173
  let l = new ScoreSlideLineGlyph(n.slideInType, n.slideOutType, n, this);
36963
- this.ties.push(l);
37174
+ this.addTie(l);
36964
37175
  }
36965
37176
  if (n.isSlurOrigin && n.slurDestination && n.slurDestination.isVisible) {
36966
37177
  // tslint:disable-next-line: no-unnecessary-type-assertion
36967
37178
  let tie = new ScoreSlurGlyph(n, n.slurDestination, false);
36968
- this.ties.push(tie);
37179
+ this.addTie(tie);
36969
37180
  }
36970
37181
  if (n.isSlurDestination) {
36971
37182
  let tie = new ScoreSlurGlyph(n.slurOrigin, n, true);
36972
- this.ties.push(tie);
37183
+ this.addTie(tie);
36973
37184
  }
36974
37185
  // start effect slur on first beat
36975
37186
  if (!this._effectSlur && n.isEffectSlurOrigin && n.effectSlurDestination) {
36976
37187
  const effectSlur = new ScoreSlurGlyph(n, n.effectSlurDestination, false);
36977
37188
  this._effectSlur = effectSlur;
36978
- this.ties.push(effectSlur);
37189
+ this.addTie(effectSlur);
36979
37190
  }
36980
37191
  // end effect slur on last beat
36981
37192
  if (!this._effectEndSlur && n.beat.isEffectSlurDestination && n.beat.effectSlurOrigin) {
@@ -36984,14 +37195,14 @@
36984
37195
  let endNote = direction === BeamDirection.Up ? n.beat.minNote : n.beat.maxNote;
36985
37196
  const effectEndSlur = new ScoreSlurGlyph(startNote, endNote, true);
36986
37197
  this._effectEndSlur = effectEndSlur;
36987
- this.ties.push(effectEndSlur);
37198
+ this.addTie(effectEndSlur);
36988
37199
  }
36989
37200
  if (n.hasBend) {
36990
37201
  if (!this._bend) {
36991
37202
  const bend = new ScoreBendGlyph(n.beat);
36992
37203
  this._bend = bend;
36993
37204
  bend.renderer = this.renderer;
36994
- this.ties.push(bend);
37205
+ this.addTie(bend);
36995
37206
  }
36996
37207
  // tslint:disable-next-line: no-unnecessary-type-assertion
36997
37208
  this._bend.addBends(n);
@@ -38133,15 +38344,15 @@
38133
38344
  let renderer = this.renderer;
38134
38345
  if (n.isTieOrigin && renderer.showTiedNotes && n.tieDestination.isVisible) {
38135
38346
  let tie = new TabTieGlyph(n, n.tieDestination, false);
38136
- this.ties.push(tie);
38347
+ this.addTie(tie);
38137
38348
  }
38138
38349
  if (n.isTieDestination && renderer.showTiedNotes) {
38139
38350
  let tie = new TabTieGlyph(n.tieOrigin, n, true);
38140
- this.ties.push(tie);
38351
+ this.addTie(tie);
38141
38352
  }
38142
38353
  if (n.isLeftHandTapped && !n.isHammerPullDestination) {
38143
38354
  let tapSlur = new TabTieGlyph(n, n, false);
38144
- this.ties.push(tapSlur);
38355
+ this.addTie(tapSlur);
38145
38356
  }
38146
38357
  // start effect slur on first beat
38147
38358
  if (n.isEffectSlurOrigin && n.effectSlurDestination) {
@@ -38155,7 +38366,7 @@
38155
38366
  if (!expanded) {
38156
38367
  let effectSlur = new TabSlurGlyph(n, n.effectSlurDestination, false, false);
38157
38368
  this._effectSlurs.push(effectSlur);
38158
- this.ties.push(effectSlur);
38369
+ this.addTie(effectSlur);
38159
38370
  }
38160
38371
  }
38161
38372
  // end effect slur on last beat
@@ -38170,19 +38381,19 @@
38170
38381
  if (!expanded) {
38171
38382
  let effectSlur = new TabSlurGlyph(n.effectSlurOrigin, n, false, true);
38172
38383
  this._effectSlurs.push(effectSlur);
38173
- this.ties.push(effectSlur);
38384
+ this.addTie(effectSlur);
38174
38385
  }
38175
38386
  }
38176
38387
  if (n.slideInType !== SlideInType.None || n.slideOutType !== SlideOutType.None) {
38177
38388
  let l = new TabSlideLineGlyph(n.slideInType, n.slideOutType, n, this);
38178
- this.ties.push(l);
38389
+ this.addTie(l);
38179
38390
  }
38180
38391
  if (n.hasBend) {
38181
38392
  if (!this._bend) {
38182
38393
  const bend = new TabBendGlyph();
38183
38394
  this._bend = bend;
38184
38395
  bend.renderer = this.renderer;
38185
- this.ties.push(bend);
38396
+ this.addTie(bend);
38186
38397
  }
38187
38398
  this._bend.addBends(n);
38188
38399
  }
@@ -41173,8 +41384,8 @@
41173
41384
  // </auto-generated>
41174
41385
  class VersionInfo {
41175
41386
  }
41176
- VersionInfo.version = '1.3.0-alpha.411';
41177
- VersionInfo.date = '2022-10-04T01:07:09.329Z';
41387
+ VersionInfo.version = '1.3.0-alpha.418';
41388
+ VersionInfo.date = '2022-10-11T00:58:31.859Z';
41178
41389
 
41179
41390
  var index$5 = /*#__PURE__*/Object.freeze({
41180
41391
  __proto__: null,