vector-score 1.1.0 → 1.2.1
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 +159 -40
- package/dist/classes/GuitarChord.d.ts +108 -0
- package/dist/classes/SVGRenderer.d.ts +19 -0
- package/dist/constants.d.ts +19 -0
- package/dist/helpers/guitarHelpers.d.ts +5 -0
- package/dist/index.d.ts +3 -0
- package/dist/types.d.ts +15 -0
- package/dist/vector-score.js +488 -161
- package/dist/vector-score.umd.cjs +1 -1
- package/package.json +2 -1
package/dist/vector-score.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const R = {
|
|
2
2
|
treble: {
|
|
3
3
|
staffType: "treble",
|
|
4
4
|
paddingTop: 13,
|
|
@@ -31,16 +31,16 @@ const I = {
|
|
|
31
31
|
topLineYPos: 0,
|
|
32
32
|
bottomLineYPos: 110
|
|
33
33
|
}
|
|
34
|
-
},
|
|
34
|
+
}, p = {
|
|
35
35
|
w: 4,
|
|
36
36
|
h: 2,
|
|
37
37
|
q: 1,
|
|
38
38
|
e: 0.5,
|
|
39
39
|
s: 0.25
|
|
40
|
-
},
|
|
40
|
+
}, at = 6, ct = 5, _ = 22, T = 30, u = 10, g = 6, ht = 4, lt = u * 2, M = 51, dt = 12, ft = 4, $ = 1, P = 4, k = 1, W = g * 2 + P + 4, rt = 16, S = 12, Z = rt, ut = 2, V = 8, Et = 40, nt = {
|
|
41
41
|
sharp: ["F", "C", "G", "D", "A", "E", "B"],
|
|
42
42
|
flat: ["B", "E", "A", "D", "G", "C", "F"]
|
|
43
|
-
},
|
|
43
|
+
}, q = {
|
|
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 I = {
|
|
|
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,22 +75,22 @@ const I = {
|
|
|
75
75
|
},
|
|
76
76
|
grand: { sharp: [], flat: [] }
|
|
77
77
|
};
|
|
78
|
-
function
|
|
79
|
-
const e =
|
|
80
|
-
if (!e) throw new Error(`Unknown key signature "${h}". Valid keys: ${Object.keys(
|
|
78
|
+
function gt(h) {
|
|
79
|
+
const e = q[h];
|
|
80
|
+
if (!e) throw new Error(`Unknown key signature "${h}". Valid keys: ${Object.keys(q).join(", ")}`);
|
|
81
81
|
return e;
|
|
82
82
|
}
|
|
83
|
-
function
|
|
84
|
-
const r =
|
|
83
|
+
function At(h, e, t, s) {
|
|
84
|
+
const r = gt(t);
|
|
85
85
|
if (r.count === 0) return 0;
|
|
86
86
|
const n = r.type === "sharp" ? "ACCIDENTAL_SHARP" : "ACCIDENTAL_FLAT", o = h.getLayerByName("staff");
|
|
87
|
-
return e.getKeySignatureYPositions(r.type, r.count).forEach((
|
|
88
|
-
|
|
89
|
-
h.drawGlyph(n, o, { xOffset: s + l *
|
|
87
|
+
return e.getKeySignatureYPositions(r.type, r.count).forEach((a) => {
|
|
88
|
+
a.forEach((c, l) => {
|
|
89
|
+
h.drawGlyph(n, o, { xOffset: s + l * V, yOffset: c });
|
|
90
90
|
});
|
|
91
|
-
}), r.count *
|
|
91
|
+
}), r.count * V;
|
|
92
92
|
}
|
|
93
|
-
const
|
|
93
|
+
const pt = {
|
|
94
94
|
CLEF_TREBLE: {
|
|
95
95
|
path: "m150 273 10 58c2 7 2 7 12 7 59 0 96 46 96 97 0 45-26 79-67 95-5 2-6 2-5 7 4 25 12 63 12 85 0 68-52 80-79 80-61 0-76-39-76-65 0-25 16-46 43-46 24 0 38 19 38 41 0 23-14 34-27 38-9 2-13 4-13 6 0 6 11 12 32 12 24 0 64-7 64-66 0-19-6-54-11-81-1-5-1-4-6-3l-27 2C48 540 0 474 0 404c0-80 61-138 119-185 5-4 4-5 3-10-2-16-5-42-5-65 0-42 9-92 39-125 8-9 20-19 26-19 4 0 15 11 21 20 16 24 26 58 26 93 0 61-33 112-76 153-3 2-3 2-3 7Zm38-211c-24 0-53 38-53 101l2 37c1 5 3 5 5 3 32-28 70-64 70-108 0-22-11-33-24-33Zm-44 272-8-51c-1-4-2-5-6-1-18 15-37 30-61 56-33 38-37 70-37 93 0 56 45 95 115 95l23-2c6-2 6-2 5-6l-20-119c-1-5-1-5-8-3-24 6-40 24-40 46 0 19 12 36 29 43 3 1 6 3 6 5 0 3-2 5-5 5l-11-3c-27-9-46-34-46-70 0-34 23-66 58-78 8-2 8-2 6-10Zm28 64 20 114c0 5 1 5 6 2 22-11 38-31 38-56 0-36-27-63-60-66-4 0-5 1-4 6Z",
|
|
96
96
|
xOffset: 0,
|
|
@@ -186,9 +186,9 @@ const $ = {
|
|
|
186
186
|
xOffset: 0,
|
|
187
187
|
yOffset: 0
|
|
188
188
|
}
|
|
189
|
-
},
|
|
190
|
-
function
|
|
191
|
-
const e = h.match(
|
|
189
|
+
}, It = /^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/, _t = /^[whqeWHQE]$/, X = ["C", "D", "E", "F", "G", "A", "B"];
|
|
190
|
+
function U(h) {
|
|
191
|
+
const e = h.match(It);
|
|
192
192
|
if (!e || !e.groups)
|
|
193
193
|
throw new Error(`Invalid note string format: ${h}. Expected format: [A-Ga-g][#|b]?[0-9][w|h|q|e].`);
|
|
194
194
|
let { name: t, accidental: s, octave: r, duration: n } = e.groups;
|
|
@@ -200,12 +200,12 @@ function O(h) {
|
|
|
200
200
|
};
|
|
201
201
|
return s && (o.accidental = s), o;
|
|
202
202
|
}
|
|
203
|
-
function
|
|
204
|
-
const e = h.match(
|
|
203
|
+
function b(h) {
|
|
204
|
+
const e = h.match(_t);
|
|
205
205
|
if (!e) throw new Error(`Invalid note duration '${h}'. Use w | h | q | e.`);
|
|
206
206
|
return e[0].toString().toLowerCase();
|
|
207
207
|
}
|
|
208
|
-
function
|
|
208
|
+
function Y(h) {
|
|
209
209
|
let e;
|
|
210
210
|
switch (h) {
|
|
211
211
|
case "treble":
|
|
@@ -221,22 +221,22 @@ function R(h) {
|
|
|
221
221
|
if (!e) throw new Error(`Invalid clef type: ${h}. Valid clef types are: treble, bass, alto.`);
|
|
222
222
|
return e;
|
|
223
223
|
}
|
|
224
|
-
function
|
|
225
|
-
let e =
|
|
224
|
+
function z(h) {
|
|
225
|
+
let e = X.indexOf(h.name);
|
|
226
226
|
return e += h.octave * 12, e;
|
|
227
227
|
}
|
|
228
|
-
function
|
|
229
|
-
return
|
|
228
|
+
function N(h, e) {
|
|
229
|
+
return X.indexOf(h.name) - X.indexOf(e.name) + (h.octave - e.octave) * 7;
|
|
230
230
|
}
|
|
231
|
-
const
|
|
232
|
-
class
|
|
231
|
+
const G = 48, j = 40 + 30 / 2, K = 20, Q = 90;
|
|
232
|
+
class ot {
|
|
233
233
|
params;
|
|
234
234
|
rendererRef;
|
|
235
235
|
width = 0;
|
|
236
236
|
trebleStaffHeight = 0;
|
|
237
237
|
constructor(e, t) {
|
|
238
238
|
this.rendererRef = e;
|
|
239
|
-
const s =
|
|
239
|
+
const s = R[t];
|
|
240
240
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
241
241
|
this.params = s;
|
|
242
242
|
}
|
|
@@ -252,17 +252,17 @@ class x {
|
|
|
252
252
|
let s = this.drawStaffLines(0, t), r = this.drawStaffLines(s + 30, t);
|
|
253
253
|
this.rendererRef.drawLine(0, 0, 0, r, t), this.rendererRef.drawLine(this.width, 0, this.width, r, t), this.trebleStaffHeight = s;
|
|
254
254
|
let n = r, o = 1;
|
|
255
|
-
const
|
|
256
|
-
this.rendererRef.drawGlyph(
|
|
255
|
+
const i = Y("treble"), a = Y("bass");
|
|
256
|
+
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
257
|
};
|
|
258
258
|
shouldNoteFlip(e) {
|
|
259
|
-
const t = Math.abs(e -
|
|
260
|
-
return e ===
|
|
259
|
+
const t = Math.abs(e - Q), s = Math.abs(e - K);
|
|
260
|
+
return e === j ? !1 : t <= s ? !(e >= Q) : e <= K;
|
|
261
261
|
}
|
|
262
262
|
getLedgerLinesX(e, t) {
|
|
263
|
-
const s = [], r =
|
|
263
|
+
const s = [], r = z(e);
|
|
264
264
|
let n = e.duration === "w" ? 17 : 12.5;
|
|
265
|
-
if (r ===
|
|
265
|
+
if (r === G)
|
|
266
266
|
return s.push({ x1: -2, x2: n, yPos: 0 }), s;
|
|
267
267
|
if (t < this.params.topLineYPos) {
|
|
268
268
|
let o = this.params.topLineYPos - 10;
|
|
@@ -284,41 +284,41 @@ class x {
|
|
|
284
284
|
return s;
|
|
285
285
|
}
|
|
286
286
|
calculateNoteYPos = (e) => {
|
|
287
|
-
let s =
|
|
288
|
-
const r =
|
|
289
|
-
return r <
|
|
287
|
+
let s = N(this.params.topLineNote, e) * (10 / 2);
|
|
288
|
+
const r = z(e);
|
|
289
|
+
return r < G ? s += 10 : r === G && (s = j), s;
|
|
290
290
|
};
|
|
291
291
|
getKeySignatureYPositions(e, t) {
|
|
292
|
-
const s =
|
|
293
|
-
(
|
|
294
|
-
),
|
|
295
|
-
(
|
|
292
|
+
const s = nt[e].slice(0, t), r = x.treble[e], n = x.bass[e], o = s.map(
|
|
293
|
+
(a, c) => N(R.treble.topLineNote, { name: a, octave: r[c] }) * (10 / 2)
|
|
294
|
+
), i = s.map(
|
|
295
|
+
(a, c) => N(R.bass.topLineNote, { name: a, octave: n[c] }) * (10 / 2) + this.trebleStaffHeight + 30
|
|
296
296
|
);
|
|
297
|
-
return [o,
|
|
297
|
+
return [o, i];
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
|
-
const
|
|
301
|
-
class
|
|
300
|
+
const Tt = 20;
|
|
301
|
+
class m {
|
|
302
302
|
params;
|
|
303
303
|
rendererRef;
|
|
304
304
|
constructor(e, t) {
|
|
305
305
|
this.rendererRef = e;
|
|
306
|
-
const s =
|
|
306
|
+
const s = R[t];
|
|
307
307
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
308
308
|
this.params = s;
|
|
309
309
|
}
|
|
310
310
|
drawStaff = (e) => {
|
|
311
311
|
const t = this.rendererRef.getLayerByName("staff");
|
|
312
312
|
let s = 0;
|
|
313
|
-
for (let
|
|
313
|
+
for (let i = 0; i < 5; i++)
|
|
314
314
|
this.rendererRef.drawLine(0, s, e, s, t), s += 10;
|
|
315
315
|
this.rendererRef.drawLine(0, 0, 0, s - 10, t), this.rendererRef.drawLine(e, 0, e, s - 10, t);
|
|
316
316
|
let r = s - 10 + 1, n = 1;
|
|
317
|
-
const o =
|
|
317
|
+
const o = Y(this.params.staffType);
|
|
318
318
|
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
319
|
};
|
|
320
320
|
shouldNoteFlip(e) {
|
|
321
|
-
return e <=
|
|
321
|
+
return e <= Tt;
|
|
322
322
|
}
|
|
323
323
|
getLedgerLinesX(e, t) {
|
|
324
324
|
const s = [];
|
|
@@ -342,15 +342,15 @@ class A {
|
|
|
342
342
|
}
|
|
343
343
|
return s;
|
|
344
344
|
}
|
|
345
|
-
calculateNoteYPos = (e) =>
|
|
345
|
+
calculateNoteYPos = (e) => N(this.params.topLineNote, e) * (10 / 2);
|
|
346
346
|
getKeySignatureYPositions(e, t) {
|
|
347
|
-
const s =
|
|
347
|
+
const s = nt[e].slice(0, t), r = x[this.params.staffType][e];
|
|
348
348
|
return [s.map(
|
|
349
|
-
(o,
|
|
349
|
+
(o, i) => this.calculateNoteYPos({ name: o, octave: r[i] })
|
|
350
350
|
)];
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
|
-
class
|
|
353
|
+
class it {
|
|
354
354
|
svgRendererInstance;
|
|
355
355
|
strategyInstance;
|
|
356
356
|
constructor(e, t) {
|
|
@@ -364,9 +364,9 @@ class U {
|
|
|
364
364
|
for (let n = 0; n < e.length; n++) {
|
|
365
365
|
const o = e[n];
|
|
366
366
|
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
|
|
368
|
-
if (!
|
|
369
|
-
|
|
367
|
+
const a = Array.from(o.noteGroup.getElementsByTagName("use")).find((c) => c.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
368
|
+
if (!a) continue;
|
|
369
|
+
a.setAttribute("transform", `translate(${t + 8}, 0)`);
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
return -s;
|
|
@@ -375,13 +375,13 @@ class U {
|
|
|
375
375
|
let t = e[0], s = 0;
|
|
376
376
|
for (let r = 1; r < e.length; r++) {
|
|
377
377
|
const n = e[r];
|
|
378
|
-
if (-
|
|
378
|
+
if (-N(t.noteObj, n.noteObj) === 1) {
|
|
379
379
|
s = 28 / 2, n.noteGroup.setAttribute("transform", `translate(${s}, ${n.noteYPos})`);
|
|
380
|
-
const
|
|
381
|
-
if (
|
|
382
|
-
const c =
|
|
383
|
-
let
|
|
384
|
-
l && (
|
|
380
|
+
const a = Array.from(n.noteGroup.getElementsByTagName("use")).find((c) => c.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
381
|
+
if (a) {
|
|
382
|
+
const c = a.getAttribute("transform")?.match(/([-]?\d+)/), l = c && c[0];
|
|
383
|
+
let d = -s;
|
|
384
|
+
l && (d += Number(l)), a.setAttribute("transform", `translate(${d}, 0)`);
|
|
385
385
|
}
|
|
386
386
|
r++, t = e[r];
|
|
387
387
|
continue;
|
|
@@ -392,7 +392,7 @@ class U {
|
|
|
392
392
|
}
|
|
393
393
|
// Handles drawing the glyphs to internal group, applies the xPositioning to note Cursor X
|
|
394
394
|
renderNote(e) {
|
|
395
|
-
const t = this.svgRendererInstance.createGroup("note"), s =
|
|
395
|
+
const t = this.svgRendererInstance.createGroup("note"), s = U(e), r = this.strategyInstance.calculateNoteYPos({
|
|
396
396
|
name: s.name,
|
|
397
397
|
octave: s.octave
|
|
398
398
|
});
|
|
@@ -428,8 +428,8 @@ class U {
|
|
|
428
428
|
this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_FLAT", t), o -= -14;
|
|
429
429
|
break;
|
|
430
430
|
}
|
|
431
|
-
return this.strategyInstance.getLedgerLinesX(s, r).forEach((
|
|
432
|
-
this.svgRendererInstance.drawLine(
|
|
431
|
+
return this.strategyInstance.getLedgerLinesX(s, r).forEach((a) => {
|
|
432
|
+
this.svgRendererInstance.drawLine(a.x1, a.yPos, a.x2, a.yPos, t);
|
|
433
433
|
}), {
|
|
434
434
|
noteGroup: t,
|
|
435
435
|
noteObj: s,
|
|
@@ -441,11 +441,11 @@ class U {
|
|
|
441
441
|
renderChord(e) {
|
|
442
442
|
const t = this.svgRendererInstance.createGroup("chord"), s = [];
|
|
443
443
|
for (const o of e) {
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
noteGroup:
|
|
447
|
-
noteObj:
|
|
448
|
-
noteYPos:
|
|
444
|
+
const i = this.renderNote(o);
|
|
445
|
+
i.noteGroup.setAttribute("transform", `translate(0, ${i.noteYPos})`), t.appendChild(i.noteGroup), s.push({
|
|
446
|
+
noteGroup: i.noteGroup,
|
|
447
|
+
noteObj: i.noteObj,
|
|
448
|
+
noteYPos: i.noteYPos,
|
|
449
449
|
cursorOffset: 0,
|
|
450
450
|
accidentalOffset: 0
|
|
451
451
|
});
|
|
@@ -460,8 +460,8 @@ class U {
|
|
|
460
460
|
};
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
|
-
const
|
|
464
|
-
class
|
|
463
|
+
const A = "http://www.w3.org/2000/svg", mt = 0.1, v = 1200;
|
|
464
|
+
class w {
|
|
465
465
|
rootElementRef;
|
|
466
466
|
svgElementRef;
|
|
467
467
|
// Layers
|
|
@@ -479,18 +479,21 @@ class b {
|
|
|
479
479
|
// from get rootSvgElement().
|
|
480
480
|
// HEIGHT and YOfsset should be set externally, values are calculated internally.
|
|
481
481
|
constructor(e, t) {
|
|
482
|
-
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.width >
|
|
482
|
+
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.width > v && (this.width = v, console.warn(`Width provided for the staff ${this.width} exceeds the limit ${v}. Please use this value to fix positioning issues.`)), this.svgElementRef = document.createElementNS(A, "svg"), this.svgElementRef.classList.add("vs-svg-renderer-root"), this.svgElementRef.style.maxWidth = "100%", this.svgElementRef.style.height = "auto", this.svgElementRef.style.display = "block", this.svgElementRef.setAttribute("color", t.staffColor), this.svgElementRef.style.backgroundColor = t.staffBackgroundColor, this.makeGlyphDefs(t.useGlyphs), this.parentGroupContainer = this.createGroup("svg-renderer-parent"), this.svgElementRef.appendChild(this.parentGroupContainer), this.musicStaffLayer = this.createGroup("music-staff-layer"), this.musicNotesLayer = this.createGroup("music-notes-layer"), this.musicUILayer = this.createGroup("music-ui-layer"), this.parentGroupContainer.appendChild(this.musicStaffLayer), this.parentGroupContainer.appendChild(this.musicNotesLayer), this.parentGroupContainer.appendChild(this.musicUILayer);
|
|
483
483
|
}
|
|
484
484
|
// Creates SVG defs for all glyphs in GLYPH_ENTRIES, applies global scale and offsets, appends to root SVG
|
|
485
485
|
makeGlyphDefs(e) {
|
|
486
|
-
const t = document.createElementNS(
|
|
487
|
-
Object.entries(
|
|
488
|
-
const o = document.createElementNS(
|
|
489
|
-
o.setAttribute("id", `glyph-${r}`), o.setAttribute("d", n.path), o.setAttribute("fill", "currentColor"), o.setAttribute("transform", `translate(${n.xOffset}, ${n.yOffset}) scale(${
|
|
486
|
+
const t = document.createElementNS(A, "defs");
|
|
487
|
+
Object.entries(pt).filter(([r]) => e.includes(r)).forEach(([r, n]) => {
|
|
488
|
+
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(${mt})`), t.appendChild(o);
|
|
490
490
|
}), this.rootSvgElement.appendChild(t);
|
|
491
491
|
}
|
|
492
|
+
addNamespacedClassesToElement(e, t) {
|
|
493
|
+
[e].flat().forEach((r) => t.classList.add(`vs-${r}`));
|
|
494
|
+
}
|
|
492
495
|
createGroup(e) {
|
|
493
|
-
const t = document.createElementNS(
|
|
496
|
+
const t = document.createElementNS(A, "g");
|
|
494
497
|
return e && t.classList.add(`vs-${e}`), t;
|
|
495
498
|
}
|
|
496
499
|
commitElementsToDOM(e, t = this.rootElementRef) {
|
|
@@ -514,6 +517,9 @@ class b {
|
|
|
514
517
|
addTotalRootSvgHeight(e) {
|
|
515
518
|
this.totalHeight += e;
|
|
516
519
|
}
|
|
520
|
+
setTotalRootSvgHeight(e) {
|
|
521
|
+
this.totalHeight = e;
|
|
522
|
+
}
|
|
517
523
|
addTotalRootSvgYOffset(e) {
|
|
518
524
|
this.totalYOffset += e;
|
|
519
525
|
}
|
|
@@ -531,12 +537,12 @@ class b {
|
|
|
531
537
|
}
|
|
532
538
|
// Drawing Methods
|
|
533
539
|
drawLine(e, t, s, r, n) {
|
|
534
|
-
const o = document.createElementNS(
|
|
540
|
+
const o = document.createElementNS(A, "line");
|
|
535
541
|
o.setAttribute("x1", e.toString()), o.setAttribute("y1", t.toString()), o.setAttribute("x2", s.toString()), o.setAttribute("y2", r.toString()), o.setAttribute("stroke", "currentColor"), o.setAttribute("stroke-width", "1"), n.appendChild(o);
|
|
536
542
|
}
|
|
537
543
|
drawRect(e, t, s, r) {
|
|
538
|
-
const n = document.createElementNS(
|
|
539
|
-
return n.setAttribute("width", e.toString()), n.setAttribute("height", t.toString()), n.setAttribute("x", (r?.x ?? 0).toString()), n.setAttribute("y", (r?.y ?? 0).toString()), r?.fill ? n.setAttribute("fill", r.fill) : n.setAttribute("fill", "currentColor"), s.appendChild(n), n;
|
|
544
|
+
const n = document.createElementNS(A, "rect");
|
|
545
|
+
return n.setAttribute("width", e.toString()), n.setAttribute("height", t.toString()), n.setAttribute("x", (r?.x ?? 0).toString()), n.setAttribute("y", (r?.y ?? 0).toString()), r?.fill ? n.setAttribute("fill", r.fill) : n.setAttribute("fill", "currentColor"), r?.rx && n.setAttribute("rx", r.rx.toString()), r?.classes && this.addNamespacedClassesToElement(r.classes, n), s.appendChild(n), n;
|
|
540
546
|
}
|
|
541
547
|
drawGlyph(e, t, s) {
|
|
542
548
|
s = {
|
|
@@ -544,14 +550,22 @@ class b {
|
|
|
544
550
|
yOffset: 0,
|
|
545
551
|
...s
|
|
546
552
|
};
|
|
547
|
-
const r = document.createElementNS(
|
|
553
|
+
const r = document.createElementNS(A, "use");
|
|
548
554
|
r.setAttribute("href", `#glyph-${e}`), (s.xOffset || s.yOffset) && r.setAttribute("transform", `translate(${s.xOffset}, ${s.yOffset})`), t.appendChild(r);
|
|
549
555
|
}
|
|
556
|
+
drawCircle(e, t, s, r, n) {
|
|
557
|
+
const o = document.createElementNS(A, "circle");
|
|
558
|
+
return o.setAttribute("cx", e.toString()), o.setAttribute("cy", t.toString()), o.setAttribute("r", s.toString()), n?.filled === !1 ? (o.setAttribute("fill", "none"), o.setAttribute("stroke", "currentColor"), o.setAttribute("stroke-width", (n?.strokeWidth ?? 1.5).toString())) : o.setAttribute("fill", n?.fill ?? "currentColor"), n?.classes && this.addNamespacedClassesToElement(n.classes, o), r.appendChild(o), o;
|
|
559
|
+
}
|
|
560
|
+
drawText(e, t, s, r, n) {
|
|
561
|
+
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;
|
|
563
|
+
}
|
|
550
564
|
destroy() {
|
|
551
565
|
this.rootElementRef && this.svgElementRef && this.rootElementRef.contains(this.svgElementRef) && this.rootElementRef.removeChild(this.svgElementRef);
|
|
552
566
|
}
|
|
553
567
|
}
|
|
554
|
-
const
|
|
568
|
+
const Ct = [
|
|
555
569
|
"CLEF_TREBLE",
|
|
556
570
|
"CLEF_BASS",
|
|
557
571
|
"CLEF_ALTO",
|
|
@@ -566,7 +580,7 @@ const j = [
|
|
|
566
580
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
567
581
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
568
582
|
];
|
|
569
|
-
class
|
|
583
|
+
class bt {
|
|
570
584
|
svgRendererInstance;
|
|
571
585
|
strategyInstance;
|
|
572
586
|
noteRendererInstance;
|
|
@@ -591,32 +605,32 @@ class et {
|
|
|
591
605
|
staffColor: "black",
|
|
592
606
|
staffBackgroundColor: "transparent",
|
|
593
607
|
...t
|
|
594
|
-
}, this.svgRendererInstance = new
|
|
608
|
+
}, this.svgRendererInstance = new w(e, {
|
|
595
609
|
width: this.options.width,
|
|
596
610
|
height: 100,
|
|
597
611
|
scale: this.options.scale,
|
|
598
612
|
staffColor: this.options.staffColor,
|
|
599
613
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
600
|
-
useGlyphs:
|
|
614
|
+
useGlyphs: Ct
|
|
601
615
|
});
|
|
602
616
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
603
617
|
switch (this.options.staffType) {
|
|
604
618
|
case "grand":
|
|
605
|
-
this.strategyInstance = new
|
|
619
|
+
this.strategyInstance = new ot(this.svgRendererInstance, "grand");
|
|
606
620
|
break;
|
|
607
621
|
case "bass":
|
|
608
|
-
this.strategyInstance = new
|
|
622
|
+
this.strategyInstance = new m(this.svgRendererInstance, "bass");
|
|
609
623
|
break;
|
|
610
624
|
case "treble":
|
|
611
|
-
this.strategyInstance = new
|
|
625
|
+
this.strategyInstance = new m(this.svgRendererInstance, "treble");
|
|
612
626
|
break;
|
|
613
627
|
case "alto":
|
|
614
|
-
this.strategyInstance = new
|
|
628
|
+
this.strategyInstance = new m(this.svgRendererInstance, "alto");
|
|
615
629
|
break;
|
|
616
630
|
default:
|
|
617
631
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
618
632
|
}
|
|
619
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
633
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new it(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
620
634
|
const n = this.options.spaceAbove * 10;
|
|
621
635
|
this.svgRendererInstance.addTotalRootSvgYOffset(n);
|
|
622
636
|
}
|
|
@@ -628,7 +642,7 @@ class et {
|
|
|
628
642
|
this.options.keySignature && (r = this.createKeySignature(this.options.keySignature)), this.noteStartX = 38 + this.options.noteStartX + r, this.svgRendererInstance.getLayerByName("notes").setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
629
643
|
}
|
|
630
644
|
createKeySignature(e) {
|
|
631
|
-
return
|
|
645
|
+
return At(this.svgRendererInstance, this.strategyInstance, e, Et);
|
|
632
646
|
}
|
|
633
647
|
/**
|
|
634
648
|
* Draws a note on the staff.
|
|
@@ -656,8 +670,8 @@ class et {
|
|
|
656
670
|
let o;
|
|
657
671
|
try {
|
|
658
672
|
o = this.noteRendererInstance.renderNote(n);
|
|
659
|
-
} catch (
|
|
660
|
-
throw r.length > 0 && this.svgRendererInstance.commitElementsToDOM(r, s),
|
|
673
|
+
} catch (i) {
|
|
674
|
+
throw r.length > 0 && this.svgRendererInstance.commitElementsToDOM(r, s), i;
|
|
661
675
|
}
|
|
662
676
|
o.noteGroup.setAttribute("transform", `translate(${this.noteCursorX + o.accidentalOffset}, ${o.noteYPos})`), this.noteEntries.push({
|
|
663
677
|
gElement: o.noteGroup,
|
|
@@ -689,7 +703,7 @@ class et {
|
|
|
689
703
|
const t = this.svgRendererInstance.getLayerByName("notes"), s = this.noteRendererInstance.renderChord(e);
|
|
690
704
|
s.noteGroup.setAttribute("transform", `translate(${this.noteCursorX + s.accidentalOffset}, 0)`), this.noteEntries.push({
|
|
691
705
|
gElement: s.noteGroup,
|
|
692
|
-
note:
|
|
706
|
+
note: U(e[0]),
|
|
693
707
|
xPos: this.noteCursorX + s.accidentalOffset,
|
|
694
708
|
yPos: 0,
|
|
695
709
|
accidentalXOffset: s.accidentalOffset
|
|
@@ -704,15 +718,15 @@ class et {
|
|
|
704
718
|
if (t <= 0 || e <= 0) return;
|
|
705
719
|
const s = Math.round(e / t);
|
|
706
720
|
this.noteEntries.map((n, o) => {
|
|
707
|
-
const
|
|
721
|
+
const i = (o + 0.5) * s, a = n.gElement.getBBox(), c = i - a.width / 2 - a.x, l = Math.round(c * 10) / 10;
|
|
708
722
|
return {
|
|
709
723
|
entry: n,
|
|
710
724
|
newX: l,
|
|
711
725
|
isChord: n.gElement.classList.contains("chord")
|
|
712
726
|
};
|
|
713
727
|
}).forEach((n) => {
|
|
714
|
-
const { entry: o, newX:
|
|
715
|
-
|
|
728
|
+
const { entry: o, newX: i, isChord: a } = n;
|
|
729
|
+
a ? o.gElement.setAttribute("transform", `translate(${i}, 0)`) : o.gElement.setAttribute("transform", `translate(${i}, ${o.yPos})`), o.xPos = i;
|
|
716
730
|
});
|
|
717
731
|
}
|
|
718
732
|
/**
|
|
@@ -771,7 +785,7 @@ class et {
|
|
|
771
785
|
const s = this.noteEntries[t], r = this.noteRendererInstance.renderChord(e), o = s.xPos - s.accidentalXOffset + r.accidentalOffset;
|
|
772
786
|
r.noteGroup.setAttribute("transform", `translate(${o}, 0)`), this.svgRendererInstance.getLayerByName("notes").replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
773
787
|
gElement: r.noteGroup,
|
|
774
|
-
note:
|
|
788
|
+
note: U(e[0]),
|
|
775
789
|
xPos: o,
|
|
776
790
|
yPos: 0,
|
|
777
791
|
accidentalXOffset: r.accidentalOffset
|
|
@@ -807,7 +821,7 @@ class et {
|
|
|
807
821
|
this.noteEntries = [], this.svgRendererInstance.destroy();
|
|
808
822
|
}
|
|
809
823
|
}
|
|
810
|
-
const
|
|
824
|
+
const I = 30, J = 19, F = 12, St = 4, Nt = 6, tt = 1, D = 38, Lt = [
|
|
811
825
|
"TIME_4",
|
|
812
826
|
"TIME_3",
|
|
813
827
|
"NOTE_HEAD_WHOLE",
|
|
@@ -819,7 +833,7 @@ const d = 30, H = 19, g = 12, K = 4, Q = 6, P = 1, m = 38, z = [
|
|
|
819
833
|
"REST_QUARTER",
|
|
820
834
|
"REST_EIGHTH"
|
|
821
835
|
];
|
|
822
|
-
class
|
|
836
|
+
class Gt {
|
|
823
837
|
rendererInstance;
|
|
824
838
|
options;
|
|
825
839
|
barSpacing;
|
|
@@ -830,7 +844,7 @@ class st {
|
|
|
830
844
|
currentBeatCount = 0;
|
|
831
845
|
currentBeatUICount = 0;
|
|
832
846
|
currentBeatUIElement = null;
|
|
833
|
-
currentBeatUIXPos =
|
|
847
|
+
currentBeatUIXPos = D;
|
|
834
848
|
/**
|
|
835
849
|
* Creates an instance of a RhythmStaff, A single staff that will automatically apply positioning of elements based on the duration of a note.
|
|
836
850
|
*
|
|
@@ -850,13 +864,13 @@ class st {
|
|
|
850
864
|
staffBackgroundColor: "white",
|
|
851
865
|
currentBeatUIColor: "#24ff7450",
|
|
852
866
|
...t
|
|
853
|
-
}, this.rendererInstance = new
|
|
867
|
+
}, this.rendererInstance = new w(e, {
|
|
854
868
|
width: this.options.width,
|
|
855
869
|
height: 100,
|
|
856
870
|
scale: this.options.scale,
|
|
857
871
|
staffColor: this.options.staffColor,
|
|
858
872
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
859
|
-
useGlyphs:
|
|
873
|
+
useGlyphs: Lt
|
|
860
874
|
});
|
|
861
875
|
const s = this.rendererInstance.rootSvgElement;
|
|
862
876
|
let r = "TIME_4";
|
|
@@ -872,41 +886,41 @@ class st {
|
|
|
872
886
|
}
|
|
873
887
|
if (this.options.barsCount < 1 || this.options.barsCount > 3) throw new Error(`Bars count ${this.options.barsCount} not supported. Please use 1 - 3`);
|
|
874
888
|
if (this.options.spaceAbove) {
|
|
875
|
-
const
|
|
876
|
-
this.rendererInstance.addTotalRootSvgYOffset(
|
|
889
|
+
const f = this.options.spaceAbove * 10;
|
|
890
|
+
this.rendererInstance.addTotalRootSvgYOffset(f);
|
|
877
891
|
}
|
|
878
892
|
if (this.options.spaceBelow) {
|
|
879
|
-
let
|
|
880
|
-
this.rendererInstance.addTotalRootSvgHeight(
|
|
893
|
+
let f = this.options.spaceBelow * 10;
|
|
894
|
+
this.rendererInstance.addTotalRootSvgHeight(f);
|
|
881
895
|
}
|
|
882
896
|
const n = this.rendererInstance.getLayerByName("staff");
|
|
883
|
-
this.rendererInstance.addTotalRootSvgHeight(
|
|
897
|
+
this.rendererInstance.addTotalRootSvgHeight(I * 2);
|
|
884
898
|
const o = this.rendererInstance.createGroup("time-signature");
|
|
885
899
|
n.appendChild(o);
|
|
886
|
-
const
|
|
887
|
-
this.rendererInstance.drawGlyph(r, o), this.rendererInstance.drawGlyph("TIME_4", o, { yOffset:
|
|
888
|
-
let
|
|
889
|
-
this.options.barsCount > 1 && (
|
|
900
|
+
const i = I - J;
|
|
901
|
+
this.rendererInstance.drawGlyph(r, o), this.rendererInstance.drawGlyph("TIME_4", o, { yOffset: J }), o.setAttribute("transform", `translate(0, ${i})`);
|
|
902
|
+
let a = this.options.width - 38;
|
|
903
|
+
this.options.barsCount > 1 && (a -= (this.options.barsCount - 1) * F), a -= tt, this.rendererInstance.drawLine(0, I, this.options.width - tt, I, n), this.barSpacing = a / this.options.barsCount, this.quarterNoteSpacing = Math.round(this.barSpacing / this.options.topNumber), this.maxBeatCount = this.options.barsCount * this.options.topNumber;
|
|
890
904
|
let c = this.barSpacing + 38;
|
|
891
|
-
const l =
|
|
892
|
-
for (let
|
|
893
|
-
this.rendererInstance.drawLine(c, l, c,
|
|
894
|
-
this.rendererInstance.getLayerByName("notes").setAttribute("transform", `translate(38, ${
|
|
905
|
+
const l = I / 2, d = I + l;
|
|
906
|
+
for (let f = 0; f < this.options.barsCount - 1; f++)
|
|
907
|
+
this.rendererInstance.drawLine(c, l, c, d, n), c += this.barSpacing;
|
|
908
|
+
this.rendererInstance.getLayerByName("notes").setAttribute("transform", `translate(38, ${I})`), this.rendererInstance.applySizingToRootSvg(), this.rendererInstance.commitElementsToDOM(s);
|
|
895
909
|
}
|
|
896
910
|
createBeatUIElement() {
|
|
897
911
|
const e = this.rendererInstance.getLayerByName("ui");
|
|
898
912
|
this.currentBeatUIElement = this.rendererInstance.drawRect(
|
|
899
913
|
this.quarterNoteSpacing / 2,
|
|
900
|
-
|
|
914
|
+
I * 2,
|
|
901
915
|
e,
|
|
902
916
|
{
|
|
903
|
-
x:
|
|
917
|
+
x: D,
|
|
904
918
|
fill: this.options.currentBeatUIColor
|
|
905
919
|
}
|
|
906
920
|
);
|
|
907
921
|
}
|
|
908
922
|
handleNewBar() {
|
|
909
|
-
this.noteCursorX +=
|
|
923
|
+
this.noteCursorX += F;
|
|
910
924
|
}
|
|
911
925
|
// Translates group, returns cursor increment amount
|
|
912
926
|
translateGroupByDuration(e, t) {
|
|
@@ -966,14 +980,14 @@ class st {
|
|
|
966
980
|
for (; s > 0; ) {
|
|
967
981
|
const r = this.rendererInstance.createGroup("rest");
|
|
968
982
|
let n = 0;
|
|
969
|
-
s -
|
|
983
|
+
s - p.h >= 0 ? (this.rendererInstance.drawGlyph("REST_HALF", r), n = p.h) : s - p.q >= 0 ? (this.rendererInstance.drawGlyph("REST_QUARTER", r), n = p.q) : (this.rendererInstance.drawGlyph("REST_EIGHTH", r), n = p.e), s -= n, this.currentBeatCount += n, r.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += n * this.quarterNoteSpacing, t.push(r);
|
|
970
984
|
}
|
|
971
985
|
return t;
|
|
972
986
|
}
|
|
973
987
|
renderBeamRect(e, t, s, r) {
|
|
974
988
|
this.rendererInstance.drawRect(
|
|
975
989
|
e - t,
|
|
976
|
-
|
|
990
|
+
St,
|
|
977
991
|
s,
|
|
978
992
|
{
|
|
979
993
|
x: 10,
|
|
@@ -1005,20 +1019,20 @@ class st {
|
|
|
1005
1019
|
for (const n of t) {
|
|
1006
1020
|
let o = "w";
|
|
1007
1021
|
try {
|
|
1008
|
-
o =
|
|
1009
|
-
} catch (
|
|
1010
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1022
|
+
o = b(n);
|
|
1023
|
+
} catch (d) {
|
|
1024
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), d;
|
|
1011
1025
|
}
|
|
1012
|
-
const
|
|
1026
|
+
const i = p[o];
|
|
1013
1027
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1014
1028
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1015
1029
|
this.checkAndCreateNewBar();
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1018
|
-
r.push(
|
|
1030
|
+
const a = this.checkAndFillBarWithRests(i);
|
|
1031
|
+
a && a.forEach((d) => {
|
|
1032
|
+
r.push(d), this.noteEntries.push(d);
|
|
1019
1033
|
});
|
|
1020
|
-
const c = this.rendererInstance.createGroup("note"), l = this.translateGroupByDuration(
|
|
1021
|
-
this.noteCursorX += l, this.currentBeatCount +=
|
|
1034
|
+
const c = this.rendererInstance.createGroup("note"), l = this.translateGroupByDuration(i, c);
|
|
1035
|
+
this.noteCursorX += l, this.currentBeatCount += i, this.renderNote(o, c), r.push(c), this.noteEntries.push(c);
|
|
1022
1036
|
}
|
|
1023
1037
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1024
1038
|
}
|
|
@@ -1045,18 +1059,18 @@ class st {
|
|
|
1045
1059
|
for (const n of t) {
|
|
1046
1060
|
let o = "w";
|
|
1047
1061
|
try {
|
|
1048
|
-
o =
|
|
1049
|
-
} catch (
|
|
1050
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1062
|
+
o = b(n);
|
|
1063
|
+
} catch (d) {
|
|
1064
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), d;
|
|
1051
1065
|
}
|
|
1052
|
-
const
|
|
1066
|
+
const i = this.rendererInstance.createGroup("rest"), a = p[o], c = a * this.quarterNoteSpacing;
|
|
1053
1067
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1054
1068
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1055
1069
|
this.checkAndCreateNewBar();
|
|
1056
|
-
const l = this.checkAndFillBarWithRests(
|
|
1057
|
-
l && l.forEach((
|
|
1058
|
-
r.push(
|
|
1059
|
-
}), this.renderRest(o,
|
|
1070
|
+
const l = this.checkAndFillBarWithRests(a);
|
|
1071
|
+
l && l.forEach((d) => {
|
|
1072
|
+
r.push(d), this.noteEntries.push(d);
|
|
1073
|
+
}), this.renderRest(o, i), i.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += c, this.currentBeatCount += a, r.push(i), this.noteEntries.push(i);
|
|
1060
1074
|
}
|
|
1061
1075
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1062
1076
|
}
|
|
@@ -1083,13 +1097,13 @@ class st {
|
|
|
1083
1097
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1084
1098
|
throw new Error("Max beat count reached. Can't add additional beamed note.");
|
|
1085
1099
|
let s = "s";
|
|
1086
|
-
e === "s" ? s = "s" : s =
|
|
1087
|
-
const r = this.rendererInstance.getLayerByName("notes"), n =
|
|
1100
|
+
e === "s" ? s = "s" : s = b(e), this.checkAndCreateNewBar();
|
|
1101
|
+
const r = this.rendererInstance.getLayerByName("notes"), n = p[s], o = n * this.quarterNoteSpacing, i = this.options.topNumber - this.currentBeatCount % this.options.topNumber, a = Math.min(t, i / n), c = this.rendererInstance.createGroup("beamed-note");
|
|
1088
1102
|
c.setAttribute("transform", `translate(${this.noteCursorX}, 0)`);
|
|
1089
1103
|
let l = 0;
|
|
1090
|
-
for (let
|
|
1104
|
+
for (let d = 0; d < a; d++)
|
|
1091
1105
|
this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER", c, { xOffset: l }), this.drawStem(c, l), l += o, this.currentBeatCount += n;
|
|
1092
|
-
this.renderBeamRect(l, o, c), e === "s" && this.renderBeamRect(l, o, c,
|
|
1106
|
+
this.renderBeamRect(l, o, c), e === "s" && this.renderBeamRect(l, o, c, Nt), this.noteCursorX += l, this.noteEntries.push(c), this.rendererInstance.commitElementsToDOM(c, r);
|
|
1093
1107
|
}
|
|
1094
1108
|
/**
|
|
1095
1109
|
* Will increment the UI showing the current beat in quarters. Once exceeded, must be reset with `resetCurrentBeatUI()`
|
|
@@ -1100,14 +1114,14 @@ class st {
|
|
|
1100
1114
|
this.currentBeatUIElement.setAttribute("display", "none");
|
|
1101
1115
|
return;
|
|
1102
1116
|
}
|
|
1103
|
-
this.currentBeatUIElement?.getAttribute("display") === "none" && this.currentBeatUIElement.removeAttribute("display"), this.currentBeatUICount++, this.currentBeatUICount > this.options.topNumber && this.currentBeatUICount % this.options.topNumber === 1 && (this.currentBeatUIXPos +=
|
|
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 += F), this.currentBeatUICount > 1 && (this.currentBeatUIXPos += this.quarterNoteSpacing), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString());
|
|
1104
1118
|
}
|
|
1105
1119
|
/**
|
|
1106
1120
|
* Resets the ui showing the current beat value.
|
|
1107
1121
|
* @returns void
|
|
1108
1122
|
*/
|
|
1109
1123
|
resetCurrentBeatUI() {
|
|
1110
|
-
this.currentBeatUICount = 0, this.currentBeatUIXPos =
|
|
1124
|
+
this.currentBeatUICount = 0, this.currentBeatUIXPos = D, this.currentBeatUIElement && (this.currentBeatUIElement.setAttribute("display", "none"), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString()));
|
|
1111
1125
|
}
|
|
1112
1126
|
/**
|
|
1113
1127
|
* Clears staff of notes and resets internal positioning.
|
|
@@ -1124,7 +1138,7 @@ class st {
|
|
|
1124
1138
|
this.noteEntries = [], this.rendererInstance.destroy();
|
|
1125
1139
|
}
|
|
1126
1140
|
}
|
|
1127
|
-
const
|
|
1141
|
+
const Rt = [
|
|
1128
1142
|
"CLEF_TREBLE",
|
|
1129
1143
|
"CLEF_BASS",
|
|
1130
1144
|
"CLEF_ALTO",
|
|
@@ -1138,8 +1152,8 @@ const J = [
|
|
|
1138
1152
|
"ACCIDENTAL_NATURAL",
|
|
1139
1153
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
1140
1154
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
1141
|
-
],
|
|
1142
|
-
class
|
|
1155
|
+
], y = 60, yt = y;
|
|
1156
|
+
class vt {
|
|
1143
1157
|
svgRendererInstance;
|
|
1144
1158
|
strategyInstance;
|
|
1145
1159
|
noteRendererInstance;
|
|
@@ -1166,32 +1180,32 @@ class rt {
|
|
|
1166
1180
|
staffColor: "black",
|
|
1167
1181
|
staffBackgroundColor: "transparent",
|
|
1168
1182
|
...t
|
|
1169
|
-
}, this.svgRendererInstance = new
|
|
1183
|
+
}, this.svgRendererInstance = new w(e, {
|
|
1170
1184
|
width: this.options.width,
|
|
1171
1185
|
height: 100,
|
|
1172
1186
|
scale: this.options.scale,
|
|
1173
1187
|
staffColor: this.options.staffColor,
|
|
1174
1188
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
1175
|
-
useGlyphs:
|
|
1189
|
+
useGlyphs: Rt
|
|
1176
1190
|
});
|
|
1177
1191
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1178
1192
|
switch (this.options.staffType) {
|
|
1179
1193
|
case "grand":
|
|
1180
|
-
this.strategyInstance = new
|
|
1194
|
+
this.strategyInstance = new ot(this.svgRendererInstance, "grand");
|
|
1181
1195
|
break;
|
|
1182
1196
|
case "bass":
|
|
1183
|
-
this.strategyInstance = new
|
|
1197
|
+
this.strategyInstance = new m(this.svgRendererInstance, "bass");
|
|
1184
1198
|
break;
|
|
1185
1199
|
case "treble":
|
|
1186
|
-
this.strategyInstance = new
|
|
1200
|
+
this.strategyInstance = new m(this.svgRendererInstance, "treble");
|
|
1187
1201
|
break;
|
|
1188
1202
|
case "alto":
|
|
1189
|
-
this.strategyInstance = new
|
|
1203
|
+
this.strategyInstance = new m(this.svgRendererInstance, "alto");
|
|
1190
1204
|
break;
|
|
1191
1205
|
default:
|
|
1192
1206
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
1193
1207
|
}
|
|
1194
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
1208
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new it(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
1195
1209
|
const r = this.options.spaceAbove * 10;
|
|
1196
1210
|
this.svgRendererInstance.addTotalRootSvgYOffset(r);
|
|
1197
1211
|
}
|
|
@@ -1202,10 +1216,10 @@ class rt {
|
|
|
1202
1216
|
this.notesLayer = this.svgRendererInstance.getLayerByName("notes"), this.notesLayer.classList.add("vs-scrolling-notes-layer"), this.noteStartX = 38 + this.options.noteStartX, this.svgRendererInstance.getLayerByName("notes").setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
1203
1217
|
}
|
|
1204
1218
|
renderFirstNoteGroups() {
|
|
1205
|
-
const e = this.options.width - this.options.noteStartX +
|
|
1219
|
+
const e = this.options.width - this.options.noteStartX + yt;
|
|
1206
1220
|
for (; this.noteBuffer.length > 0 && this.noteCursorX < e; )
|
|
1207
|
-
this.renderNextNote(), this.noteCursorX +=
|
|
1208
|
-
this.activeEntries.length > 1 && (this.noteCursorX -=
|
|
1221
|
+
this.renderNextNote(), this.noteCursorX += y;
|
|
1222
|
+
this.activeEntries.length > 1 && (this.noteCursorX -= y);
|
|
1209
1223
|
}
|
|
1210
1224
|
renderNextNote() {
|
|
1211
1225
|
if (this.noteBuffer.length < 1) return;
|
|
@@ -1264,7 +1278,7 @@ class rt {
|
|
|
1264
1278
|
return;
|
|
1265
1279
|
}
|
|
1266
1280
|
this.activeEntries.forEach((t) => {
|
|
1267
|
-
t.xPos -=
|
|
1281
|
+
t.xPos -= y, t.noteWrapper.style.transform = `translate(${t.xPos}px, 0px)`;
|
|
1268
1282
|
});
|
|
1269
1283
|
const e = this.activeEntries[0];
|
|
1270
1284
|
e.xPos <= 0 && (this.notesLayer.removeChild(e.noteWrapper), this.activeEntries.shift()), this.renderNextNote();
|
|
@@ -1284,8 +1298,321 @@ class rt {
|
|
|
1284
1298
|
this.svgRendererInstance.destroy(), this.activeEntries = [], this.noteBuffer = [];
|
|
1285
1299
|
}
|
|
1286
1300
|
}
|
|
1301
|
+
const wt = /^[xX\da-zA-Z]+$/, Ot = /^[\d]+$/;
|
|
1302
|
+
function et(h, e) {
|
|
1303
|
+
const t = [];
|
|
1304
|
+
for (let s = 0; s < h.length; s++)
|
|
1305
|
+
t.push({
|
|
1306
|
+
fret: h[s],
|
|
1307
|
+
finger: e[s]
|
|
1308
|
+
});
|
|
1309
|
+
return t;
|
|
1310
|
+
}
|
|
1311
|
+
function st(h, e) {
|
|
1312
|
+
const t = h.filter((n) => n.toLowerCase() !== "x" && n !== "0").map((n) => parseInt(n, 36));
|
|
1313
|
+
if (t.length === 0) return 1;
|
|
1314
|
+
const s = Math.min(...t);
|
|
1315
|
+
return Math.max(...t) <= e ? 1 : s;
|
|
1316
|
+
}
|
|
1317
|
+
function H(h) {
|
|
1318
|
+
if (!wt.test(h)) throw new Error("Invalid frets string. Only 'x', 'X', and digits are allowed.");
|
|
1319
|
+
return h.split("");
|
|
1320
|
+
}
|
|
1321
|
+
function B(h) {
|
|
1322
|
+
if (!Ot.test(h)) throw new Error("Invalid fingers string. Only digits are allowed.");
|
|
1323
|
+
return h.split("");
|
|
1324
|
+
}
|
|
1325
|
+
class Ft {
|
|
1326
|
+
svgRendererInstance;
|
|
1327
|
+
options;
|
|
1328
|
+
chordEntries = [];
|
|
1329
|
+
cursorX = 0;
|
|
1330
|
+
cursorY = 0;
|
|
1331
|
+
diagramWidth;
|
|
1332
|
+
diagramHeight;
|
|
1333
|
+
gridTopY;
|
|
1334
|
+
rowHeight;
|
|
1335
|
+
/**
|
|
1336
|
+
* Creates an instance of a GuitarChord diagram renderer.
|
|
1337
|
+
*
|
|
1338
|
+
* @param rootElementCtx - The element (div) reference that the chord diagram(s) will be appended to.
|
|
1339
|
+
* @param options - Optional configuration. Can adjust total width, scale, string/fret count, and coloring.
|
|
1340
|
+
* All config options are in the type GuitarChordOptions.
|
|
1341
|
+
*/
|
|
1342
|
+
constructor(e, t) {
|
|
1343
|
+
if (this.options = {
|
|
1344
|
+
stringCount: at,
|
|
1345
|
+
fretCount: ct,
|
|
1346
|
+
stringLabels: [],
|
|
1347
|
+
inlineChordsAmount: 2,
|
|
1348
|
+
scale: 1,
|
|
1349
|
+
color: "black",
|
|
1350
|
+
backgroundColor: "transparent",
|
|
1351
|
+
...t
|
|
1352
|
+
}, this.diagramWidth = (this.options.stringCount - 1) * _, this.diagramHeight = this.options.fretCount * T, this.gridTopY = Z + W, this.rowHeight = this.gridTopY + this.diagramHeight + $, t?.width ? this.options.width = t.width : this.options.width = (this.diagramWidth + M) * this.options.inlineChordsAmount, this.options.stringLabels.length >= 1 && (this.rowHeight += lt + ht), this.diagramWidth > this.options.width)
|
|
1353
|
+
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 w(e, {
|
|
1355
|
+
width: this.options.width,
|
|
1356
|
+
height: 100,
|
|
1357
|
+
scale: this.options.scale,
|
|
1358
|
+
staffColor: this.options.color,
|
|
1359
|
+
staffBackgroundColor: this.options.backgroundColor,
|
|
1360
|
+
useGlyphs: []
|
|
1361
|
+
});
|
|
1362
|
+
const s = this.svgRendererInstance.rootSvgElement;
|
|
1363
|
+
this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
1364
|
+
}
|
|
1365
|
+
getDotsToHide(e) {
|
|
1366
|
+
const t = /* @__PURE__ */ new Set();
|
|
1367
|
+
return e && e.forEach((s) => {
|
|
1368
|
+
const r = s.fromString - 1, n = s.toString - 1;
|
|
1369
|
+
for (let o = r; o <= n; o++)
|
|
1370
|
+
t.add(`${o}-${s.fret}`);
|
|
1371
|
+
}), t;
|
|
1372
|
+
}
|
|
1373
|
+
drawFretDots(e, t, s, r, n) {
|
|
1374
|
+
const o = this.gridTopY - W / 2;
|
|
1375
|
+
for (let i = 0; i < this.options.stringCount; i++) {
|
|
1376
|
+
const a = i * _, c = e[i].toLowerCase(), l = t[i];
|
|
1377
|
+
if (c === "x")
|
|
1378
|
+
this.svgRendererInstance.drawLine(a - g, o - g, a + g, o + g, n), this.svgRendererInstance.drawLine(a - g, o + g, a + g, o - g, n);
|
|
1379
|
+
else if (c === "0")
|
|
1380
|
+
this.svgRendererInstance.drawCircle(a, o, g, n, { filled: !1 });
|
|
1381
|
+
else {
|
|
1382
|
+
const d = parseInt(c, 36);
|
|
1383
|
+
if (r.has(`${i}-${d}`))
|
|
1384
|
+
continue;
|
|
1385
|
+
const f = d - s + 1;
|
|
1386
|
+
if (f < 1 || f > this.options.fretCount)
|
|
1387
|
+
throw new Error(`Fret ${c} on string ${i + 1} is outside the visible range (${s}-${s + this.options.fretCount - 1}). Adjust 'startFret' or 'fretCount'.`);
|
|
1388
|
+
const C = this.gridTopY + (f - 0.5) * T;
|
|
1389
|
+
if (this.svgRendererInstance.drawCircle(a, C, u, n, {
|
|
1390
|
+
classes: "guitar-fret-dot"
|
|
1391
|
+
}), l !== "0") {
|
|
1392
|
+
const E = this.options.backgroundColor === "transparent" ? "white" : this.options.backgroundColor;
|
|
1393
|
+
this.svgRendererInstance.drawText(l, a, C + S / 3, n, {
|
|
1394
|
+
fontSize: S,
|
|
1395
|
+
fill: E,
|
|
1396
|
+
classes: "guitar-text-small"
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
drawStringLabels(e, t) {
|
|
1403
|
+
if (!t || t.length === 0) return;
|
|
1404
|
+
const s = u, r = this.rowHeight - s - $;
|
|
1405
|
+
for (let n = 0; n < this.options.stringCount; n++) {
|
|
1406
|
+
const o = t[n];
|
|
1407
|
+
if (!o) continue;
|
|
1408
|
+
const i = n * _, a = r + s / 2;
|
|
1409
|
+
this.svgRendererInstance.drawText(o, i, a, e, {
|
|
1410
|
+
fontSize: S,
|
|
1411
|
+
classes: "guitar-text-small"
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
// Passed in 'from' and 'to' index values are zero-based
|
|
1416
|
+
drawBarre(e, t) {
|
|
1417
|
+
const s = t.fret;
|
|
1418
|
+
if (t.fromIndex < 0 || t.toIndex >= this.options.stringCount || t.fromIndex >= t.toIndex)
|
|
1419
|
+
throw new Error(`Barre fret error: Invalid string range ${t.fromIndex + 1}:${t.toIndex + 1}.`);
|
|
1420
|
+
if (s < t.startingFret || s > t.startingFret + (this.options.fretCount - 1))
|
|
1421
|
+
throw new Error(`Barre fret error: ${t.fret} is outside the visible range.`);
|
|
1422
|
+
const r = s - t.startingFret, n = t.fromIndex * _, o = t.toIndex * _, i = u * 2, a = o - n + i, c = this.gridTopY + u / 2 + T * r, l = this.gridTopY + T * r + u * 2;
|
|
1423
|
+
if (this.svgRendererInstance.drawRect(a, i, e, {
|
|
1424
|
+
x: n - u,
|
|
1425
|
+
y: c,
|
|
1426
|
+
rx: u,
|
|
1427
|
+
classes: "guitar-barre"
|
|
1428
|
+
}), t.finger) {
|
|
1429
|
+
const d = this.options.backgroundColor === "transparent" ? "white" : this.options.backgroundColor;
|
|
1430
|
+
this.svgRendererInstance.drawText(t.finger.toString(), (n + o) / 2, l, e, {
|
|
1431
|
+
fontSize: S,
|
|
1432
|
+
fill: d,
|
|
1433
|
+
classes: "guitar-text-small"
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
// Builds a single chord diagram's group element: grid, nut/fret-position label, and per-string markers.
|
|
1438
|
+
renderChordDiagram(e, t, s) {
|
|
1439
|
+
const r = this.svgRendererInstance.createGroup("chord"), n = s?.startFret ?? 1;
|
|
1440
|
+
s?.label && this.svgRendererInstance.drawText(s.label, this.diagramWidth / 2, Z - 5, r, {
|
|
1441
|
+
fontSize: rt,
|
|
1442
|
+
fontWeight: "bold",
|
|
1443
|
+
classes: "guitar-text-base"
|
|
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, {
|
|
1453
|
+
anchor: "start",
|
|
1454
|
+
fontSize: S,
|
|
1455
|
+
fontWeight: "bold",
|
|
1456
|
+
classes: "guitar-text-small"
|
|
1457
|
+
});
|
|
1458
|
+
for (let i = 0; i < this.options.stringCount; i++) {
|
|
1459
|
+
const a = i * _;
|
|
1460
|
+
this.svgRendererInstance.drawLine(a, this.gridTopY, a, this.gridTopY + this.diagramHeight, r);
|
|
1461
|
+
}
|
|
1462
|
+
const o = this.getDotsToHide(s?.barres);
|
|
1463
|
+
return this.drawFretDots(e, t, n, o, r), this.options.stringLabels.length >= 1 && this.drawStringLabels(r, this.options.stringLabels), s?.barres?.forEach((i) => {
|
|
1464
|
+
this.drawBarre(r, {
|
|
1465
|
+
fromIndex: i.fromString - 1,
|
|
1466
|
+
toIndex: i.toString - 1,
|
|
1467
|
+
fret: i.fret,
|
|
1468
|
+
finger: i.finger,
|
|
1469
|
+
startingFret: n
|
|
1470
|
+
});
|
|
1471
|
+
}), r;
|
|
1472
|
+
}
|
|
1473
|
+
// 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 incremental deltas.
|
|
1475
|
+
relayoutChords() {
|
|
1476
|
+
if (this.cursorX = u, this.cursorY = ft, this.chordEntries.length === 1) {
|
|
1477
|
+
const t = this.chordEntries[0];
|
|
1478
|
+
this.cursorX = this.options.width / 2 - this.diagramWidth / 2, t.xPos = this.cursorX, t.yPos = this.cursorY, t.gElement.setAttribute("transform", `translate(${this.cursorX}, ${this.cursorY})`);
|
|
1479
|
+
} else
|
|
1480
|
+
this.chordEntries.forEach((t, s) => {
|
|
1481
|
+
s > 0 && this.cursorX + this.diagramWidth > this.options.width && (this.cursorX = u, this.cursorY += this.rowHeight + dt), t.xPos = this.cursorX, t.yPos = this.cursorY, t.gElement.setAttribute("transform", `translate(${this.cursorX}, ${this.cursorY})`), this.cursorX += this.diagramWidth + M;
|
|
1482
|
+
});
|
|
1483
|
+
const e = this.cursorY + this.rowHeight;
|
|
1484
|
+
this.svgRendererInstance.setTotalRootSvgHeight(e), this.svgRendererInstance.applySizingToRootSvg();
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Adds a new chord diagram. Diagrams are placed left-to-right in the order added, wrapping to a
|
|
1488
|
+
* new row automatically once the configured width is exceeded.
|
|
1489
|
+
*
|
|
1490
|
+
* @param frets - A string, with each value being ordered low-to-high (e.g. first position in string 0 is the low E string)
|
|
1491
|
+
* * `x` - muted string
|
|
1492
|
+
* * `0` - open string
|
|
1493
|
+
* * `1...n` - fretted at the given absolute fret number (e.g. `3`)
|
|
1494
|
+
* @param fingers - A string, with each value being ordered low-to-high (e.g. first position in string 0 is the low E string)
|
|
1495
|
+
* * `0` - No finger labeled
|
|
1496
|
+
* * `1...n` - Finger labeled as number provided
|
|
1497
|
+
*
|
|
1498
|
+
* @param options - Optional per-chord settings: `startFret` (default `1`, for diagrams higher up the neck)
|
|
1499
|
+
* and `label` (a chord name drawn above the diagram).
|
|
1500
|
+
*
|
|
1501
|
+
* @returns The index of the newly added chord, for later use with the CRUD-by-index methods.
|
|
1502
|
+
*
|
|
1503
|
+
* @throws {Error} If fret or finger's string length doesn't match the configured string count.
|
|
1504
|
+
*
|
|
1505
|
+
* @example
|
|
1506
|
+
* // Draw an open C major chord
|
|
1507
|
+
* guitarChord.addChord("x32010", "032010", { label: "C" });
|
|
1508
|
+
*/
|
|
1509
|
+
addChord(e, t, s) {
|
|
1510
|
+
const r = H(e), n = B(t);
|
|
1511
|
+
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
|
+
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 ?? st(r, this.options.fretCount), i = s?.label, a = s?.barres, c = { startFret: o, label: i, barres: a }, l = this.renderChordDiagram(r, n, c), d = this.svgRendererInstance.getLayerByName("notes");
|
|
1514
|
+
return this.svgRendererInstance.commitElementsToDOM(l, d), this.chordEntries.push({
|
|
1515
|
+
gElement: l,
|
|
1516
|
+
strings: et(r, n),
|
|
1517
|
+
...c,
|
|
1518
|
+
xPos: 0,
|
|
1519
|
+
yPos: 0
|
|
1520
|
+
}), this.relayoutChords(), this.chordEntries.length - 1;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Replaces the chord diagram at the specified index with a new one, in place.
|
|
1524
|
+
*
|
|
1525
|
+
* @param frets - A string, with each value being ordered low-to-high (e.g. first position in string 0 is the low E string)
|
|
1526
|
+
* * `x` - muted string
|
|
1527
|
+
* * `0` - open string
|
|
1528
|
+
* * `1...n` - fretted at the given absolute fret number (e.g. `3`)
|
|
1529
|
+
* @param fingers - A string, with each value being ordered low-to-high (e.g. first position in string 0 is the low E string)
|
|
1530
|
+
* * `0` - No finger labeled
|
|
1531
|
+
* * `1...n` - Finger labeled as number provided
|
|
1532
|
+
*
|
|
1533
|
+
* @param chordIndex - The index of the chord to replace (as returned by addChord).
|
|
1534
|
+
*
|
|
1535
|
+
* @param options - Optional per-chord settings, see addChord.
|
|
1536
|
+
*
|
|
1537
|
+
* @returns void
|
|
1538
|
+
*
|
|
1539
|
+
* @throws {Error} If the index is out of bounds, or if chordDef is invalid (see addChord).
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* // Change chord at index 0 to a D major chord
|
|
1543
|
+
* guitarChord.modifyChordByIndex("xx0232", "000132", 0, { label: "D" });
|
|
1544
|
+
*
|
|
1545
|
+
*/
|
|
1546
|
+
modifyChordByIndex(e, t, s, r) {
|
|
1547
|
+
if (s >= this.chordEntries.length || s < 0) throw new Error("Chord index was out of bounds.");
|
|
1548
|
+
const n = H(e), o = B(t);
|
|
1549
|
+
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
|
+
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, c = r?.startFret ?? st(n, this.options.fretCount), l = { ...r, label: a, startFret: c }, d = this.renderChordDiagram(n, o, l);
|
|
1552
|
+
this.svgRendererInstance.getLayerByName("notes").replaceChild(d, i.gElement), this.chordEntries[s] = {
|
|
1553
|
+
gElement: d,
|
|
1554
|
+
strings: et(n, o),
|
|
1555
|
+
...l,
|
|
1556
|
+
xPos: i.xPos,
|
|
1557
|
+
yPos: i.yPos
|
|
1558
|
+
}, this.relayoutChords();
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Removes the chord diagram at the specified index. Remaining chords are re-flowed to close the gap.
|
|
1562
|
+
* @param chordIndex - The index of the chord to remove.
|
|
1563
|
+
* @returns void
|
|
1564
|
+
* @throws {Error} If the index is out of bounds.
|
|
1565
|
+
*/
|
|
1566
|
+
removeChordByIndex(e) {
|
|
1567
|
+
if (e >= this.chordEntries.length || e < 0) throw new Error("Chord index was out of bounds.");
|
|
1568
|
+
this.chordEntries[e].gElement.remove(), this.chordEntries.splice(e, 1), this.relayoutChords();
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Removes all chord diagrams and resets internal positioning.
|
|
1572
|
+
* @returns void
|
|
1573
|
+
*/
|
|
1574
|
+
clearAllChords() {
|
|
1575
|
+
this.svgRendererInstance.getLayerByName("notes").replaceChildren(), this.chordEntries = [], this.cursorX = 0, this.cursorY = 0, this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg();
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* * Used to automatically determine options for creating barre lines.
|
|
1579
|
+
* * The returned value then can be used in addChord and modifyChord methods.
|
|
1580
|
+
* @returns GuitarBarreDef[]
|
|
1581
|
+
*/
|
|
1582
|
+
determineBarreOptions(e, t, s) {
|
|
1583
|
+
const r = H(e), n = B(t), o = [];
|
|
1584
|
+
return s.forEach((i) => {
|
|
1585
|
+
if (i === 0) return;
|
|
1586
|
+
const a = [], c = {};
|
|
1587
|
+
for (let E = 0; E < r.length; E++) {
|
|
1588
|
+
if (r[E].toLowerCase() === "x") continue;
|
|
1589
|
+
const L = parseInt(r[E], 36), O = Number(n[E]);
|
|
1590
|
+
L === i && (c[O] ? c[O] += 1 : c[O] = 1, a.push(E + 1));
|
|
1591
|
+
}
|
|
1592
|
+
a.sort();
|
|
1593
|
+
let l = 0, d = 0;
|
|
1594
|
+
for (const [E, L] of Object.entries(c))
|
|
1595
|
+
L > d && (d = L, l = Number(E));
|
|
1596
|
+
const f = a[0], C = a.at(-1);
|
|
1597
|
+
a.length > 1 && C && o.push({
|
|
1598
|
+
fret: i,
|
|
1599
|
+
fromString: f,
|
|
1600
|
+
toString: C,
|
|
1601
|
+
finger: l
|
|
1602
|
+
});
|
|
1603
|
+
}), o;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Removes the root svg element and cleans up arrays.
|
|
1607
|
+
* @returns void
|
|
1608
|
+
*/
|
|
1609
|
+
destroy() {
|
|
1610
|
+
this.chordEntries = [], this.svgRendererInstance.destroy();
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1287
1613
|
export {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1614
|
+
Ft as GuitarChord,
|
|
1615
|
+
bt as MusicStaff,
|
|
1616
|
+
Gt as RhythmStaff,
|
|
1617
|
+
vt as ScrollingStaff
|
|
1291
1618
|
};
|