vector-score 1.2.1 → 1.3.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 +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 +355 -324
- 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, A = 6, ct = 4, ht = u * 2, L = 51, lt = 12, dt = 4, $ = 1, x = 4, ft = 1, W = A * 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,22 +75,23 @@ 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
|
|
83
|
+
function pt(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
|
-
const
|
|
94
|
+
const At = {
|
|
94
95
|
CLEF_TREBLE: {
|
|
95
96
|
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
97
|
xOffset: 0,
|
|
@@ -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 G = 48,
|
|
232
|
-
class
|
|
232
|
+
const G = 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,16 +249,16 @@ 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);
|
|
@@ -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 < G ? s += 10 : r === G && (s =
|
|
290
|
+
return r < G ? s += 10 : r === G && (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
|
|
464
|
-
class
|
|
464
|
+
const p = "http://www.w3.org/2000/svg", St = 0.1, F = 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,21 +478,36 @@ 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(p, "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
|
-
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(${
|
|
485
|
+
const t = document.createElementNS(p, "defs");
|
|
486
|
+
Object.entries(At).filter(([r]) => e.includes(r)).forEach(([r, n]) => {
|
|
487
|
+
const o = document.createElementNS(p, "path");
|
|
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(p, "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
|
-
const t = document.createElementNS(
|
|
510
|
+
const t = document.createElementNS(p, "g");
|
|
497
511
|
return e && t.classList.add(`vs-${e}`), t;
|
|
498
512
|
}
|
|
499
513
|
commitElementsToDOM(e, t = this.rootElementRef) {
|
|
@@ -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(${F / 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 += F, this.svgElementRef.setAttribute("width", e.toString()), this.svgElementRef.setAttribute("height", t.toString()), this.svgElementRef.setAttribute("viewBox", `0 0 ${this.width + F} ${this.totalHeight + this.totalYOffset}`);
|
|
531
533
|
}
|
|
532
534
|
get rootSvgElement() {
|
|
533
535
|
return this.svgElementRef;
|
|
@@ -536,12 +538,12 @@ 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(
|
|
541
|
-
|
|
541
|
+
drawLine(e, t, s, r, n, o) {
|
|
542
|
+
const i = o?.strokeWidth ?? 1, a = document.createElementNS(p, "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
|
-
const n = document.createElementNS(
|
|
546
|
+
const n = document.createElementNS(p, "rect");
|
|
545
547
|
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;
|
|
546
548
|
}
|
|
547
549
|
drawGlyph(e, t, s) {
|
|
@@ -550,22 +552,22 @@ class w {
|
|
|
550
552
|
yOffset: 0,
|
|
551
553
|
...s
|
|
552
554
|
};
|
|
553
|
-
const r = document.createElementNS(
|
|
555
|
+
const r = document.createElementNS(p, "use");
|
|
554
556
|
r.setAttribute("href", `#glyph-${e}`), (s.xOffset || s.yOffset) && r.setAttribute("transform", `translate(${s.xOffset}, ${s.yOffset})`), t.appendChild(r);
|
|
555
557
|
}
|
|
556
558
|
drawCircle(e, t, s, r, n) {
|
|
557
|
-
const o = document.createElementNS(
|
|
559
|
+
const o = document.createElementNS(p, "circle");
|
|
558
560
|
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
561
|
}
|
|
560
562
|
drawText(e, t, s, r, n) {
|
|
561
|
-
const o = document.createElementNS(
|
|
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
|
+
const o = document.createElementNS(p, "text");
|
|
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
|
|
647
|
+
return pt(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,10 @@ 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})`)
|
|
764
|
+
r.noteGroup.setAttribute("transform", `translate(${o}, ${r.noteYPos})`);
|
|
765
|
+
const i = this.svgRendererInstance.getLayer("notes");
|
|
766
|
+
if (!i) throw new Error("ChangeNoteByIndex Error: Failed to retrieve notesLayer to append notes.");
|
|
767
|
+
i.replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
759
768
|
gElement: r.noteGroup,
|
|
760
769
|
note: r.noteObj,
|
|
761
770
|
xPos: o,
|
|
@@ -783,9 +792,12 @@ class bt {
|
|
|
783
792
|
if (t >= this.noteEntries.length) throw new Error("Chord index was out of bounds.");
|
|
784
793
|
if (e.length < 2) throw new Error("Notes provided need to be more than one to be considered a chord.");
|
|
785
794
|
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)`)
|
|
795
|
+
r.noteGroup.setAttribute("transform", `translate(${o}, 0)`);
|
|
796
|
+
const i = this.svgRendererInstance.getLayer("notes");
|
|
797
|
+
if (!i) throw new Error("DrawNote Error: Failed to retrieve notesLayer to append notes.");
|
|
798
|
+
i.replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
787
799
|
gElement: r.noteGroup,
|
|
788
|
-
note:
|
|
800
|
+
note: Y(e[0]),
|
|
789
801
|
xPos: o,
|
|
790
802
|
yPos: 0,
|
|
791
803
|
accidentalXOffset: r.accidentalOffset
|
|
@@ -821,7 +833,7 @@ class bt {
|
|
|
821
833
|
this.noteEntries = [], this.svgRendererInstance.destroy();
|
|
822
834
|
}
|
|
823
835
|
}
|
|
824
|
-
const
|
|
836
|
+
const _ = 30, Q = 19, D = 12, Ct = 4, Nt = 6, J = 1, H = 38, Lt = [
|
|
825
837
|
"TIME_4",
|
|
826
838
|
"TIME_3",
|
|
827
839
|
"NOTE_HEAD_WHOLE",
|
|
@@ -833,7 +845,7 @@ const I = 30, J = 19, F = 12, St = 4, Nt = 6, tt = 1, D = 38, Lt = [
|
|
|
833
845
|
"REST_QUARTER",
|
|
834
846
|
"REST_EIGHTH"
|
|
835
847
|
];
|
|
836
|
-
class
|
|
848
|
+
class vt {
|
|
837
849
|
rendererInstance;
|
|
838
850
|
options;
|
|
839
851
|
barSpacing;
|
|
@@ -844,7 +856,7 @@ class Gt {
|
|
|
844
856
|
currentBeatCount = 0;
|
|
845
857
|
currentBeatUICount = 0;
|
|
846
858
|
currentBeatUIElement = null;
|
|
847
|
-
currentBeatUIXPos =
|
|
859
|
+
currentBeatUIXPos = H;
|
|
848
860
|
/**
|
|
849
861
|
* Creates an instance of a RhythmStaff, A single staff that will automatically apply positioning of elements based on the duration of a note.
|
|
850
862
|
*
|
|
@@ -860,67 +872,66 @@ class Gt {
|
|
|
860
872
|
barsCount: 2,
|
|
861
873
|
spaceAbove: 0,
|
|
862
874
|
spaceBelow: 0,
|
|
863
|
-
|
|
864
|
-
staffBackgroundColor: "white",
|
|
865
|
-
currentBeatUIColor: "#24ff7450",
|
|
875
|
+
svgAutoFill: !0,
|
|
866
876
|
...t
|
|
867
|
-
}, this.rendererInstance = new
|
|
877
|
+
}, this.rendererInstance = new O(e, {
|
|
868
878
|
width: this.options.width,
|
|
869
879
|
height: 100,
|
|
870
880
|
scale: this.options.scale,
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
useGlyphs: Lt
|
|
881
|
+
useGlyphs: Lt,
|
|
882
|
+
svgAutoFill: this.options.svgAutoFill
|
|
874
883
|
});
|
|
875
|
-
const s = this.rendererInstance.rootSvgElement;
|
|
876
|
-
|
|
884
|
+
const s = this.rendererInstance.rootSvgElement, r = this.rendererInstance.createLayer("staff"), n = this.rendererInstance.createLayer("notes");
|
|
885
|
+
this.rendererInstance.createLayer("ui");
|
|
886
|
+
let o = "TIME_4";
|
|
877
887
|
switch (this.options.topNumber) {
|
|
878
888
|
case 3:
|
|
879
|
-
|
|
889
|
+
o = "TIME_3";
|
|
880
890
|
break;
|
|
881
891
|
case 4:
|
|
882
|
-
|
|
892
|
+
o = "TIME_4";
|
|
883
893
|
break;
|
|
884
894
|
default:
|
|
885
895
|
throw new Error(`Time signature ${this.options.topNumber} not supported. Please use either 3 or 4.`);
|
|
886
896
|
}
|
|
887
897
|
if (this.options.barsCount < 1 || this.options.barsCount > 3) throw new Error(`Bars count ${this.options.barsCount} not supported. Please use 1 - 3`);
|
|
888
898
|
if (this.options.spaceAbove) {
|
|
889
|
-
const
|
|
890
|
-
this.rendererInstance.addTotalRootSvgYOffset(
|
|
899
|
+
const E = this.options.spaceAbove * 10;
|
|
900
|
+
this.rendererInstance.addTotalRootSvgYOffset(E);
|
|
891
901
|
}
|
|
892
902
|
if (this.options.spaceBelow) {
|
|
893
|
-
let
|
|
894
|
-
this.rendererInstance.addTotalRootSvgHeight(
|
|
903
|
+
let E = this.options.spaceBelow * 10;
|
|
904
|
+
this.rendererInstance.addTotalRootSvgHeight(E);
|
|
895
905
|
}
|
|
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);
|
|
906
|
+
this.rendererInstance.addTotalRootSvgHeight(_ * 2);
|
|
907
|
+
const i = this.rendererInstance.createGroup("time-signature");
|
|
908
|
+
r.appendChild(i);
|
|
909
|
+
const a = _ - Q;
|
|
910
|
+
this.rendererInstance.drawGlyph(o, i), this.rendererInstance.drawGlyph("TIME_4", i, { yOffset: Q }), i.setAttribute("transform", `translate(0, ${a})`);
|
|
911
|
+
let h = this.options.width - 38;
|
|
912
|
+
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;
|
|
913
|
+
let d = this.barSpacing + 38;
|
|
914
|
+
const c = _ / 2, f = _ + c;
|
|
915
|
+
for (let E = 0; E < this.options.barsCount - 1; E++)
|
|
916
|
+
this.rendererInstance.drawLine(d, c, d, f, r), d += this.barSpacing;
|
|
917
|
+
n.setAttribute("transform", `translate(38, ${_})`), this.rendererInstance.applySizingToRootSvg(), this.rendererInstance.commitElementsToDOM(s);
|
|
909
918
|
}
|
|
910
919
|
createBeatUIElement() {
|
|
911
|
-
const e = this.rendererInstance.
|
|
920
|
+
const e = this.rendererInstance.getLayer("ui");
|
|
921
|
+
if (!e) throw new Error("BeatUI Error: Failed to retrieve ui layer");
|
|
912
922
|
this.currentBeatUIElement = this.rendererInstance.drawRect(
|
|
913
923
|
this.quarterNoteSpacing / 2,
|
|
914
|
-
|
|
924
|
+
_ * 2,
|
|
915
925
|
e,
|
|
916
926
|
{
|
|
917
|
-
x:
|
|
918
|
-
fill:
|
|
927
|
+
x: H,
|
|
928
|
+
fill: "rgba(0,255,40,0.4)",
|
|
929
|
+
classes: "rhythm-current-beat"
|
|
919
930
|
}
|
|
920
931
|
);
|
|
921
932
|
}
|
|
922
933
|
handleNewBar() {
|
|
923
|
-
this.noteCursorX +=
|
|
934
|
+
this.noteCursorX += D;
|
|
924
935
|
}
|
|
925
936
|
// Translates group, returns cursor increment amount
|
|
926
937
|
translateGroupByDuration(e, t) {
|
|
@@ -980,19 +991,18 @@ class Gt {
|
|
|
980
991
|
for (; s > 0; ) {
|
|
981
992
|
const r = this.rendererInstance.createGroup("rest");
|
|
982
993
|
let n = 0;
|
|
983
|
-
s -
|
|
994
|
+
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
995
|
}
|
|
985
996
|
return t;
|
|
986
997
|
}
|
|
987
998
|
renderBeamRect(e, t, s, r) {
|
|
988
999
|
this.rendererInstance.drawRect(
|
|
989
1000
|
e - t,
|
|
990
|
-
|
|
1001
|
+
Ct,
|
|
991
1002
|
s,
|
|
992
1003
|
{
|
|
993
1004
|
x: 10,
|
|
994
|
-
y: -28 + (r ?? 0)
|
|
995
|
-
fill: this.options.staffColor
|
|
1005
|
+
y: -28 + (r ?? 0)
|
|
996
1006
|
}
|
|
997
1007
|
);
|
|
998
1008
|
}
|
|
@@ -1015,24 +1025,26 @@ class Gt {
|
|
|
1015
1025
|
* drawNote("w");
|
|
1016
1026
|
*/
|
|
1017
1027
|
drawNote(e) {
|
|
1018
|
-
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.
|
|
1028
|
+
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayer("notes");
|
|
1029
|
+
if (!s) throw new Error("DrawNote Error: Failed to retrieve notes layer");
|
|
1030
|
+
const r = [];
|
|
1019
1031
|
for (const n of t) {
|
|
1020
1032
|
let o = "w";
|
|
1021
1033
|
try {
|
|
1022
|
-
o =
|
|
1023
|
-
} catch (
|
|
1024
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1034
|
+
o = v(n);
|
|
1035
|
+
} catch (c) {
|
|
1036
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), c;
|
|
1025
1037
|
}
|
|
1026
|
-
const i =
|
|
1038
|
+
const i = I[o];
|
|
1027
1039
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1028
1040
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1029
1041
|
this.checkAndCreateNewBar();
|
|
1030
1042
|
const a = this.checkAndFillBarWithRests(i);
|
|
1031
|
-
a && a.forEach((
|
|
1032
|
-
r.push(
|
|
1043
|
+
a && a.forEach((c) => {
|
|
1044
|
+
r.push(c), this.noteEntries.push(c);
|
|
1033
1045
|
});
|
|
1034
|
-
const
|
|
1035
|
-
this.noteCursorX +=
|
|
1046
|
+
const h = this.rendererInstance.createGroup("note"), d = this.translateGroupByDuration(i, h);
|
|
1047
|
+
this.noteCursorX += d, this.currentBeatCount += i, this.renderNote(o, h), r.push(h), this.noteEntries.push(h);
|
|
1036
1048
|
}
|
|
1037
1049
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1038
1050
|
}
|
|
@@ -1055,22 +1067,24 @@ class Gt {
|
|
|
1055
1067
|
* drawRest("w");
|
|
1056
1068
|
*/
|
|
1057
1069
|
drawRest(e) {
|
|
1058
|
-
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.
|
|
1070
|
+
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayer("notes");
|
|
1071
|
+
if (!s) throw new Error("DrawRest Error: Failed to retrieve notes layer");
|
|
1072
|
+
const r = [];
|
|
1059
1073
|
for (const n of t) {
|
|
1060
1074
|
let o = "w";
|
|
1061
1075
|
try {
|
|
1062
|
-
o =
|
|
1063
|
-
} catch (
|
|
1064
|
-
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s),
|
|
1076
|
+
o = v(n);
|
|
1077
|
+
} catch (c) {
|
|
1078
|
+
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), c;
|
|
1065
1079
|
}
|
|
1066
|
-
const i = this.rendererInstance.createGroup("rest"), a =
|
|
1080
|
+
const i = this.rendererInstance.createGroup("rest"), a = I[o], h = a * this.quarterNoteSpacing;
|
|
1067
1081
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1068
1082
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
1069
1083
|
this.checkAndCreateNewBar();
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
r.push(
|
|
1073
|
-
}), this.renderRest(o, i), i.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX +=
|
|
1084
|
+
const d = this.checkAndFillBarWithRests(a);
|
|
1085
|
+
d && d.forEach((c) => {
|
|
1086
|
+
r.push(c), this.noteEntries.push(c);
|
|
1087
|
+
}), 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
1088
|
}
|
|
1075
1089
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
1076
1090
|
}
|
|
@@ -1097,13 +1111,15 @@ class Gt {
|
|
|
1097
1111
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1098
1112
|
throw new Error("Max beat count reached. Can't add additional beamed note.");
|
|
1099
1113
|
let s = "s";
|
|
1100
|
-
e === "s" ? s = "s" : s =
|
|
1101
|
-
const r = this.rendererInstance.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1114
|
+
e === "s" ? s = "s" : s = v(e), this.checkAndCreateNewBar();
|
|
1115
|
+
const r = this.rendererInstance.getLayer("notes");
|
|
1116
|
+
if (!r) throw new Error("drawBeamedNotes Error: Failed to retrieve notes layer");
|
|
1117
|
+
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");
|
|
1118
|
+
h.setAttribute("transform", `translate(${this.noteCursorX}, 0)`);
|
|
1119
|
+
let d = 0;
|
|
1120
|
+
for (let c = 0; c < a; c++)
|
|
1121
|
+
this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER", h, { xOffset: d }), this.drawStem(h, d), d += o, this.currentBeatCount += n;
|
|
1122
|
+
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
1123
|
}
|
|
1108
1124
|
/**
|
|
1109
1125
|
* Will increment the UI showing the current beat in quarters. Once exceeded, must be reset with `resetCurrentBeatUI()`
|
|
@@ -1114,21 +1130,21 @@ class Gt {
|
|
|
1114
1130
|
this.currentBeatUIElement.setAttribute("display", "none");
|
|
1115
1131
|
return;
|
|
1116
1132
|
}
|
|
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 +=
|
|
1133
|
+
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
1134
|
}
|
|
1119
1135
|
/**
|
|
1120
1136
|
* Resets the ui showing the current beat value.
|
|
1121
1137
|
* @returns void
|
|
1122
1138
|
*/
|
|
1123
1139
|
resetCurrentBeatUI() {
|
|
1124
|
-
this.currentBeatUICount = 0, this.currentBeatUIXPos =
|
|
1140
|
+
this.currentBeatUICount = 0, this.currentBeatUIXPos = H, this.currentBeatUIElement && (this.currentBeatUIElement.setAttribute("display", "none"), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString()));
|
|
1125
1141
|
}
|
|
1126
1142
|
/**
|
|
1127
1143
|
* Clears staff of notes and resets internal positioning.
|
|
1128
1144
|
* @returns void
|
|
1129
1145
|
*/
|
|
1130
1146
|
clearAllNotes() {
|
|
1131
|
-
this.noteCursorX = 0, this.currentBeatCount = 0, this.rendererInstance.
|
|
1147
|
+
this.noteCursorX = 0, this.currentBeatCount = 0, this.rendererInstance.getLayer("notes")?.replaceChildren(), this.noteEntries = [];
|
|
1132
1148
|
}
|
|
1133
1149
|
/**
|
|
1134
1150
|
* Removes the root svg element and cleans up arrays.
|
|
@@ -1152,8 +1168,8 @@ const Rt = [
|
|
|
1152
1168
|
"ACCIDENTAL_NATURAL",
|
|
1153
1169
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
1154
1170
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
1155
|
-
], y = 60,
|
|
1156
|
-
class
|
|
1171
|
+
], y = 60, wt = y;
|
|
1172
|
+
class Gt {
|
|
1157
1173
|
svgRendererInstance;
|
|
1158
1174
|
strategyInstance;
|
|
1159
1175
|
noteRendererInstance;
|
|
@@ -1177,46 +1193,45 @@ class vt {
|
|
|
1177
1193
|
staffType: "treble",
|
|
1178
1194
|
spaceAbove: 0,
|
|
1179
1195
|
spaceBelow: 0,
|
|
1180
|
-
|
|
1181
|
-
staffBackgroundColor: "transparent",
|
|
1196
|
+
svgAutoFill: !0,
|
|
1182
1197
|
...t
|
|
1183
|
-
}, this.svgRendererInstance = new
|
|
1198
|
+
}, this.svgRendererInstance = new O(e, {
|
|
1184
1199
|
width: this.options.width,
|
|
1185
1200
|
height: 100,
|
|
1186
1201
|
scale: this.options.scale,
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
useGlyphs: Rt
|
|
1202
|
+
useGlyphs: Rt,
|
|
1203
|
+
svgAutoFill: this.options.svgAutoFill
|
|
1190
1204
|
});
|
|
1191
1205
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1192
1206
|
switch (this.options.staffType) {
|
|
1193
1207
|
case "grand":
|
|
1194
|
-
this.strategyInstance = new
|
|
1208
|
+
this.strategyInstance = new nt(this.svgRendererInstance, "grand");
|
|
1195
1209
|
break;
|
|
1196
1210
|
case "bass":
|
|
1197
|
-
this.strategyInstance = new
|
|
1211
|
+
this.strategyInstance = new S(this.svgRendererInstance, "bass");
|
|
1198
1212
|
break;
|
|
1199
1213
|
case "treble":
|
|
1200
|
-
this.strategyInstance = new
|
|
1214
|
+
this.strategyInstance = new S(this.svgRendererInstance, "treble");
|
|
1201
1215
|
break;
|
|
1202
1216
|
case "alto":
|
|
1203
|
-
this.strategyInstance = new
|
|
1217
|
+
this.strategyInstance = new S(this.svgRendererInstance, "alto");
|
|
1204
1218
|
break;
|
|
1205
1219
|
default:
|
|
1206
1220
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
1207
1221
|
}
|
|
1208
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
1209
|
-
const
|
|
1210
|
-
this.svgRendererInstance.addTotalRootSvgYOffset(
|
|
1222
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new ot(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
1223
|
+
const n = this.options.spaceAbove * 10;
|
|
1224
|
+
this.svgRendererInstance.addTotalRootSvgYOffset(n);
|
|
1211
1225
|
}
|
|
1212
1226
|
if (this.options.spaceBelow) {
|
|
1213
|
-
let
|
|
1214
|
-
this.options.staffType === "grand" && (
|
|
1227
|
+
let n = this.options.spaceBelow * 10;
|
|
1228
|
+
this.options.staffType === "grand" && (n -= 10 / 2), this.svgRendererInstance.addTotalRootSvgHeight(n);
|
|
1215
1229
|
}
|
|
1216
|
-
|
|
1230
|
+
const r = this.svgRendererInstance.createLayer("notes");
|
|
1231
|
+
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
1232
|
}
|
|
1218
1233
|
renderFirstNoteGroups() {
|
|
1219
|
-
const e = this.options.width - this.options.noteStartX +
|
|
1234
|
+
const e = this.options.width - this.options.noteStartX + wt;
|
|
1220
1235
|
for (; this.noteBuffer.length > 0 && this.noteCursorX < e; )
|
|
1221
1236
|
this.renderNextNote(), this.noteCursorX += y;
|
|
1222
1237
|
this.activeEntries.length > 1 && (this.noteCursorX -= y);
|
|
@@ -1298,29 +1313,29 @@ class vt {
|
|
|
1298
1313
|
this.svgRendererInstance.destroy(), this.activeEntries = [], this.noteBuffer = [];
|
|
1299
1314
|
}
|
|
1300
1315
|
}
|
|
1301
|
-
const
|
|
1302
|
-
function
|
|
1316
|
+
const yt = /^[xX\da-zA-Z]+$/, Ot = /^[\d]+$/;
|
|
1317
|
+
function tt(l, e) {
|
|
1303
1318
|
const t = [];
|
|
1304
|
-
for (let s = 0; s <
|
|
1319
|
+
for (let s = 0; s < l.length; s++)
|
|
1305
1320
|
t.push({
|
|
1306
|
-
fret:
|
|
1321
|
+
fret: l[s],
|
|
1307
1322
|
finger: e[s]
|
|
1308
1323
|
});
|
|
1309
1324
|
return t;
|
|
1310
1325
|
}
|
|
1311
|
-
function
|
|
1312
|
-
const t =
|
|
1326
|
+
function et(l, e) {
|
|
1327
|
+
const t = l.filter((n) => n.toLowerCase() !== "x" && n !== "0").map((n) => parseInt(n, 36));
|
|
1313
1328
|
if (t.length === 0) return 1;
|
|
1314
1329
|
const s = Math.min(...t);
|
|
1315
1330
|
return Math.max(...t) <= e ? 1 : s;
|
|
1316
1331
|
}
|
|
1317
|
-
function
|
|
1318
|
-
if (!
|
|
1319
|
-
return
|
|
1332
|
+
function P(l) {
|
|
1333
|
+
if (!yt.test(l)) throw new Error("Invalid frets string. Only 'x', 'X', and digits are allowed.");
|
|
1334
|
+
return l.split("");
|
|
1320
1335
|
}
|
|
1321
|
-
function B(
|
|
1322
|
-
if (!Ot.test(
|
|
1323
|
-
return
|
|
1336
|
+
function B(l) {
|
|
1337
|
+
if (!Ot.test(l)) throw new Error("Invalid fingers string. Only digits are allowed.");
|
|
1338
|
+
return l.split("");
|
|
1324
1339
|
}
|
|
1325
1340
|
class Ft {
|
|
1326
1341
|
svgRendererInstance;
|
|
@@ -1341,23 +1356,22 @@ class Ft {
|
|
|
1341
1356
|
*/
|
|
1342
1357
|
constructor(e, t) {
|
|
1343
1358
|
if (this.options = {
|
|
1344
|
-
stringCount:
|
|
1345
|
-
fretCount:
|
|
1359
|
+
stringCount: it,
|
|
1360
|
+
fretCount: at,
|
|
1346
1361
|
stringLabels: [],
|
|
1347
1362
|
inlineChordsAmount: 2,
|
|
1363
|
+
centerChords: !0,
|
|
1348
1364
|
scale: 1,
|
|
1349
|
-
|
|
1350
|
-
backgroundColor: "transparent",
|
|
1365
|
+
svgAutoFill: !0,
|
|
1351
1366
|
...t
|
|
1352
|
-
}, this.diagramWidth = (this.options.stringCount - 1) *
|
|
1367
|
+
}, 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
1368
|
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
|
|
1369
|
+
this.svgRendererInstance = new O(e, {
|
|
1355
1370
|
width: this.options.width,
|
|
1356
1371
|
height: 100,
|
|
1357
1372
|
scale: this.options.scale,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
useGlyphs: []
|
|
1373
|
+
useGlyphs: [],
|
|
1374
|
+
svgAutoFill: this.options.svgAutoFill
|
|
1361
1375
|
});
|
|
1362
1376
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1363
1377
|
this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
@@ -1373,30 +1387,33 @@ class Ft {
|
|
|
1373
1387
|
drawFretDots(e, t, s, r, n) {
|
|
1374
1388
|
const o = this.gridTopY - W / 2;
|
|
1375
1389
|
for (let i = 0; i < this.options.stringCount; i++) {
|
|
1376
|
-
const a = i *
|
|
1377
|
-
if (
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
this.svgRendererInstance.
|
|
1390
|
+
const a = i * T, h = e[i].toLowerCase(), d = t[i], c = this.svgRendererInstance.createGroup("");
|
|
1391
|
+
if (h === "x")
|
|
1392
|
+
c.classList.add("vs-guitar-fret-muted"), c.setAttribute("transform", `translate(${a}, ${o})`), this.svgRendererInstance.drawLine(-A, -A, A, A, c, {
|
|
1393
|
+
strokeWidth: 1.5
|
|
1394
|
+
}), this.svgRendererInstance.drawLine(-A, A, A, -A, c, {
|
|
1395
|
+
strokeWidth: 1.5
|
|
1396
|
+
});
|
|
1397
|
+
else if (h === "0")
|
|
1398
|
+
c.classList.add("vs-guitar-fret-open"), c.setAttribute("transform", `translate(${a}, ${o})`), this.svgRendererInstance.drawCircle(0, 0, A, c, { filled: !1 });
|
|
1381
1399
|
else {
|
|
1382
|
-
const
|
|
1383
|
-
if (r.has(`${i}-${
|
|
1400
|
+
const f = parseInt(h, 36);
|
|
1401
|
+
if (r.has(`${i}-${f}`))
|
|
1384
1402
|
continue;
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1403
|
+
c.classList.add("vs-guitar-fret-dot");
|
|
1404
|
+
const E = f - s + 1;
|
|
1405
|
+
if (E < 1 || E > this.options.fretCount)
|
|
1406
|
+
throw new Error(`Fret ${h} on string ${i + 1} is outside the visible range (${s}-${s + this.options.fretCount - 1}). Adjust 'startFret' or 'fretCount'.`);
|
|
1407
|
+
const g = this.gridTopY + (E - 0.5) * m;
|
|
1408
|
+
c.setAttribute("transform", `translate(${a}, ${g})`), this.svgRendererInstance.drawCircle(0, 0, u, c, {
|
|
1409
|
+
classes: "guitar-fret-circle"
|
|
1410
|
+
}), d !== "0" && this.svgRendererInstance.drawText(d, 0, -1, c, {
|
|
1411
|
+
fontSize: R,
|
|
1412
|
+
baseline: "central",
|
|
1413
|
+
classes: ["guitar-text", "guitar-fret-text"]
|
|
1414
|
+
});
|
|
1399
1415
|
}
|
|
1416
|
+
n.appendChild(c);
|
|
1400
1417
|
}
|
|
1401
1418
|
}
|
|
1402
1419
|
drawStringLabels(e, t) {
|
|
@@ -1405,10 +1422,11 @@ class Ft {
|
|
|
1405
1422
|
for (let n = 0; n < this.options.stringCount; n++) {
|
|
1406
1423
|
const o = t[n];
|
|
1407
1424
|
if (!o) continue;
|
|
1408
|
-
const i = n *
|
|
1409
|
-
this.svgRendererInstance.drawText(o, i,
|
|
1410
|
-
fontSize:
|
|
1411
|
-
|
|
1425
|
+
const i = n * T;
|
|
1426
|
+
this.svgRendererInstance.drawText(o, i, r, e, {
|
|
1427
|
+
fontSize: R,
|
|
1428
|
+
baseline: "central",
|
|
1429
|
+
classes: "guitar-text"
|
|
1412
1430
|
});
|
|
1413
1431
|
}
|
|
1414
1432
|
}
|
|
@@ -1419,69 +1437,82 @@ class Ft {
|
|
|
1419
1437
|
throw new Error(`Barre fret error: Invalid string range ${t.fromIndex + 1}:${t.toIndex + 1}.`);
|
|
1420
1438
|
if (s < t.startingFret || s > t.startingFret + (this.options.fretCount - 1))
|
|
1421
1439
|
throw new Error(`Barre fret error: ${t.fret} is outside the visible range.`);
|
|
1422
|
-
const r = s - t.startingFret,
|
|
1423
|
-
|
|
1424
|
-
x:
|
|
1425
|
-
y:
|
|
1440
|
+
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;
|
|
1441
|
+
r.setAttribute("transform", `translate(0, ${d})`), this.svgRendererInstance.drawRect(h, a, r, {
|
|
1442
|
+
x: o - u,
|
|
1443
|
+
y: u / 2,
|
|
1426
1444
|
rx: u,
|
|
1427
1445
|
classes: "guitar-barre"
|
|
1428
|
-
}), t.finger) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
classes: "guitar-text-small"
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1446
|
+
}), t.finger && this.svgRendererInstance.drawText(t.finger.toString(), (o + i) / 2, u * 1.5 - 1, r, {
|
|
1447
|
+
fontSize: R,
|
|
1448
|
+
baseline: "central",
|
|
1449
|
+
classes: ["guitar-text", "guitar-fret-text"]
|
|
1450
|
+
}), e.appendChild(r);
|
|
1436
1451
|
}
|
|
1437
1452
|
// Builds a single chord diagram's group element: grid, nut/fret-position label, and per-string markers.
|
|
1438
1453
|
renderChordDiagram(e, t, s) {
|
|
1439
1454
|
const r = this.svgRendererInstance.createGroup("chord"), n = s?.startFret ?? 1;
|
|
1440
|
-
s?.label && this.svgRendererInstance.drawText(s.label, this.diagramWidth / 2,
|
|
1441
|
-
fontSize:
|
|
1455
|
+
s?.label && this.svgRendererInstance.drawText(s.label, this.diagramWidth / 2, k - 5, r, {
|
|
1456
|
+
fontSize: st,
|
|
1442
1457
|
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, {
|
|
1458
|
+
classes: ["guitar-text", "guitar-diagram-label"]
|
|
1459
|
+
}), n > 1 && this.svgRendererInstance.drawText(`${n}fr`, this.diagramWidth + u + Et, this.gridTopY + m / 2 + 4, r, {
|
|
1453
1460
|
anchor: "start",
|
|
1454
|
-
fontSize:
|
|
1461
|
+
fontSize: R,
|
|
1455
1462
|
fontWeight: "bold",
|
|
1456
|
-
classes: "guitar-text-
|
|
1463
|
+
classes: ["guitar-text", "guitar-fret-label"]
|
|
1457
1464
|
});
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1465
|
+
const o = this.svgRendererInstance.createGroup("guitar-group-fret-lines");
|
|
1466
|
+
for (let c = 0; c <= this.options.fretCount; c++) {
|
|
1467
|
+
const f = this.gridTopY + c * m;
|
|
1468
|
+
c === 0 && n === 1 ? this.svgRendererInstance.drawRect(this.diagramWidth + ft, x, o, {
|
|
1469
|
+
x: -0.5,
|
|
1470
|
+
y: f - x / 2
|
|
1471
|
+
}) : this.svgRendererInstance.drawLine(0, f, this.diagramWidth, f, o);
|
|
1461
1472
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1473
|
+
r.appendChild(o);
|
|
1474
|
+
const i = this.svgRendererInstance.createGroup("guitar-group-string-lines");
|
|
1475
|
+
for (let c = 0; c < this.options.stringCount; c++) {
|
|
1476
|
+
const f = c * T;
|
|
1477
|
+
this.svgRendererInstance.drawLine(f, this.gridTopY, f, this.gridTopY + this.diagramHeight, i);
|
|
1478
|
+
}
|
|
1479
|
+
r.appendChild(i);
|
|
1480
|
+
const a = this.svgRendererInstance.createGroup("guitar-group-fret-dots"), h = this.getDotsToHide(s?.barres);
|
|
1481
|
+
this.drawFretDots(e, t, n, h, a), s?.barres?.forEach((c) => {
|
|
1482
|
+
this.drawBarre(a, {
|
|
1483
|
+
fromIndex: c.fromString - 1,
|
|
1484
|
+
toIndex: c.toString - 1,
|
|
1485
|
+
fret: c.fret,
|
|
1486
|
+
finger: c.finger,
|
|
1469
1487
|
startingFret: n
|
|
1470
1488
|
});
|
|
1471
|
-
}), r;
|
|
1489
|
+
}), r.appendChild(a);
|
|
1490
|
+
const d = this.svgRendererInstance.createGroup("guitar-group-string-labels");
|
|
1491
|
+
return this.options.stringLabels.length >= 1 && this.drawStringLabels(d, this.options.stringLabels), r.appendChild(d), r;
|
|
1472
1492
|
}
|
|
1473
1493
|
// 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
|
|
1494
|
+
// Called after any add/remove/change so the layout never has to track pos.
|
|
1475
1495
|
relayoutChords() {
|
|
1476
|
-
if (this.
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1496
|
+
if (this.chordEntries.length === 0) {
|
|
1497
|
+
this.svgRendererInstance.setTotalRootSvgHeight(0), this.svgRendererInstance.applySizingToRootSvg();
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const e = [];
|
|
1501
|
+
let t = [], s = u;
|
|
1502
|
+
this.chordEntries.forEach((n, o) => {
|
|
1503
|
+
o > 0 && s + this.diagramWidth > this.options.width && (e.push(t), t = [], s = u), t.push(n), s += this.diagramWidth + L;
|
|
1504
|
+
}), t.length > 0 && e.push(t), this.cursorY = dt, e.forEach((n, o) => {
|
|
1505
|
+
if (o > 0 && (this.cursorY += this.rowHeight + lt), this.options.centerChords) {
|
|
1506
|
+
const i = n.length * this.diagramWidth + (n.length - 1) * L, a = this.options.width / 2 - i / 2 - 16;
|
|
1507
|
+
this.cursorX = a;
|
|
1508
|
+
} else
|
|
1509
|
+
this.cursorX = u;
|
|
1510
|
+
n.forEach((i) => {
|
|
1511
|
+
i.xPos = this.cursorX, i.yPos = this.cursorY, i.gElement.setAttribute("transform", `translate(${this.cursorX}, ${this.cursorY})`), this.cursorX += this.diagramWidth + L;
|
|
1482
1512
|
});
|
|
1483
|
-
|
|
1484
|
-
this.
|
|
1513
|
+
});
|
|
1514
|
+
const r = this.cursorY + this.rowHeight;
|
|
1515
|
+
this.svgRendererInstance.setTotalRootSvgHeight(r), this.svgRendererInstance.applySizingToRootSvg();
|
|
1485
1516
|
}
|
|
1486
1517
|
/**
|
|
1487
1518
|
* Adds a new chord diagram. Diagrams are placed left-to-right in the order added, wrapping to a
|
|
@@ -1507,14 +1538,14 @@ class Ft {
|
|
|
1507
1538
|
* guitarChord.addChord("x32010", "032010", { label: "C" });
|
|
1508
1539
|
*/
|
|
1509
1540
|
addChord(e, t, s) {
|
|
1510
|
-
const r =
|
|
1541
|
+
const r = P(e), n = B(t);
|
|
1511
1542
|
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
1543
|
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
|
-
...
|
|
1544
|
+
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;
|
|
1545
|
+
return this.svgRendererInstance.commitElementsToDOM(d, c), this.chordEntries.push({
|
|
1546
|
+
gElement: d,
|
|
1547
|
+
strings: tt(r, n),
|
|
1548
|
+
...h,
|
|
1518
1549
|
xPos: 0,
|
|
1519
1550
|
yPos: 0
|
|
1520
1551
|
}), this.relayoutChords(), this.chordEntries.length - 1;
|
|
@@ -1545,14 +1576,14 @@ class Ft {
|
|
|
1545
1576
|
*/
|
|
1546
1577
|
modifyChordByIndex(e, t, s, r) {
|
|
1547
1578
|
if (s >= this.chordEntries.length || s < 0) throw new Error("Chord index was out of bounds.");
|
|
1548
|
-
const n =
|
|
1579
|
+
const n = P(e), o = B(t);
|
|
1549
1580
|
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
1581
|
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
|
-
...
|
|
1582
|
+
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);
|
|
1583
|
+
this.svgRendererInstance.parentGroupElement.replaceChild(c, i.gElement), this.chordEntries[s] = {
|
|
1584
|
+
gElement: c,
|
|
1585
|
+
strings: tt(n, o),
|
|
1586
|
+
...d,
|
|
1556
1587
|
xPos: i.xPos,
|
|
1557
1588
|
yPos: i.yPos
|
|
1558
1589
|
}, this.relayoutChords();
|
|
@@ -1572,7 +1603,7 @@ class Ft {
|
|
|
1572
1603
|
* @returns void
|
|
1573
1604
|
*/
|
|
1574
1605
|
clearAllChords() {
|
|
1575
|
-
this.svgRendererInstance.
|
|
1606
|
+
this.svgRendererInstance.parentGroupElement.replaceChildren(), this.chordEntries = [], this.cursorX = 0, this.cursorY = 0, this.svgRendererInstance.setTotalRootSvgHeight(this.rowHeight), this.svgRendererInstance.applySizingToRootSvg();
|
|
1576
1607
|
}
|
|
1577
1608
|
/**
|
|
1578
1609
|
* * Used to automatically determine options for creating barre lines.
|
|
@@ -1580,25 +1611,25 @@ class Ft {
|
|
|
1580
1611
|
* @returns GuitarBarreDef[]
|
|
1581
1612
|
*/
|
|
1582
1613
|
determineBarreOptions(e, t, s) {
|
|
1583
|
-
const r =
|
|
1614
|
+
const r = P(e), n = B(t), o = [];
|
|
1584
1615
|
return s.forEach((i) => {
|
|
1585
1616
|
if (i === 0) return;
|
|
1586
|
-
const a = [],
|
|
1587
|
-
for (let
|
|
1588
|
-
if (r[
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1617
|
+
const a = [], h = {};
|
|
1618
|
+
for (let g = 0; g < r.length; g++) {
|
|
1619
|
+
if (r[g].toLowerCase() === "x") continue;
|
|
1620
|
+
const N = parseInt(r[g], 36), b = Number(n[g]);
|
|
1621
|
+
N === i && (h[b] ? h[b] += 1 : h[b] = 1, a.push(g + 1));
|
|
1591
1622
|
}
|
|
1592
1623
|
a.sort();
|
|
1593
|
-
let
|
|
1594
|
-
for (const [
|
|
1595
|
-
|
|
1596
|
-
const f = a[0],
|
|
1597
|
-
a.length > 1 &&
|
|
1624
|
+
let d = 0, c = 0;
|
|
1625
|
+
for (const [g, N] of Object.entries(h))
|
|
1626
|
+
N > c && (c = N, d = Number(g));
|
|
1627
|
+
const f = a[0], E = a.at(-1);
|
|
1628
|
+
a.length > 1 && E && o.push({
|
|
1598
1629
|
fret: i,
|
|
1599
1630
|
fromString: f,
|
|
1600
|
-
toString:
|
|
1601
|
-
finger:
|
|
1631
|
+
toString: E,
|
|
1632
|
+
finger: d
|
|
1602
1633
|
});
|
|
1603
1634
|
}), o;
|
|
1604
1635
|
}
|
|
@@ -1613,6 +1644,6 @@ class Ft {
|
|
|
1613
1644
|
export {
|
|
1614
1645
|
Ft as GuitarChord,
|
|
1615
1646
|
bt as MusicStaff,
|
|
1616
|
-
|
|
1617
|
-
|
|
1647
|
+
vt as RhythmStaff,
|
|
1648
|
+
Gt as ScrollingStaff
|
|
1618
1649
|
};
|