vector-score 1.2.1 → 1.3.0
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/README.md +90 -42
- package/dist/classes/GuitarChord.d.ts +2 -2
- package/dist/classes/MusicStaff.d.ts +1 -2
- package/dist/classes/RhythmStaff.d.ts +1 -3
- package/dist/classes/SVGRenderer.d.ts +18 -8
- package/dist/classes/ScrollingStaff.d.ts +1 -2
- package/dist/vector-score.js +347 -318
- package/dist/vector-score.umd.cjs +1 -1
- package/package.json +1 -1
package/dist/vector-score.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const w = {
|
|
2
2
|
treble: {
|
|
3
3
|
staffType: "treble",
|
|
4
4
|
paddingTop: 13,
|
|
@@ -31,16 +31,16 @@ const R = {
|
|
|
31
31
|
topLineYPos: 0,
|
|
32
32
|
bottomLineYPos: 110
|
|
33
33
|
}
|
|
34
|
-
},
|
|
34
|
+
}, I = {
|
|
35
35
|
w: 4,
|
|
36
36
|
h: 2,
|
|
37
37
|
q: 1,
|
|
38
38
|
e: 0.5,
|
|
39
39
|
s: 0.25
|
|
40
|
-
},
|
|
40
|
+
}, it = 6, at = 5, T = 22, m = 30, u = 10, p = 6, ct = 4, ht = u * 2, L = 51, lt = 12, dt = 4, $ = 1, x = 4, ft = 1, W = p * 2 + x + 8, st = 16, R = 12, k = st, Et = 2, Z = 8, ut = 40, rt = {
|
|
41
41
|
sharp: ["F", "C", "G", "D", "A", "E", "B"],
|
|
42
42
|
flat: ["B", "E", "A", "D", "G", "C", "F"]
|
|
43
|
-
},
|
|
43
|
+
}, V = {
|
|
44
44
|
C: { type: "sharp", count: 0 },
|
|
45
45
|
G: { type: "sharp", count: 1 },
|
|
46
46
|
D: { type: "sharp", count: 2 },
|
|
@@ -54,7 +54,7 @@ const R = {
|
|
|
54
54
|
Ab: { type: "flat", count: 4 },
|
|
55
55
|
Db: { type: "flat", count: 5 },
|
|
56
56
|
Gb: { type: "flat", count: 6 }
|
|
57
|
-
},
|
|
57
|
+
}, X = {
|
|
58
58
|
treble: {
|
|
59
59
|
sharp: [5, 5, 5, 5, 4, 5, 4],
|
|
60
60
|
// F5 C5 G5 D5 A4 E5 B4
|
|
@@ -75,20 +75,21 @@ const R = {
|
|
|
75
75
|
},
|
|
76
76
|
grand: { sharp: [], flat: [] }
|
|
77
77
|
};
|
|
78
|
-
function gt(
|
|
79
|
-
const e =
|
|
80
|
-
if (!e) throw new Error(`Unknown key signature "${
|
|
78
|
+
function gt(l) {
|
|
79
|
+
const e = V[l];
|
|
80
|
+
if (!e) throw new Error(`Unknown key signature "${l}". Valid keys: ${Object.keys(V).join(", ")}`);
|
|
81
81
|
return e;
|
|
82
82
|
}
|
|
83
|
-
function At(
|
|
83
|
+
function At(l, e, t, s) {
|
|
84
84
|
const r = gt(t);
|
|
85
85
|
if (r.count === 0) return 0;
|
|
86
|
-
const n = r.type === "sharp" ? "ACCIDENTAL_SHARP" : "ACCIDENTAL_FLAT", o =
|
|
86
|
+
const n = r.type === "sharp" ? "ACCIDENTAL_SHARP" : "ACCIDENTAL_FLAT", o = l.getLayer("staff");
|
|
87
|
+
if (!o) throw new Error("Staff Init Error: Failed to retrieve staff layer for key signature renderering.");
|
|
87
88
|
return e.getKeySignatureYPositions(r.type, r.count).forEach((a) => {
|
|
88
|
-
a.forEach((
|
|
89
|
-
|
|
89
|
+
a.forEach((h, d) => {
|
|
90
|
+
l.drawGlyph(n, o, { xOffset: s + d * Z, yOffset: h });
|
|
90
91
|
});
|
|
91
|
-
}), r.count *
|
|
92
|
+
}), r.count * Z;
|
|
92
93
|
}
|
|
93
94
|
const pt = {
|
|
94
95
|
CLEF_TREBLE: {
|
|
@@ -186,11 +187,11 @@ const pt = {
|
|
|
186
187
|
xOffset: 0,
|
|
187
188
|
yOffset: 0
|
|
188
189
|
}
|
|
189
|
-
}, It = /^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/, _t = /^[whqeWHQE]$/,
|
|
190
|
-
function
|
|
191
|
-
const e =
|
|
190
|
+
}, It = /^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/, _t = /^[whqeWHQE]$/, U = ["C", "D", "E", "F", "G", "A", "B"];
|
|
191
|
+
function Y(l) {
|
|
192
|
+
const e = l.match(It);
|
|
192
193
|
if (!e || !e.groups)
|
|
193
|
-
throw new Error(`Invalid note string format: ${
|
|
194
|
+
throw new Error(`Invalid note string format: ${l}. Expected format: [A-Ga-g][#|b]?[0-9][w|h|q|e].`);
|
|
194
195
|
let { name: t, accidental: s, octave: r, duration: n } = e.groups;
|
|
195
196
|
t = t.toUpperCase(), n = n.toLowerCase(), n || (n = "w");
|
|
196
197
|
const o = {
|
|
@@ -200,14 +201,14 @@ function U(h) {
|
|
|
200
201
|
};
|
|
201
202
|
return s && (o.accidental = s), o;
|
|
202
203
|
}
|
|
203
|
-
function
|
|
204
|
-
const e =
|
|
205
|
-
if (!e) throw new Error(`Invalid note duration '${
|
|
204
|
+
function v(l) {
|
|
205
|
+
const e = l.match(_t);
|
|
206
|
+
if (!e) throw new Error(`Invalid note duration '${l}'. Use w | h | q | e.`);
|
|
206
207
|
return e[0].toString().toLowerCase();
|
|
207
208
|
}
|
|
208
|
-
function
|
|
209
|
+
function M(l) {
|
|
209
210
|
let e;
|
|
210
|
-
switch (
|
|
211
|
+
switch (l) {
|
|
211
212
|
case "treble":
|
|
212
213
|
e = "CLEF_TREBLE";
|
|
213
214
|
break;
|
|
@@ -218,25 +219,25 @@ function Y(h) {
|
|
|
218
219
|
e = "CLEF_ALTO";
|
|
219
220
|
break;
|
|
220
221
|
}
|
|
221
|
-
if (!e) throw new Error(`Invalid clef type: ${
|
|
222
|
+
if (!e) throw new Error(`Invalid clef type: ${l}. Valid clef types are: treble, bass, alto.`);
|
|
222
223
|
return e;
|
|
223
224
|
}
|
|
224
|
-
function z(
|
|
225
|
-
let e =
|
|
226
|
-
return e +=
|
|
225
|
+
function z(l) {
|
|
226
|
+
let e = U.indexOf(l.name);
|
|
227
|
+
return e += l.octave * 12, e;
|
|
227
228
|
}
|
|
228
|
-
function
|
|
229
|
-
return
|
|
229
|
+
function C(l, e) {
|
|
230
|
+
return U.indexOf(l.name) - U.indexOf(e.name) + (l.octave - e.octave) * 7;
|
|
230
231
|
}
|
|
231
|
-
const
|
|
232
|
-
class
|
|
232
|
+
const F = 48, q = 40 + 30 / 2, j = 20, K = 90;
|
|
233
|
+
class nt {
|
|
233
234
|
params;
|
|
234
235
|
rendererRef;
|
|
235
236
|
width = 0;
|
|
236
237
|
trebleStaffHeight = 0;
|
|
237
238
|
constructor(e, t) {
|
|
238
239
|
this.rendererRef = e;
|
|
239
|
-
const s =
|
|
240
|
+
const s = w[t];
|
|
240
241
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
241
242
|
this.params = s;
|
|
242
243
|
}
|
|
@@ -248,21 +249,21 @@ class ot {
|
|
|
248
249
|
};
|
|
249
250
|
drawStaff = (e) => {
|
|
250
251
|
this.width = e;
|
|
251
|
-
const t = this.rendererRef.
|
|
252
|
+
const t = this.rendererRef.createLayer("staff");
|
|
252
253
|
let s = this.drawStaffLines(0, t), r = this.drawStaffLines(s + 30, t);
|
|
253
254
|
this.rendererRef.drawLine(0, 0, 0, r, t), this.rendererRef.drawLine(this.width, 0, this.width, r, t), this.trebleStaffHeight = s;
|
|
254
255
|
let n = r, o = 1;
|
|
255
|
-
const i =
|
|
256
|
+
const i = M("treble"), a = M("bass");
|
|
256
257
|
this.rendererRef.drawGlyph(i, t), this.rendererRef.drawGlyph(a, t, { yOffset: s + 30 }), n += this.params.paddingBottom + 1, o += this.params.paddingTop, this.rendererRef.addTotalRootSvgHeight(n), this.rendererRef.addTotalRootSvgYOffset(o);
|
|
257
258
|
};
|
|
258
259
|
shouldNoteFlip(e) {
|
|
259
|
-
const t = Math.abs(e -
|
|
260
|
-
return e ===
|
|
260
|
+
const t = Math.abs(e - K), s = Math.abs(e - j);
|
|
261
|
+
return e === q ? !1 : t <= s ? !(e >= K) : e <= j;
|
|
261
262
|
}
|
|
262
263
|
getLedgerLinesX(e, t) {
|
|
263
264
|
const s = [], r = z(e);
|
|
264
265
|
let n = e.duration === "w" ? 17 : 12.5;
|
|
265
|
-
if (r ===
|
|
266
|
+
if (r === F)
|
|
266
267
|
return s.push({ x1: -2, x2: n, yPos: 0 }), s;
|
|
267
268
|
if (t < this.params.topLineYPos) {
|
|
268
269
|
let o = this.params.topLineYPos - 10;
|
|
@@ -284,37 +285,37 @@ class ot {
|
|
|
284
285
|
return s;
|
|
285
286
|
}
|
|
286
287
|
calculateNoteYPos = (e) => {
|
|
287
|
-
let s =
|
|
288
|
+
let s = C(this.params.topLineNote, e) * (10 / 2);
|
|
288
289
|
const r = z(e);
|
|
289
|
-
return r <
|
|
290
|
+
return r < F ? s += 10 : r === F && (s = q), s;
|
|
290
291
|
};
|
|
291
292
|
getKeySignatureYPositions(e, t) {
|
|
292
|
-
const s =
|
|
293
|
-
(a,
|
|
293
|
+
const s = rt[e].slice(0, t), r = X.treble[e], n = X.bass[e], o = s.map(
|
|
294
|
+
(a, h) => C(w.treble.topLineNote, { name: a, octave: r[h] }) * (10 / 2)
|
|
294
295
|
), i = s.map(
|
|
295
|
-
(a,
|
|
296
|
+
(a, h) => C(w.bass.topLineNote, { name: a, octave: n[h] }) * (10 / 2) + this.trebleStaffHeight + 30
|
|
296
297
|
);
|
|
297
298
|
return [o, i];
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
301
|
const Tt = 20;
|
|
301
|
-
class
|
|
302
|
+
class S {
|
|
302
303
|
params;
|
|
303
304
|
rendererRef;
|
|
304
305
|
constructor(e, t) {
|
|
305
306
|
this.rendererRef = e;
|
|
306
|
-
const s =
|
|
307
|
+
const s = w[t];
|
|
307
308
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
308
309
|
this.params = s;
|
|
309
310
|
}
|
|
310
311
|
drawStaff = (e) => {
|
|
311
|
-
const t = this.rendererRef.
|
|
312
|
+
const t = this.rendererRef.createLayer("staff");
|
|
312
313
|
let s = 0;
|
|
313
314
|
for (let i = 0; i < 5; i++)
|
|
314
315
|
this.rendererRef.drawLine(0, s, e, s, t), s += 10;
|
|
315
316
|
this.rendererRef.drawLine(0, 0, 0, s - 10, t), this.rendererRef.drawLine(e, 0, e, s - 10, t);
|
|
316
317
|
let r = s - 10 + 1, n = 1;
|
|
317
|
-
const o =
|
|
318
|
+
const o = M(this.params.staffType);
|
|
318
319
|
this.rendererRef.drawGlyph(o, t), r += this.params.paddingTop + this.params.paddingBottom, n += this.params.paddingTop, this.rendererRef.addTotalRootSvgHeight(r), this.rendererRef.addTotalRootSvgYOffset(n);
|
|
319
320
|
};
|
|
320
321
|
shouldNoteFlip(e) {
|
|
@@ -342,15 +343,15 @@ class m {
|
|
|
342
343
|
}
|
|
343
344
|
return s;
|
|
344
345
|
}
|
|
345
|
-
calculateNoteYPos = (e) =>
|
|
346
|
+
calculateNoteYPos = (e) => C(this.params.topLineNote, e) * (10 / 2);
|
|
346
347
|
getKeySignatureYPositions(e, t) {
|
|
347
|
-
const s =
|
|
348
|
+
const s = rt[e].slice(0, t), r = X[this.params.staffType][e];
|
|
348
349
|
return [s.map(
|
|
349
350
|
(o, i) => this.calculateNoteYPos({ name: o, octave: r[i] })
|
|
350
351
|
)];
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
|
-
class
|
|
354
|
+
class ot {
|
|
354
355
|
svgRendererInstance;
|
|
355
356
|
strategyInstance;
|
|
356
357
|
constructor(e, t) {
|
|
@@ -364,7 +365,7 @@ class it {
|
|
|
364
365
|
for (let n = 0; n < e.length; n++) {
|
|
365
366
|
const o = e[n];
|
|
366
367
|
if (o.noteObj.accidental && r < 3 ? (t += -8, s = Math.min(s, t), r++) : o.noteObj.accidental && r <= 3 ? (t = -8, r = 1) : (t = 0, r = 0), t !== 0) {
|
|
367
|
-
const a = Array.from(o.noteGroup.getElementsByTagName("use")).find((
|
|
368
|
+
const a = Array.from(o.noteGroup.getElementsByTagName("use")).find((h) => h.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
368
369
|
if (!a) continue;
|
|
369
370
|
a.setAttribute("transform", `translate(${t + 8}, 0)`);
|
|
370
371
|
}
|
|
@@ -375,13 +376,13 @@ class it {
|
|
|
375
376
|
let t = e[0], s = 0;
|
|
376
377
|
for (let r = 1; r < e.length; r++) {
|
|
377
378
|
const n = e[r];
|
|
378
|
-
if (-
|
|
379
|
+
if (-C(t.noteObj, n.noteObj) === 1) {
|
|
379
380
|
s = 28 / 2, n.noteGroup.setAttribute("transform", `translate(${s}, ${n.noteYPos})`);
|
|
380
|
-
const a = Array.from(n.noteGroup.getElementsByTagName("use")).find((
|
|
381
|
+
const a = Array.from(n.noteGroup.getElementsByTagName("use")).find((h) => h.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
381
382
|
if (a) {
|
|
382
|
-
const
|
|
383
|
-
let
|
|
384
|
-
|
|
383
|
+
const h = a.getAttribute("transform")?.match(/([-]?\d+)/), d = h && h[0];
|
|
384
|
+
let c = -s;
|
|
385
|
+
d && (c += Number(d)), a.setAttribute("transform", `translate(${c}, 0)`);
|
|
385
386
|
}
|
|
386
387
|
r++, t = e[r];
|
|
387
388
|
continue;
|
|
@@ -392,7 +393,7 @@ class it {
|
|
|
392
393
|
}
|
|
393
394
|
// Handles drawing the glyphs to internal group, applies the xPositioning to note Cursor X
|
|
394
395
|
renderNote(e) {
|
|
395
|
-
const t = this.svgRendererInstance.createGroup("note"), s =
|
|
396
|
+
const t = this.svgRendererInstance.createGroup("note"), s = Y(e), r = this.strategyInstance.calculateNoteYPos({
|
|
396
397
|
name: s.name,
|
|
397
398
|
octave: s.octave
|
|
398
399
|
});
|
|
@@ -460,15 +461,13 @@ class it {
|
|
|
460
461
|
};
|
|
461
462
|
}
|
|
462
463
|
}
|
|
463
|
-
const A = "http://www.w3.org/2000/svg",
|
|
464
|
-
class
|
|
464
|
+
const A = "http://www.w3.org/2000/svg", St = 0.1, G = 2;
|
|
465
|
+
class O {
|
|
465
466
|
rootElementRef;
|
|
466
467
|
svgElementRef;
|
|
467
468
|
// Layers
|
|
468
469
|
parentGroupContainer;
|
|
469
|
-
|
|
470
|
-
musicNotesLayer;
|
|
471
|
-
musicUILayer;
|
|
470
|
+
layers = {};
|
|
472
471
|
// Positioning variables
|
|
473
472
|
width;
|
|
474
473
|
scale;
|
|
@@ -479,19 +478,34 @@ class w {
|
|
|
479
478
|
// from get rootSvgElement().
|
|
480
479
|
// HEIGHT and YOfsset should be set externally, values are calculated internally.
|
|
481
480
|
constructor(e, t) {
|
|
482
|
-
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.
|
|
481
|
+
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.svgElementRef = document.createElementNS(A, "svg"), this.svgElementRef.classList.add("vs-svg-renderer-root"), t.svgAutoFill && (this.svgElementRef.style.maxWidth = "100%", this.svgElementRef.style.height = "auto"), this.makeGlyphDefs(t.useGlyphs), this.parentGroupContainer = this.createGroup("svg-renderer-parent"), this.svgElementRef.appendChild(this.parentGroupContainer);
|
|
483
482
|
}
|
|
484
483
|
// Creates SVG defs for all glyphs in GLYPH_ENTRIES, applies global scale and offsets, appends to root SVG
|
|
485
484
|
makeGlyphDefs(e) {
|
|
486
485
|
const t = document.createElementNS(A, "defs");
|
|
487
486
|
Object.entries(pt).filter(([r]) => e.includes(r)).forEach(([r, n]) => {
|
|
488
487
|
const o = document.createElementNS(A, "path");
|
|
489
|
-
o.setAttribute("id", `glyph-${r}`), o.setAttribute("d", n.path), o.setAttribute("fill", "currentColor"), o.setAttribute("transform", `translate(${n.xOffset}, ${n.yOffset}) scale(${
|
|
488
|
+
o.setAttribute("id", `glyph-${r}`), o.setAttribute("d", n.path), o.setAttribute("fill", "currentColor"), o.setAttribute("transform", `translate(${n.xOffset}, ${n.yOffset}) scale(${St})`), t.appendChild(o);
|
|
490
489
|
}), this.rootSvgElement.appendChild(t);
|
|
491
490
|
}
|
|
492
491
|
addNamespacedClassesToElement(e, t) {
|
|
493
492
|
[e].flat().forEach((r) => t.classList.add(`vs-${r}`));
|
|
494
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Creates a layer that is appended to parent element.
|
|
496
|
+
* layerName arg is the key that is appended to the internal list of layers, which
|
|
497
|
+
* can be used in method getLayer() arg. Best to call on construction.
|
|
498
|
+
*
|
|
499
|
+
* @param {string} layerName
|
|
500
|
+
* @returns {SVGGElement}
|
|
501
|
+
*/
|
|
502
|
+
createLayer(e) {
|
|
503
|
+
const t = document.createElementNS(A, "g");
|
|
504
|
+
return t.classList.add(`vs-${e}-layer`), this.layers[e] = t, this.parentGroupContainer.appendChild(this.layers[e]), t;
|
|
505
|
+
}
|
|
506
|
+
getLayer(e) {
|
|
507
|
+
return this.layers[e] ?? null;
|
|
508
|
+
}
|
|
495
509
|
createGroup(e) {
|
|
496
510
|
const t = document.createElementNS(A, "g");
|
|
497
511
|
return e && t.classList.add(`vs-${e}`), t;
|
|
@@ -502,18 +516,6 @@ class w {
|
|
|
502
516
|
s.appendChild(r);
|
|
503
517
|
}) : s.appendChild(e), t.appendChild(s);
|
|
504
518
|
}
|
|
505
|
-
getLayerByName(e) {
|
|
506
|
-
switch (e) {
|
|
507
|
-
case "staff":
|
|
508
|
-
return this.musicStaffLayer;
|
|
509
|
-
case "notes":
|
|
510
|
-
return this.musicNotesLayer;
|
|
511
|
-
case "ui":
|
|
512
|
-
return this.musicUILayer;
|
|
513
|
-
default:
|
|
514
|
-
throw new Error(`Layer with name '${e}' does not exist.`);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
519
|
addTotalRootSvgHeight(e) {
|
|
518
520
|
this.totalHeight += e;
|
|
519
521
|
}
|
|
@@ -524,10 +526,10 @@ class w {
|
|
|
524
526
|
this.totalYOffset += e;
|
|
525
527
|
}
|
|
526
528
|
applySizingToRootSvg() {
|
|
527
|
-
this.parentGroupContainer.setAttribute("transform", `translate(
|
|
528
|
-
let e = this.width * this.scale;
|
|
529
|
+
this.parentGroupContainer.setAttribute("transform", `translate(${G / 2}, ${this.totalYOffset})`);
|
|
530
|
+
let e = Math.round(this.width * this.scale);
|
|
529
531
|
const t = (this.totalHeight + this.totalYOffset) * this.scale;
|
|
530
|
-
e +=
|
|
532
|
+
e += G, this.svgElementRef.setAttribute("width", e.toString()), this.svgElementRef.setAttribute("height", t.toString()), this.svgElementRef.setAttribute("viewBox", `0 0 ${this.width + G} ${this.totalHeight + this.totalYOffset}`);
|
|
531
533
|
}
|
|
532
534
|
get rootSvgElement() {
|
|
533
535
|
return this.svgElementRef;
|
|
@@ -536,9 +538,9 @@ class w {
|
|
|
536
538
|
return this.parentGroupContainer;
|
|
537
539
|
}
|
|
538
540
|
// Drawing Methods
|
|
539
|
-
drawLine(e, t, s, r, n) {
|
|
540
|
-
const o = document.createElementNS(A, "line");
|
|
541
|
-
|
|
541
|
+
drawLine(e, t, s, r, n, o) {
|
|
542
|
+
const i = o?.strokeWidth ?? 1, a = document.createElementNS(A, "line");
|
|
543
|
+
a.setAttribute("x1", e.toString()), a.setAttribute("y1", t.toString()), a.setAttribute("x2", s.toString()), a.setAttribute("y2", r.toString()), a.setAttribute("stroke", "currentColor"), a.setAttribute("stroke-width", i.toString()), o?.classes && this.addNamespacedClassesToElement(o.classes, n), n.appendChild(a);
|
|
542
544
|
}
|
|
543
545
|
drawRect(e, t, s, r) {
|
|
544
546
|
const n = document.createElementNS(A, "rect");
|
|
@@ -559,13 +561,13 @@ class w {
|
|
|
559
561
|
}
|
|
560
562
|
drawText(e, t, s, r, n) {
|
|
561
563
|
const o = document.createElementNS(A, "text");
|
|
562
|
-
return o.setAttribute("x", t.toString()), o.setAttribute("y", s.toString()), o.setAttribute("text-anchor", n?.anchor ?? "middle"), o.setAttribute("fill", n?.fill ?? "currentColor"), n?.fontSize && o.setAttribute("font-size", n.fontSize + "px"), n?.fontWeight && o.setAttribute("font-weight", n.fontWeight), n?.classes && this.addNamespacedClassesToElement(n.classes, o), o.textContent = e, r.appendChild(o), o;
|
|
564
|
+
return o.setAttribute("x", t.toString()), o.setAttribute("y", s.toString()), o.setAttribute("text-anchor", n?.anchor ?? "middle"), o.setAttribute("fill", n?.fill ?? "currentColor"), n?.fontSize && o.setAttribute("font-size", n.fontSize + "px"), n?.fontWeight && o.setAttribute("font-weight", n.fontWeight), n?.baseline && o.setAttribute("dominant-baseline", n.baseline), n?.classes && this.addNamespacedClassesToElement(n.classes, o), o.textContent = e, r.appendChild(o), o;
|
|
563
565
|
}
|
|
564
566
|
destroy() {
|
|
565
567
|
this.rootElementRef && this.svgElementRef && this.rootElementRef.contains(this.svgElementRef) && this.rootElementRef.removeChild(this.svgElementRef);
|
|
566
568
|
}
|
|
567
569
|
}
|
|
568
|
-
const
|
|
570
|
+
const mt = [
|
|
569
571
|
"CLEF_TREBLE",
|
|
570
572
|
"CLEF_BASS",
|
|
571
573
|
"CLEF_ALTO",
|
|
@@ -602,47 +604,47 @@ class bt {
|
|
|
602
604
|
staffType: "treble",
|
|
603
605
|
spaceAbove: 0,
|
|
604
606
|
spaceBelow: 0,
|
|
605
|
-
|
|
606
|
-
staffBackgroundColor: "transparent",
|
|
607
|
+
svgAutoFill: !0,
|
|
607
608
|
...t
|
|
608
|
-
}, this.svgRendererInstance = new
|
|
609
|
+
}, this.svgRendererInstance = new O(e, {
|
|
609
610
|
width: this.options.width,
|
|
610
611
|
height: 100,
|
|
611
612
|
scale: this.options.scale,
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
useGlyphs: Ct
|
|
613
|
+
useGlyphs: mt,
|
|
614
|
+
svgAutoFill: this.options.svgAutoFill
|
|
615
615
|
});
|
|
616
616
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
617
617
|
switch (this.options.staffType) {
|
|
618
618
|
case "grand":
|
|
619
|
-
this.strategyInstance = new
|
|
619
|
+
this.strategyInstance = new nt(this.svgRendererInstance, "grand");
|
|
620
620
|
break;
|
|
621
621
|
case "bass":
|
|
622
|
-
this.strategyInstance = new
|
|
622
|
+
this.strategyInstance = new S(this.svgRendererInstance, "bass");
|
|
623
623
|
break;
|
|
624
624
|
case "treble":
|
|
625
|
-
this.strategyInstance = new
|
|
625
|
+
this.strategyInstance = new S(this.svgRendererInstance, "treble");
|
|
626
626
|
break;
|
|
627
627
|
case "alto":
|
|
628
|
-
this.strategyInstance = new
|
|
628
|
+
this.strategyInstance = new S(this.svgRendererInstance, "alto");
|
|
629
629
|
break;
|
|
630
630
|
default:
|
|
631
631
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
632
632
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
633
|
+
this.strategyInstance.drawStaff(this.options.width);
|
|
634
|
+
const r = this.svgRendererInstance.createLayer("notes");
|
|
635
|
+
if (this.noteRendererInstance = new ot(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
636
|
+
const o = this.options.spaceAbove * 10;
|
|
637
|
+
this.svgRendererInstance.addTotalRootSvgYOffset(o);
|
|
636
638
|
}
|
|
637
639
|
if (this.options.spaceBelow) {
|
|
638
|
-
let
|
|
639
|
-
this.options.staffType === "grand" && (
|
|
640
|
+
let o = this.options.spaceBelow * 10;
|
|
641
|
+
this.options.staffType === "grand" && (o -= 10 / 2), this.svgRendererInstance.addTotalRootSvgHeight(o);
|
|
640
642
|
}
|
|
641
|
-
let
|
|
642
|
-
this.options.keySignature && (
|
|
643
|
+
let n = 0;
|
|
644
|
+
this.options.keySignature && (n = this.createKeySignature(this.options.keySignature)), this.noteStartX = 38 + this.options.noteStartX + n, r.setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
643
645
|
}
|
|
644
646
|
createKeySignature(e) {
|
|
645
|
-
return At(this.svgRendererInstance, this.strategyInstance, e,
|
|
647
|
+
return At(this.svgRendererInstance, this.strategyInstance, e, ut);
|
|
646
648
|
}
|
|
647
649
|
/**
|
|
648
650
|
* Draws a note on the staff.
|
|
@@ -665,7 +667,9 @@ class bt {
|
|
|
665
667
|
* drawNote("D4w");
|
|
666
668
|
*/
|
|
667
669
|
drawNote(e) {
|
|
668
|
-
const t = Array.isArray(e) ? e : [e], s = this.svgRendererInstance.
|
|
670
|
+
const t = Array.isArray(e) ? e : [e], s = this.svgRendererInstance.getLayer("notes");
|
|
671
|
+
if (!s) throw new Error("DrawNote Error: Failed to retrieve notesLayer to append notes.");
|
|
672
|
+
const r = [];
|
|
669
673
|
for (const n of t) {
|
|
670
674
|
let o;
|
|
671
675
|
try {
|
|
@@ -700,10 +704,12 @@ class bt {
|
|
|
700
704
|
*/
|
|
701
705
|
drawChord(e) {
|
|
702
706
|
if (e.length < 2) throw new Error("Provide more than one note for a chord.");
|
|
703
|
-
const t = this.svgRendererInstance.
|
|
707
|
+
const t = this.svgRendererInstance.getLayer("notes");
|
|
708
|
+
if (!t) throw new Error("DrawChord Error: Failed to retrieve notesLayer to append chord.");
|
|
709
|
+
const s = this.noteRendererInstance.renderChord(e);
|
|
704
710
|
s.noteGroup.setAttribute("transform", `translate(${this.noteCursorX + s.accidentalOffset}, 0)`), this.noteEntries.push({
|
|
705
711
|
gElement: s.noteGroup,
|
|
706
|
-
note:
|
|
712
|
+
note: Y(e[0]),
|
|
707
713
|
xPos: this.noteCursorX + s.accidentalOffset,
|
|
708
714
|
yPos: 0,
|
|
709
715
|
accidentalXOffset: s.accidentalOffset
|
|
@@ -718,10 +724,10 @@ class bt {
|
|
|
718
724
|
if (t <= 0 || e <= 0) return;
|
|
719
725
|
const s = Math.round(e / t);
|
|
720
726
|
this.noteEntries.map((n, o) => {
|
|
721
|
-
const i = (o + 0.5) * s, a = n.gElement.getBBox(),
|
|
727
|
+
const i = (o + 0.5) * s, a = n.gElement.getBBox(), h = i - a.width / 2 - a.x, d = Math.round(h * 10) / 10;
|
|
722
728
|
return {
|
|
723
729
|
entry: n,
|
|
724
|
-
newX:
|
|
730
|
+
newX: d,
|
|
725
731
|
isChord: n.gElement.classList.contains("chord")
|
|
726
732
|
};
|
|
727
733
|
}).forEach((n) => {
|
|
@@ -734,7 +740,7 @@ class bt {
|
|
|
734
740
|
* @returns void
|
|
735
741
|
*/
|
|
736
742
|
clearAllNotes() {
|
|
737
|
-
this.noteCursorX = 0, this.svgRendererInstance.
|
|
743
|
+
this.noteCursorX = 0, this.svgRendererInstance.getLayer("notes")?.replaceChildren(), this.noteEntries = [];
|
|
738
744
|
}
|
|
739
745
|
/**
|
|
740
746
|
* Changes the note by index to the specified note.
|
|
@@ -755,7 +761,8 @@ class bt {
|
|
|
755
761
|
changeNoteByIndex(e, t) {
|
|
756
762
|
if (t >= this.noteEntries.length) throw new Error("Note index was out of bounds.");
|
|
757
763
|
const s = this.noteEntries[t], r = this.noteRendererInstance.renderNote(e), o = s.xPos - s.accidentalXOffset + r.accidentalOffset;
|
|
758
|
-
r.noteGroup.setAttribute("transform", `translate(${o}, ${r.noteYPos})`), this.svgRendererInstance.
|
|
764
|
+
if (r.noteGroup.setAttribute("transform", `translate(${o}, ${r.noteYPos})`), !this.svgRendererInstance.getLayer("notes")) throw new Error("ChangeNoteByIndex Error: Failed to retrieve notesLayer to append notes.");
|
|
765
|
+
this.noteEntries[t] = {
|
|
759
766
|
gElement: r.noteGroup,
|
|
760
767
|
note: r.noteObj,
|
|
761
768
|
xPos: o,
|
|
@@ -783,9 +790,12 @@ class bt {
|
|
|
783
790
|
if (t >= this.noteEntries.length) throw new Error("Chord index was out of bounds.");
|
|
784
791
|
if (e.length < 2) throw new Error("Notes provided need to be more than one to be considered a chord.");
|
|
785
792
|
const s = this.noteEntries[t], r = this.noteRendererInstance.renderChord(e), o = s.xPos - s.accidentalXOffset + r.accidentalOffset;
|
|
786
|
-
r.noteGroup.setAttribute("transform", `translate(${o}, 0)`)
|
|
793
|
+
r.noteGroup.setAttribute("transform", `translate(${o}, 0)`);
|
|
794
|
+
const i = this.svgRendererInstance.getLayer("notes");
|
|
795
|
+
if (!i) throw new Error("DrawNote Error: Failed to retrieve notesLayer to append notes.");
|
|
796
|
+
i.replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
787
797
|
gElement: r.noteGroup,
|
|
788
|
-
note:
|
|
798
|
+
note: Y(e[0]),
|
|
789
799
|
xPos: o,
|
|
790
800
|
yPos: 0,
|
|
791
801
|
accidentalXOffset: r.accidentalOffset
|
|
@@ -821,7 +831,7 @@ class bt {
|
|
|
821
831
|
this.noteEntries = [], this.svgRendererInstance.destroy();
|
|
822
832
|
}
|
|
823
833
|
}
|
|
824
|
-
const
|
|
834
|
+
const _ = 30, Q = 19, D = 12, Ct = 4, Nt = 6, J = 1, H = 38, Lt = [
|
|
825
835
|
"TIME_4",
|
|
826
836
|
"TIME_3",
|
|
827
837
|
"NOTE_HEAD_WHOLE",
|
|
@@ -833,7 +843,7 @@ const I = 30, J = 19, F = 12, St = 4, Nt = 6, tt = 1, D = 38, Lt = [
|
|
|
833
843
|
"REST_QUARTER",
|
|
834
844
|
"REST_EIGHTH"
|
|
835
845
|
];
|
|
836
|
-
class
|
|
846
|
+
class vt {
|
|
837
847
|
rendererInstance;
|
|
838
848
|
options;
|
|
839
849
|
barSpacing;
|
|
@@ -844,7 +854,7 @@ class Gt {
|
|
|
844
854
|
currentBeatCount = 0;
|
|
845
855
|
currentBeatUICount = 0;
|
|
846
856
|
currentBeatUIElement = null;
|
|
847
|
-
currentBeatUIXPos =
|
|
857
|
+
currentBeatUIXPos = H;
|
|
848
858
|
/**
|
|
849
859
|
* Creates an instance of a RhythmStaff, A single staff that will automatically apply positioning of elements based on the duration of a note.
|
|
850
860
|
*
|
|
@@ -860,67 +870,66 @@ class Gt {
|
|
|
860
870
|
barsCount: 2,
|
|
861
871
|
spaceAbove: 0,
|
|
862
872
|
spaceBelow: 0,
|
|
863
|
-
|
|
864
|
-
staffBackgroundColor: "white",
|
|
865
|
-
currentBeatUIColor: "#24ff7450",
|
|
873
|
+
svgAutoFill: !0,
|
|
866
874
|
...t
|
|
867
|
-
}, this.rendererInstance = new
|
|
875
|
+
}, this.rendererInstance = new O(e, {
|
|
868
876
|
width: this.options.width,
|
|
869
877
|
height: 100,
|
|
870
878
|
scale: this.options.scale,
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
useGlyphs: Lt
|
|
879
|
+
useGlyphs: Lt,
|
|
880
|
+
svgAutoFill: this.options.svgAutoFill
|
|
874
881
|
});
|
|
875
|
-
const s = this.rendererInstance.rootSvgElement;
|
|
876
|
-
|
|
882
|
+
const s = this.rendererInstance.rootSvgElement, r = this.rendererInstance.createLayer("staff"), n = this.rendererInstance.createLayer("notes");
|
|
883
|
+
this.rendererInstance.createLayer("ui");
|
|
884
|
+
let o = "TIME_4";
|
|
877
885
|
switch (this.options.topNumber) {
|
|
878
886
|
case 3:
|
|
879
|
-
|
|
887
|
+
o = "TIME_3";
|
|
880
888
|
break;
|
|
881
889
|
case 4:
|
|
882
|
-
|
|
890
|
+
o = "TIME_4";
|
|
883
891
|
break;
|
|
884
892
|
default:
|
|
885
893
|
throw new Error(`Time signature ${this.options.topNumber} not supported. Please use either 3 or 4.`);
|
|
886
894
|
}
|
|
887
895
|
if (this.options.barsCount < 1 || this.options.barsCount > 3) throw new Error(`Bars count ${this.options.barsCount} not supported. Please use 1 - 3`);
|
|
888
896
|
if (this.options.spaceAbove) {
|
|
889
|
-
const
|
|
890
|
-
this.rendererInstance.addTotalRootSvgYOffset(
|
|
897
|
+
const E = this.options.spaceAbove * 10;
|
|
898
|
+
this.rendererInstance.addTotalRootSvgYOffset(E);
|
|
891
899
|
}
|
|
892
900
|
if (this.options.spaceBelow) {
|
|
893
|
-
let
|
|
894
|
-
this.rendererInstance.addTotalRootSvgHeight(
|
|
901
|
+
let E = this.options.spaceBelow * 10;
|
|
902
|
+
this.rendererInstance.addTotalRootSvgHeight(E);
|
|
895
903
|
}
|
|
896
|
-
|
|
897
|
-
this.rendererInstance.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
this.rendererInstance.getLayerByName("notes").setAttribute("transform", `translate(38, ${I})`), this.rendererInstance.applySizingToRootSvg(), this.rendererInstance.commitElementsToDOM(s);
|
|
904
|
+
this.rendererInstance.addTotalRootSvgHeight(_ * 2);
|
|
905
|
+
const i = this.rendererInstance.createGroup("time-signature");
|
|
906
|
+
r.appendChild(i);
|
|
907
|
+
const a = _ - Q;
|
|
908
|
+
this.rendererInstance.drawGlyph(o, i), this.rendererInstance.drawGlyph("TIME_4", i, { yOffset: Q }), i.setAttribute("transform", `translate(0, ${a})`);
|
|
909
|
+
let h = this.options.width - 38;
|
|
910
|
+
this.options.barsCount > 1 && (h -= (this.options.barsCount - 1) * D), h -= J, this.rendererInstance.drawLine(0, _, this.options.width - J, _, r), this.barSpacing = h / this.options.barsCount, this.quarterNoteSpacing = Math.round(this.barSpacing / this.options.topNumber), this.maxBeatCount = this.options.barsCount * this.options.topNumber;
|
|
911
|
+
let d = this.barSpacing + 38;
|
|
912
|
+
const c = _ / 2, f = _ + c;
|
|
913
|
+
for (let E = 0; E < this.options.barsCount - 1; E++)
|
|
914
|
+
this.rendererInstance.drawLine(d, c, d, f, r), d += this.barSpacing;
|
|
915
|
+
n.setAttribute("transform", `translate(38, ${_})`), this.rendererInstance.applySizingToRootSvg(), this.rendererInstance.commitElementsToDOM(s);
|
|
909
916
|
}
|
|
910
917
|
createBeatUIElement() {
|
|
911
|
-
const e = this.rendererInstance.
|
|
918
|
+
const e = this.rendererInstance.getLayer("ui");
|
|
919
|
+
if (!e) throw new Error("BeatUI Error: Failed to retrieve ui layer");
|
|
912
920
|
this.currentBeatUIElement = this.rendererInstance.drawRect(
|
|
913
921
|
this.quarterNoteSpacing / 2,
|
|
914
|
-
|
|
922
|
+
_ * 2,
|
|
915
923
|
e,
|
|
916
924
|
{
|
|
917
|
-
x:
|
|
918
|
-
fill:
|
|
925
|
+
x: H,
|
|
926
|
+
fill: "rgba(0,255,40,0.4)",
|
|
927
|
+
classes: "rhythm-current-beat"
|
|
919
928
|
}
|
|
920
929
|
);
|
|
921
930
|
}
|
|
922
931
|
handleNewBar() {
|
|
923
|
-
this.noteCursorX +=
|
|
932
|
+
this.noteCursorX += D;
|
|
924
933
|
}
|
|
925
934
|
// Translates group, returns cursor increment amount
|
|
926
935
|
translateGroupByDuration(e, t) {
|
|
@@ -980,19 +989,18 @@ class Gt {
|
|
|
980
989
|
for (; s > 0; ) {
|
|
981
990
|
const r = this.rendererInstance.createGroup("rest");
|
|
982
991
|
let n = 0;
|
|
983
|
-
s -
|
|
992
|
+
s - I.h >= 0 ? (this.rendererInstance.drawGlyph("REST_HALF", r), n = I.h) : s - I.q >= 0 ? (this.rendererInstance.drawGlyph("REST_QUARTER", r), n = I.q) : (this.rendererInstance.drawGlyph("REST_EIGHTH", r), n = I.e), s -= n, this.currentBeatCount += n, r.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += n * this.quarterNoteSpacing, t.push(r);
|
|
984
993
|
}
|
|
985
994
|
return t;
|
|
986
995
|
}
|
|
987
996
|
renderBeamRect(e, t, s, r) {
|
|
988
997
|
this.rendererInstance.drawRect(
|
|
989
998
|
e - t,
|
|
990
|
-
|
|
999
|
+
Ct,
|
|
991
1000
|
s,
|
|
992
1001
|
{
|
|
993
1002
|
x: 10,
|
|
994
|
-
y: -28 + (r ?? 0)
|
|
995
|
-
fill: this.options.staffColor
|
|
1003
|
+
y: -28 + (r ?? 0)
|
|
996
1004
|
}
|
|
997
1005
|
);
|
|
998
1006
|
}
|
|
@@ -1015,24 +1023,26 @@ class Gt {
|
|
|
1015
1023
|
* drawNote("w");
|
|
1016
1024
|
*/
|
|
1017
1025
|
drawNote(e) {
|
|
1018
|
-
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.
|
|
1026
|
+
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayer("notes");
|
|
1027
|
+
if (!s) throw new Error("DrawNote Error: Failed to retrieve notes layer");
|
|
1028
|
+
const r = [];
|
|
1019
1029
|
for (const n of t) {
|
|
1020
1030
|
let o = "w";
|
|
1021
1031
|
try {
|
|
1022
|
-
o =
|
|
1023
|
-
} catch (
|
|
1024
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1032
|
+
o = v(n);
|
|
1033
|
+
} catch (c) {
|
|
1034
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), c;
|
|
1025
1035
|
}
|
|
1026
|
-
const i =
|
|
1036
|
+
const i = I[o];
|
|
1027
1037
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1028
1038
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1029
1039
|
this.checkAndCreateNewBar();
|
|
1030
1040
|
const a = this.checkAndFillBarWithRests(i);
|
|
1031
|
-
a && a.forEach((
|
|
1032
|
-
r.push(
|
|
1041
|
+
a && a.forEach((c) => {
|
|
1042
|
+
r.push(c), this.noteEntries.push(c);
|
|
1033
1043
|
});
|
|
1034
|
-
const
|
|
1035
|
-
this.noteCursorX +=
|
|
1044
|
+
const h = this.rendererInstance.createGroup("note"), d = this.translateGroupByDuration(i, h);
|
|
1045
|
+
this.noteCursorX += d, this.currentBeatCount += i, this.renderNote(o, h), r.push(h), this.noteEntries.push(h);
|
|
1036
1046
|
}
|
|
1037
1047
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1038
1048
|
}
|
|
@@ -1055,22 +1065,24 @@ class Gt {
|
|
|
1055
1065
|
* drawRest("w");
|
|
1056
1066
|
*/
|
|
1057
1067
|
drawRest(e) {
|
|
1058
|
-
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.
|
|
1068
|
+
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayer("notes");
|
|
1069
|
+
if (!s) throw new Error("DrawRest Error: Failed to retrieve notes layer");
|
|
1070
|
+
const r = [];
|
|
1059
1071
|
for (const n of t) {
|
|
1060
1072
|
let o = "w";
|
|
1061
1073
|
try {
|
|
1062
|
-
o =
|
|
1063
|
-
} catch (
|
|
1064
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1074
|
+
o = v(n);
|
|
1075
|
+
} catch (c) {
|
|
1076
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), c;
|
|
1065
1077
|
}
|
|
1066
|
-
const i = this.rendererInstance.createGroup("rest"), a =
|
|
1078
|
+
const i = this.rendererInstance.createGroup("rest"), a = I[o], h = a * this.quarterNoteSpacing;
|
|
1067
1079
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1068
1080
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1069
1081
|
this.checkAndCreateNewBar();
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
r.push(
|
|
1073
|
-
}), this.renderRest(o, i), i.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX +=
|
|
1082
|
+
const d = this.checkAndFillBarWithRests(a);
|
|
1083
|
+
d && d.forEach((c) => {
|
|
1084
|
+
r.push(c), this.noteEntries.push(c);
|
|
1085
|
+
}), this.renderRest(o, i), i.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += h, this.currentBeatCount += a, r.push(i), this.noteEntries.push(i);
|
|
1074
1086
|
}
|
|
1075
1087
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1076
1088
|
}
|
|
@@ -1097,13 +1109,15 @@ class Gt {
|
|
|
1097
1109
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1098
1110
|
throw new Error("Max beat count reached. Can't add additional beamed note.");
|
|
1099
1111
|
let s = "s";
|
|
1100
|
-
e === "s" ? s = "s" : s =
|
|
1101
|
-
const r = this.rendererInstance.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1112
|
+
e === "s" ? s = "s" : s = v(e), this.checkAndCreateNewBar();
|
|
1113
|
+
const r = this.rendererInstance.getLayer("notes");
|
|
1114
|
+
if (!r) throw new Error("drawBeamedNotes Error: Failed to retrieve notes layer");
|
|
1115
|
+
const n = I[s], o = n * this.quarterNoteSpacing, i = this.options.topNumber - this.currentBeatCount % this.options.topNumber, a = Math.min(t, i / n), h = this.rendererInstance.createGroup("beamed-note");
|
|
1116
|
+
h.setAttribute("transform", `translate(${this.noteCursorX}, 0)`);
|
|
1117
|
+
let d = 0;
|
|
1118
|
+
for (let c = 0; c < a; c++)
|
|
1119
|
+
this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER", h, { xOffset: d }), this.drawStem(h, d), d += o, this.currentBeatCount += n;
|
|
1120
|
+
this.renderBeamRect(d, o, h), e === "s" && this.renderBeamRect(d, o, h, Nt), this.noteCursorX += d, this.noteEntries.push(h), this.rendererInstance.commitElementsToDOM(h, r);
|
|
1107
1121
|
}
|
|
1108
1122
|
/**
|
|
1109
1123
|
* Will increment the UI showing the current beat in quarters. Once exceeded, must be reset with `resetCurrentBeatUI()`
|
|
@@ -1114,21 +1128,21 @@ class Gt {
|
|
|
1114
1128
|
this.currentBeatUIElement.setAttribute("display", "none");
|
|
1115
1129
|
return;
|
|
1116
1130
|
}
|
|
1117
|
-
this.currentBeatUIElement?.getAttribute("display") === "none" && this.currentBeatUIElement.removeAttribute("display"), this.currentBeatUICount++, this.currentBeatUICount > this.options.topNumber && this.currentBeatUICount % this.options.topNumber === 1 && (this.currentBeatUIXPos +=
|
|
1131
|
+
this.currentBeatUIElement?.getAttribute("display") === "none" && this.currentBeatUIElement.removeAttribute("display"), this.currentBeatUICount++, this.currentBeatUICount > this.options.topNumber && this.currentBeatUICount % this.options.topNumber === 1 && (this.currentBeatUIXPos += D), this.currentBeatUICount > 1 && (this.currentBeatUIXPos += this.quarterNoteSpacing), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString());
|
|
1118
1132
|
}
|
|
1119
1133
|
/**
|
|
1120
1134
|
* Resets the ui showing the current beat value.
|
|
1121
1135
|
* @returns void
|
|
1122
1136
|
*/
|
|
1123
1137
|
resetCurrentBeatUI() {
|
|
1124
|
-
this.currentBeatUICount = 0, this.currentBeatUIXPos =
|
|
1138
|
+
this.currentBeatUICount = 0, this.currentBeatUIXPos = H, this.currentBeatUIElement && (this.currentBeatUIElement.setAttribute("display", "none"), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString()));
|
|
1125
1139
|
}
|
|
1126
1140
|
/**
|
|
1127
1141
|
* Clears staff of notes and resets internal positioning.
|
|
1128
1142
|
* @returns void
|
|
1129
1143
|
*/
|
|
1130
1144
|
clearAllNotes() {
|
|
1131
|
-
this.noteCursorX = 0, this.currentBeatCount = 0, this.rendererInstance.
|
|
1145
|
+
this.noteCursorX = 0, this.currentBeatCount = 0, this.rendererInstance.getLayer("notes")?.replaceChildren(), this.noteEntries = [];
|
|
1132
1146
|
}
|
|
1133
1147
|
/**
|
|
1134
1148
|
* Removes the root svg element and cleans up arrays.
|
|
@@ -1152,8 +1166,8 @@ const Rt = [
|
|
|
1152
1166
|
"ACCIDENTAL_NATURAL",
|
|
1153
1167
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
1154
1168
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
1155
|
-
], y = 60,
|
|
1156
|
-
class
|
|
1169
|
+
], y = 60, wt = y;
|
|
1170
|
+
class Ft {
|
|
1157
1171
|
svgRendererInstance;
|
|
1158
1172
|
strategyInstance;
|
|
1159
1173
|
noteRendererInstance;
|
|
@@ -1177,46 +1191,45 @@ class vt {
|
|
|
1177
1191
|
staffType: "treble",
|
|
1178
1192
|
spaceAbove: 0,
|
|
1179
1193
|
spaceBelow: 0,
|
|
1180
|
-
|
|
1181
|
-
staffBackgroundColor: "transparent",
|
|
1194
|
+
svgAutoFill: !0,
|
|
1182
1195
|
...t
|
|
1183
|
-
}, this.svgRendererInstance = new
|
|
1196
|
+
}, this.svgRendererInstance = new O(e, {
|
|
1184
1197
|
width: this.options.width,
|
|
1185
1198
|
height: 100,
|
|
1186
1199
|
scale: this.options.scale,
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
useGlyphs: Rt
|
|
1200
|
+
useGlyphs: Rt,
|
|
1201
|
+
svgAutoFill: this.options.svgAutoFill
|
|
1190
1202
|
});
|
|
1191
1203
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1192
1204
|
switch (this.options.staffType) {
|
|
1193
1205
|
case "grand":
|
|
1194
|
-
this.strategyInstance = new
|
|
1206
|
+
this.strategyInstance = new nt(this.svgRendererInstance, "grand");
|
|
1195
1207
|
break;
|
|
1196
1208
|
case "bass":
|
|
1197
|
-
this.strategyInstance = new
|
|
1209
|
+
this.strategyInstance = new S(this.svgRendererInstance, "bass");
|
|
1198
1210
|
break;
|
|
1199
1211
|
case "treble":
|
|
1200
|
-
this.strategyInstance = new
|
|
1212
|
+
this.strategyInstance = new S(this.svgRendererInstance, "treble");
|
|
1201
1213
|
break;
|
|
1202
1214
|
case "alto":
|
|
1203
|
-
this.strategyInstance = new
|
|
1215
|
+
this.strategyInstance = new S(this.svgRendererInstance, "alto");
|
|
1204
1216
|
break;
|
|
1205
1217
|
default:
|
|
1206
1218
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
1207
1219
|
}
|
|
1208
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
1209
|
-
const
|
|
1210
|
-
this.svgRendererInstance.addTotalRootSvgYOffset(
|
|
1220
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new ot(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
1221
|
+
const n = this.options.spaceAbove * 10;
|
|
1222
|
+
this.svgRendererInstance.addTotalRootSvgYOffset(n);
|
|
1211
1223
|
}
|
|
1212
1224
|
if (this.options.spaceBelow) {
|
|
1213
|
-
let
|
|
1214
|
-
this.options.staffType === "grand" && (
|
|
1225
|
+
let n = this.options.spaceBelow * 10;
|
|
1226
|
+
this.options.staffType === "grand" && (n -= 10 / 2), this.svgRendererInstance.addTotalRootSvgHeight(n);
|
|
1215
1227
|
}
|
|
1216
|
-
|
|
1228
|
+
const r = this.svgRendererInstance.createLayer("notes");
|
|
1229
|
+
this.notesLayer = r, r.classList.add("vs-scrolling-notes-layer"), this.noteStartX = 38 + this.options.noteStartX, r.setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
1217
1230
|
}
|
|
1218
1231
|
renderFirstNoteGroups() {
|
|
1219
|
-
const e = this.options.width - this.options.noteStartX +
|
|
1232
|
+
const e = this.options.width - this.options.noteStartX + wt;
|
|
1220
1233
|
for (; this.noteBuffer.length > 0 && this.noteCursorX < e; )
|
|
1221
1234
|
this.renderNextNote(), this.noteCursorX += y;
|
|
1222
1235
|
this.activeEntries.length > 1 && (this.noteCursorX -= y);
|
|
@@ -1298,31 +1311,31 @@ class vt {
|
|
|
1298
1311
|
this.svgRendererInstance.destroy(), this.activeEntries = [], this.noteBuffer = [];
|
|
1299
1312
|
}
|
|
1300
1313
|
}
|
|
1301
|
-
const
|
|
1302
|
-
function
|
|
1314
|
+
const yt = /^[xX\da-zA-Z]+$/, Ot = /^[\d]+$/;
|
|
1315
|
+
function tt(l, e) {
|
|
1303
1316
|
const t = [];
|
|
1304
|
-
for (let s = 0; s <
|
|
1317
|
+
for (let s = 0; s < l.length; s++)
|
|
1305
1318
|
t.push({
|
|
1306
|
-
fret:
|
|
1319
|
+
fret: l[s],
|
|
1307
1320
|
finger: e[s]
|
|
1308
1321
|
});
|
|
1309
1322
|
return t;
|
|
1310
1323
|
}
|
|
1311
|
-
function
|
|
1312
|
-
const t =
|
|
1324
|
+
function et(l, e) {
|
|
1325
|
+
const t = l.filter((n) => n.toLowerCase() !== "x" && n !== "0").map((n) => parseInt(n, 36));
|
|
1313
1326
|
if (t.length === 0) return 1;
|
|
1314
1327
|
const s = Math.min(...t);
|
|
1315
1328
|
return Math.max(...t) <= e ? 1 : s;
|
|
1316
1329
|
}
|
|
1317
|
-
function
|
|
1318
|
-
if (!
|
|
1319
|
-
return
|
|
1330
|
+
function P(l) {
|
|
1331
|
+
if (!yt.test(l)) throw new Error("Invalid frets string. Only 'x', 'X', and digits are allowed.");
|
|
1332
|
+
return l.split("");
|
|
1320
1333
|
}
|
|
1321
|
-
function B(
|
|
1322
|
-
if (!Ot.test(
|
|
1323
|
-
return
|
|
1334
|
+
function B(l) {
|
|
1335
|
+
if (!Ot.test(l)) throw new Error("Invalid fingers string. Only digits are allowed.");
|
|
1336
|
+
return l.split("");
|
|
1324
1337
|
}
|
|
1325
|
-
class
|
|
1338
|
+
class Gt {
|
|
1326
1339
|
svgRendererInstance;
|
|
1327
1340
|
options;
|
|
1328
1341
|
chordEntries = [];
|
|
@@ -1341,23 +1354,22 @@ class Ft {
|
|
|
1341
1354
|
*/
|
|
1342
1355
|
constructor(e, t) {
|
|
1343
1356
|
if (this.options = {
|
|
1344
|
-
stringCount:
|
|
1345
|
-
fretCount:
|
|
1357
|
+
stringCount: it,
|
|
1358
|
+
fretCount: at,
|
|
1346
1359
|
stringLabels: [],
|
|
1347
1360
|
inlineChordsAmount: 2,
|
|
1361
|
+
centerChords: !0,
|
|
1348
1362
|
scale: 1,
|
|
1349
|
-
|
|
1350
|
-
backgroundColor: "transparent",
|
|
1363
|
+
svgAutoFill: !0,
|
|
1351
1364
|
...t
|
|
1352
|
-
}, this.diagramWidth = (this.options.stringCount - 1) *
|
|
1365
|
+
}, this.diagramWidth = (this.options.stringCount - 1) * T, this.diagramHeight = this.options.fretCount * m, this.gridTopY = k + W, this.rowHeight = this.gridTopY + this.diagramHeight + $, t?.width ? this.options.width = t.width : this.options.width = (this.diagramWidth + L) * this.options.inlineChordsAmount, this.options.stringLabels.length >= 1 && (this.rowHeight += ht + ct), this.diagramWidth > this.options.width)
|
|
1353
1366
|
throw new Error(`The configured width (${this.options.width}) is too small to fit a single ${this.options.stringCount}-string diagram (needs at least ${this.diagramWidth}). Increase 'width'.`);
|
|
1354
|
-
this.svgRendererInstance = new
|
|
1367
|
+
this.svgRendererInstance = new O(e, {
|
|
1355
1368
|
width: this.options.width,
|
|
1356
1369
|
height: 100,
|
|
1357
1370
|
scale: this.options.scale,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
useGlyphs: []
|
|
1371
|
+
useGlyphs: [],
|
|
1372
|
+
svgAutoFill: this.options.svgAutoFill
|
|
1361
1373
|
});
|
|
1362
1374
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1363
1375
|
this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
@@ -1373,30 +1385,33 @@ class Ft {
|
|
|
1373
1385
|
drawFretDots(e, t, s, r, n) {
|
|
1374
1386
|
const o = this.gridTopY - W / 2;
|
|
1375
1387
|
for (let i = 0; i < this.options.stringCount; i++) {
|
|
1376
|
-
const a = i *
|
|
1377
|
-
if (
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
this.svgRendererInstance.
|
|
1388
|
+
const a = i * T, h = e[i].toLowerCase(), d = t[i], c = this.svgRendererInstance.createGroup("");
|
|
1389
|
+
if (h === "x")
|
|
1390
|
+
c.classList.add("vs-guitar-fret-muted"), c.setAttribute("transform", `translate(${a}, ${o})`), this.svgRendererInstance.drawLine(-p, -p, p, p, c, {
|
|
1391
|
+
strokeWidth: 1.5
|
|
1392
|
+
}), this.svgRendererInstance.drawLine(-p, p, p, -p, c, {
|
|
1393
|
+
strokeWidth: 1.5
|
|
1394
|
+
});
|
|
1395
|
+
else if (h === "0")
|
|
1396
|
+
c.classList.add("vs-guitar-fret-open"), c.setAttribute("transform", `translate(${a}, ${o})`), this.svgRendererInstance.drawCircle(0, 0, p, c, { filled: !1 });
|
|
1381
1397
|
else {
|
|
1382
|
-
const
|
|
1383
|
-
if (r.has(`${i}-${
|
|
1398
|
+
const f = parseInt(h, 36);
|
|
1399
|
+
if (r.has(`${i}-${f}`))
|
|
1384
1400
|
continue;
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1401
|
+
c.classList.add("vs-guitar-fret-dot");
|
|
1402
|
+
const E = f - s + 1;
|
|
1403
|
+
if (E < 1 || E > this.options.fretCount)
|
|
1404
|
+
throw new Error(`Fret ${h} on string ${i + 1} is outside the visible range (${s}-${s + this.options.fretCount - 1}). Adjust 'startFret' or 'fretCount'.`);
|
|
1405
|
+
const g = this.gridTopY + (E - 0.5) * m;
|
|
1406
|
+
c.setAttribute("transform", `translate(${a}, ${g})`), this.svgRendererInstance.drawCircle(0, 0, u, c, {
|
|
1407
|
+
classes: "guitar-fret-circle"
|
|
1408
|
+
}), d !== "0" && this.svgRendererInstance.drawText(d, 0, -1, c, {
|
|
1409
|
+
fontSize: R,
|
|
1410
|
+
baseline: "central",
|
|
1411
|
+
classes: ["guitar-text", "guitar-fret-text"]
|
|
1412
|
+
});
|
|
1399
1413
|
}
|
|
1414
|
+
n.appendChild(c);
|
|
1400
1415
|
}
|
|
1401
1416
|
}
|
|
1402
1417
|
drawStringLabels(e, t) {
|
|
@@ -1405,10 +1420,11 @@ class Ft {
|
|
|
1405
1420
|
for (let n = 0; n < this.options.stringCount; n++) {
|
|
1406
1421
|
const o = t[n];
|
|
1407
1422
|
if (!o) continue;
|
|
1408
|
-
const i = n *
|
|
1409
|
-
this.svgRendererInstance.drawText(o, i,
|
|
1410
|
-
fontSize:
|
|
1411
|
-
|
|
1423
|
+
const i = n * T;
|
|
1424
|
+
this.svgRendererInstance.drawText(o, i, r, e, {
|
|
1425
|
+
fontSize: R,
|
|
1426
|
+
baseline: "central",
|
|
1427
|
+
classes: "guitar-text"
|
|
1412
1428
|
});
|
|
1413
1429
|
}
|
|
1414
1430
|
}
|
|
@@ -1419,69 +1435,82 @@ class Ft {
|
|
|
1419
1435
|
throw new Error(`Barre fret error: Invalid string range ${t.fromIndex + 1}:${t.toIndex + 1}.`);
|
|
1420
1436
|
if (s < t.startingFret || s > t.startingFret + (this.options.fretCount - 1))
|
|
1421
1437
|
throw new Error(`Barre fret error: ${t.fret} is outside the visible range.`);
|
|
1422
|
-
const r = s - t.startingFret,
|
|
1423
|
-
|
|
1424
|
-
x:
|
|
1425
|
-
y:
|
|
1438
|
+
const r = this.svgRendererInstance.createGroup("guitar-group-barre"), n = s - t.startingFret, o = t.fromIndex * T, i = t.toIndex * T, a = u * 2, h = i - o + a, d = this.gridTopY + m * n;
|
|
1439
|
+
r.setAttribute("transform", `translate(0, ${d})`), this.svgRendererInstance.drawRect(h, a, r, {
|
|
1440
|
+
x: o - u,
|
|
1441
|
+
y: u / 2,
|
|
1426
1442
|
rx: u,
|
|
1427
1443
|
classes: "guitar-barre"
|
|
1428
|
-
}), t.finger) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
classes: "guitar-text-small"
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1444
|
+
}), t.finger && this.svgRendererInstance.drawText(t.finger.toString(), (o + i) / 2, u * 1.5 - 1, r, {
|
|
1445
|
+
fontSize: R,
|
|
1446
|
+
baseline: "central",
|
|
1447
|
+
classes: ["guitar-text", "guitar-fret-text"]
|
|
1448
|
+
}), e.appendChild(r);
|
|
1436
1449
|
}
|
|
1437
1450
|
// Builds a single chord diagram's group element: grid, nut/fret-position label, and per-string markers.
|
|
1438
1451
|
renderChordDiagram(e, t, s) {
|
|
1439
1452
|
const r = this.svgRendererInstance.createGroup("chord"), n = s?.startFret ?? 1;
|
|
1440
|
-
s?.label && this.svgRendererInstance.drawText(s.label, this.diagramWidth / 2,
|
|
1441
|
-
fontSize:
|
|
1453
|
+
s?.label && this.svgRendererInstance.drawText(s.label, this.diagramWidth / 2, k - 5, r, {
|
|
1454
|
+
fontSize: st,
|
|
1442
1455
|
fontWeight: "bold",
|
|
1443
|
-
classes: "guitar-text-
|
|
1444
|
-
})
|
|
1445
|
-
for (let i = 0; i <= this.options.fretCount; i++) {
|
|
1446
|
-
const a = this.gridTopY + i * T;
|
|
1447
|
-
i === 0 && n === 1 ? this.svgRendererInstance.drawRect(this.diagramWidth + k * 2, P, r, {
|
|
1448
|
-
x: -k,
|
|
1449
|
-
y: a - P / 2
|
|
1450
|
-
}) : this.svgRendererInstance.drawLine(0, a, this.diagramWidth, a, r);
|
|
1451
|
-
}
|
|
1452
|
-
n > 1 && this.svgRendererInstance.drawText(`${n}fr`, this.diagramWidth + u + ut, this.gridTopY + T / 2 + 4, r, {
|
|
1456
|
+
classes: ["guitar-text", "guitar-diagram-label"]
|
|
1457
|
+
}), n > 1 && this.svgRendererInstance.drawText(`${n}fr`, this.diagramWidth + u + Et, this.gridTopY + m / 2 + 4, r, {
|
|
1453
1458
|
anchor: "start",
|
|
1454
|
-
fontSize:
|
|
1459
|
+
fontSize: R,
|
|
1455
1460
|
fontWeight: "bold",
|
|
1456
|
-
classes: "guitar-text-
|
|
1461
|
+
classes: ["guitar-text", "guitar-fret-label"]
|
|
1457
1462
|
});
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1463
|
+
const o = this.svgRendererInstance.createGroup("guitar-group-fret-lines");
|
|
1464
|
+
for (let c = 0; c <= this.options.fretCount; c++) {
|
|
1465
|
+
const f = this.gridTopY + c * m;
|
|
1466
|
+
c === 0 && n === 1 ? this.svgRendererInstance.drawRect(this.diagramWidth + ft, x, o, {
|
|
1467
|
+
x: -0.5,
|
|
1468
|
+
y: f - x / 2
|
|
1469
|
+
}) : this.svgRendererInstance.drawLine(0, f, this.diagramWidth, f, o);
|
|
1461
1470
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1471
|
+
r.appendChild(o);
|
|
1472
|
+
const i = this.svgRendererInstance.createGroup("guitar-group-string-lines");
|
|
1473
|
+
for (let c = 0; c < this.options.stringCount; c++) {
|
|
1474
|
+
const f = c * T;
|
|
1475
|
+
this.svgRendererInstance.drawLine(f, this.gridTopY, f, this.gridTopY + this.diagramHeight, i);
|
|
1476
|
+
}
|
|
1477
|
+
r.appendChild(i);
|
|
1478
|
+
const a = this.svgRendererInstance.createGroup("guitar-group-fret-dots"), h = this.getDotsToHide(s?.barres);
|
|
1479
|
+
this.drawFretDots(e, t, n, h, a), s?.barres?.forEach((c) => {
|
|
1480
|
+
this.drawBarre(a, {
|
|
1481
|
+
fromIndex: c.fromString - 1,
|
|
1482
|
+
toIndex: c.toString - 1,
|
|
1483
|
+
fret: c.fret,
|
|
1484
|
+
finger: c.finger,
|
|
1469
1485
|
startingFret: n
|
|
1470
1486
|
});
|
|
1471
|
-
}), r;
|
|
1487
|
+
}), r.appendChild(a);
|
|
1488
|
+
const d = this.svgRendererInstance.createGroup("guitar-group-string-labels");
|
|
1489
|
+
return this.options.stringLabels.length >= 1 && this.drawStringLabels(d, this.options.stringLabels), r.appendChild(d), r;
|
|
1472
1490
|
}
|
|
1473
1491
|
// Repositions every existing chord diagram from scratch, in order, wrapping rows as needed.
|
|
1474
|
-
// Called after any add/remove/change so the layout never has to track
|
|
1492
|
+
// Called after any add/remove/change so the layout never has to track pos.
|
|
1475
1493
|
relayoutChords() {
|
|
1476
|
-
if (this.
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1494
|
+
if (this.chordEntries.length === 0) {
|
|
1495
|
+
this.svgRendererInstance.setTotalRootSvgHeight(0), this.svgRendererInstance.applySizingToRootSvg();
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
const e = [];
|
|
1499
|
+
let t = [], s = u;
|
|
1500
|
+
this.chordEntries.forEach((n, o) => {
|
|
1501
|
+
o > 0 && s + this.diagramWidth > this.options.width && (e.push(t), t = [], s = u), t.push(n), s += this.diagramWidth + L;
|
|
1502
|
+
}), t.length > 0 && e.push(t), this.cursorY = dt, e.forEach((n, o) => {
|
|
1503
|
+
if (o > 0 && (this.cursorY += this.rowHeight + lt), this.options.centerChords) {
|
|
1504
|
+
const i = n.length * this.diagramWidth + (n.length - 1) * L;
|
|
1505
|
+
this.cursorX = this.options.width / 2 - i / 2;
|
|
1506
|
+
} else
|
|
1507
|
+
this.cursorX = u;
|
|
1508
|
+
n.forEach((i) => {
|
|
1509
|
+
i.xPos = this.cursorX, i.yPos = this.cursorY, i.gElement.setAttribute("transform", `translate(${this.cursorX}, ${this.cursorY})`), this.cursorX += this.diagramWidth + L;
|
|
1482
1510
|
});
|
|
1483
|
-
|
|
1484
|
-
this.
|
|
1511
|
+
});
|
|
1512
|
+
const r = this.cursorY + this.rowHeight;
|
|
1513
|
+
this.svgRendererInstance.setTotalRootSvgHeight(r), this.svgRendererInstance.applySizingToRootSvg();
|
|
1485
1514
|
}
|
|
1486
1515
|
/**
|
|
1487
1516
|
* Adds a new chord diagram. Diagrams are placed left-to-right in the order added, wrapping to a
|
|
@@ -1507,14 +1536,14 @@ class Ft {
|
|
|
1507
1536
|
* guitarChord.addChord("x32010", "032010", { label: "C" });
|
|
1508
1537
|
*/
|
|
1509
1538
|
addChord(e, t, s) {
|
|
1510
|
-
const r =
|
|
1539
|
+
const r = P(e), n = B(t);
|
|
1511
1540
|
if (r.length !== this.options.stringCount) throw new Error("Invalid number of frets provided, entries should be equal to number of strings in diagram.");
|
|
1512
1541
|
if (n.length !== this.options.stringCount) throw new Error("Invalid number of fingers provided, entries should be equal to number of strings in diagram.");
|
|
1513
|
-
const o = s?.startFret ??
|
|
1514
|
-
return this.svgRendererInstance.commitElementsToDOM(
|
|
1515
|
-
gElement:
|
|
1516
|
-
strings:
|
|
1517
|
-
...
|
|
1542
|
+
const o = s?.startFret ?? et(r, this.options.fretCount), i = s?.label, a = s?.barres, h = { startFret: o, label: i, barres: a }, d = this.renderChordDiagram(r, n, h), c = this.svgRendererInstance.parentGroupElement;
|
|
1543
|
+
return this.svgRendererInstance.commitElementsToDOM(d, c), this.chordEntries.push({
|
|
1544
|
+
gElement: d,
|
|
1545
|
+
strings: tt(r, n),
|
|
1546
|
+
...h,
|
|
1518
1547
|
xPos: 0,
|
|
1519
1548
|
yPos: 0
|
|
1520
1549
|
}), this.relayoutChords(), this.chordEntries.length - 1;
|
|
@@ -1545,14 +1574,14 @@ class Ft {
|
|
|
1545
1574
|
*/
|
|
1546
1575
|
modifyChordByIndex(e, t, s, r) {
|
|
1547
1576
|
if (s >= this.chordEntries.length || s < 0) throw new Error("Chord index was out of bounds.");
|
|
1548
|
-
const n =
|
|
1577
|
+
const n = P(e), o = B(t);
|
|
1549
1578
|
if (n.length !== this.options.stringCount) throw new Error("Invalid number of frets provided, entries should be equal to number of strings in diagram.");
|
|
1550
1579
|
if (o.length !== this.options.stringCount) throw new Error("Invalid number of fingers provided, entries should be equal to number of strings in diagram.");
|
|
1551
|
-
const i = this.chordEntries[s], a = r && "label" in r ? r.label === "" ? void 0 : r.label : i.label,
|
|
1552
|
-
this.svgRendererInstance.
|
|
1553
|
-
gElement:
|
|
1554
|
-
strings:
|
|
1555
|
-
...
|
|
1580
|
+
const i = this.chordEntries[s], a = r && "label" in r ? r.label === "" ? void 0 : r.label : i.label, h = r?.startFret ?? et(n, this.options.fretCount), d = { ...r, label: a, startFret: h }, c = this.renderChordDiagram(n, o, d);
|
|
1581
|
+
this.svgRendererInstance.parentGroupElement.replaceChild(c, i.gElement), this.chordEntries[s] = {
|
|
1582
|
+
gElement: c,
|
|
1583
|
+
strings: tt(n, o),
|
|
1584
|
+
...d,
|
|
1556
1585
|
xPos: i.xPos,
|
|
1557
1586
|
yPos: i.yPos
|
|
1558
1587
|
}, this.relayoutChords();
|
|
@@ -1572,7 +1601,7 @@ class Ft {
|
|
|
1572
1601
|
* @returns void
|
|
1573
1602
|
*/
|
|
1574
1603
|
clearAllChords() {
|
|
1575
|
-
this.svgRendererInstance.
|
|
1604
|
+
this.svgRendererInstance.parentGroupElement.replaceChildren(), this.chordEntries = [], this.cursorX = 0, this.cursorY = 0, this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg();
|
|
1576
1605
|
}
|
|
1577
1606
|
/**
|
|
1578
1607
|
* * Used to automatically determine options for creating barre lines.
|
|
@@ -1580,25 +1609,25 @@ class Ft {
|
|
|
1580
1609
|
* @returns GuitarBarreDef[]
|
|
1581
1610
|
*/
|
|
1582
1611
|
determineBarreOptions(e, t, s) {
|
|
1583
|
-
const r =
|
|
1612
|
+
const r = P(e), n = B(t), o = [];
|
|
1584
1613
|
return s.forEach((i) => {
|
|
1585
1614
|
if (i === 0) return;
|
|
1586
|
-
const a = [],
|
|
1587
|
-
for (let
|
|
1588
|
-
if (r[
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1615
|
+
const a = [], h = {};
|
|
1616
|
+
for (let g = 0; g < r.length; g++) {
|
|
1617
|
+
if (r[g].toLowerCase() === "x") continue;
|
|
1618
|
+
const N = parseInt(r[g], 36), b = Number(n[g]);
|
|
1619
|
+
N === i && (h[b] ? h[b] += 1 : h[b] = 1, a.push(g + 1));
|
|
1591
1620
|
}
|
|
1592
1621
|
a.sort();
|
|
1593
|
-
let
|
|
1594
|
-
for (const [
|
|
1595
|
-
|
|
1596
|
-
const f = a[0],
|
|
1597
|
-
a.length > 1 &&
|
|
1622
|
+
let d = 0, c = 0;
|
|
1623
|
+
for (const [g, N] of Object.entries(h))
|
|
1624
|
+
N > c && (c = N, d = Number(g));
|
|
1625
|
+
const f = a[0], E = a.at(-1);
|
|
1626
|
+
a.length > 1 && E && o.push({
|
|
1598
1627
|
fret: i,
|
|
1599
1628
|
fromString: f,
|
|
1600
|
-
toString:
|
|
1601
|
-
finger:
|
|
1629
|
+
toString: E,
|
|
1630
|
+
finger: d
|
|
1602
1631
|
});
|
|
1603
1632
|
}), o;
|
|
1604
1633
|
}
|
|
@@ -1611,8 +1640,8 @@ class Ft {
|
|
|
1611
1640
|
}
|
|
1612
1641
|
}
|
|
1613
1642
|
export {
|
|
1614
|
-
|
|
1643
|
+
Gt as GuitarChord,
|
|
1615
1644
|
bt as MusicStaff,
|
|
1616
|
-
|
|
1617
|
-
|
|
1645
|
+
vt as RhythmStaff,
|
|
1646
|
+
Ft as ScrollingStaff
|
|
1618
1647
|
};
|