abcjs 6.2.2 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +4 -0
  2. package/RELEASE.md +78 -0
  3. package/abc2xml_239/abc2xml.html +769 -0
  4. package/abc2xml_239/abc2xml.py +2248 -0
  5. package/abc2xml_239/abc2xml_changelog.html +124 -0
  6. package/abc2xml_239/lazy-river.abc +26 -0
  7. package/abc2xml_239/lazy-river.xml +3698 -0
  8. package/abc2xml_239/mean-to-me.abc +22 -0
  9. package/abc2xml_239/mean-to-me.xml +2954 -0
  10. package/abc2xml_239/pyparsing.py +3672 -0
  11. package/abc2xml_239/pyparsing.pyc +0 -0
  12. package/dist/abcjs-basic-min.js +2 -2
  13. package/dist/abcjs-basic.js +909 -485
  14. package/dist/abcjs-basic.js.map +1 -1
  15. package/dist/abcjs-plugin-min.js +2 -2
  16. package/index.js +2 -0
  17. package/package.json +1 -1
  18. package/plugin.js +1 -1
  19. package/src/api/abc_tablatures.js +51 -13
  20. package/src/api/abc_tunebook_svg.js +5 -3
  21. package/src/parse/abc_parse_directive.js +17 -16
  22. package/src/parse/abc_parse_header.js +22 -19
  23. package/src/parse/abc_parse_music.js +18 -53
  24. package/src/parse/abc_parse_settings.js +165 -0
  25. package/src/parse/abc_tokenizer.js +72 -7
  26. package/src/parse/tune-builder.js +60 -1
  27. package/src/synth/create-synth.js +4 -0
  28. package/src/synth/place-note.js +6 -0
  29. package/src/synth/play-event.js +7 -5
  30. package/src/synth/synth-controller.js +6 -2
  31. package/src/tablatures/instruments/string-patterns.js +11 -0
  32. package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
  33. package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
  34. package/src/tablatures/tab-absolute-elements.js +19 -9
  35. package/src/tablatures/tab-renderer.js +24 -10
  36. package/src/test/abc_parser_lint.js +1 -0
  37. package/src/write/creation/abstract-engraver.js +9 -2
  38. package/src/write/creation/add-chord.js +102 -82
  39. package/src/write/creation/add-text-if.js +2 -2
  40. package/src/write/creation/decoration.js +16 -8
  41. package/src/write/creation/elements/bottom-text.js +62 -47
  42. package/src/write/creation/elements/rich-text.js +51 -0
  43. package/src/write/creation/elements/top-text.js +37 -11
  44. package/src/write/creation/glyphs.js +2 -2
  45. package/src/write/draw/absolute.js +4 -1
  46. package/src/write/draw/draw.js +13 -4
  47. package/src/write/draw/glissando.js +1 -0
  48. package/src/write/draw/non-music.js +3 -1
  49. package/src/write/draw/relative.js +1 -1
  50. package/src/write/draw/set-paper-size.js +1 -1
  51. package/src/write/draw/tempo.js +1 -1
  52. package/src/write/draw/text.js +10 -0
  53. package/src/write/draw/tie.js +9 -1
  54. package/src/write/engraver-controller.js +58 -11
  55. package/src/write/helpers/classes.js +1 -1
  56. package/src/write/helpers/get-font-and-attr.js +8 -1
  57. package/src/write/helpers/get-text-size.js +8 -1
  58. package/src/write/interactive/selection.js +6 -0
  59. package/src/write/layout/layout.js +33 -3
  60. package/src/write/svg.js +30 -0
  61. package/temp.txt +50 -0
  62. package/types/index.d.ts +74 -26
  63. package/version.js +1 -1
  64. package/.github/workflows/tests.yml +0 -29
  65. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
  66. package/src/tablatures/instruments/violin/violin-patterns.js +0 -23
@@ -6,97 +6,117 @@ var addChord = function (getTextSize, abselem, elem, roomTaken, roomTakenRight,
6
6
  for (var i = 0; i < elem.chord.length; i++) {
7
7
  var pos = elem.chord[i].position;
8
8
  var rel_position = elem.chord[i].rel_position;
9
- var chords = elem.chord[i].name.split("\n");
10
- for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top.
11
- var chord = chords[j];
12
- var x = 0;
13
- var y;
14
- var font;
15
- var klass;
16
- if (pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position) {
17
- font = 'annotationfont';
18
- klass = "annotation";
19
- } else {
20
- font = 'gchordfont';
21
- klass = "chord";
22
- chord = translateChord(chord, jazzchords, germanAlphabet);
9
+ var isAnnotation = pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position
10
+ var font;
11
+ var klass;
12
+ if (isAnnotation) {
13
+ font = 'annotationfont';
14
+ klass = "abcjs-annotation";
15
+ } else {
16
+ font = 'gchordfont';
17
+ klass = "abcjs-chord";
18
+ }
19
+ var attr = getTextSize.attr(font, klass);
20
+
21
+ var name = elem.chord[i].name
22
+ var ret;
23
+ //console.log("chord",name)
24
+ if (typeof name === "string") {
25
+ ret = chordString(name, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet)
26
+ roomTaken = ret.roomTaken
27
+ roomTakenRight = ret.roomTakenRight
28
+ } else {
29
+ for (var j = 0; j < name.length; j++) {
30
+ ret = chordString(name[j].text, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet)
31
+ roomTaken = ret.roomTaken
32
+ roomTakenRight = ret.roomTakenRight
23
33
  }
24
- var attr = getTextSize.attr(font, klass);
25
- var dim = getTextSize.calc(chord, font, klass);
26
- var chordWidth = dim.width;
27
- var chordHeight = dim.height / spacing.STEP;
28
- switch (pos) {
29
- case "left":
30
- roomTaken += chordWidth + 7;
31
- x = -roomTaken; // TODO-PER: This is just a guess from trial and error
32
- y = elem.averagepitch;
33
- abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
34
- type: "text",
35
- height: chordHeight,
36
- dim: attr,
37
- position: "left"
38
- }));
39
- break;
40
- case "right":
41
- roomTakenRight += 4;
42
- x = roomTakenRight;// TODO-PER: This is just a guess from trial and error
43
- y = elem.averagepitch;
44
- abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
45
- type: "text",
46
- height: chordHeight,
47
- dim: attr,
48
- position: "right"
49
- }));
50
- break;
51
- case "below":
52
- // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
53
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
34
+ }
35
+ }
36
+ return { roomTaken: roomTaken, roomTakenRight: roomTakenRight };
37
+ };
38
+
39
+ function chordString(chordString, pos, rel_position, isAnnotation, font, klass, attr, getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords, germanAlphabet) {
40
+ var chords = chordString.split("\n");
41
+ for (var j = chords.length - 1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top.
42
+ var chord = chords[j];
43
+ var x = 0;
44
+ var y;
45
+ if (!isAnnotation)
46
+ chord = translateChord(chord, jazzchords, germanAlphabet);
47
+ var dim = getTextSize.calc(chord, font, klass);
48
+ var chordWidth = dim.width;
49
+ var chordHeight = dim.height / spacing.STEP;
50
+ switch (pos) {
51
+ case "left":
52
+ roomTaken += chordWidth + 7;
53
+ x = -roomTaken; // TODO-PER: This is just a guess from trial and error
54
+ y = elem.averagepitch;
55
+ abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
56
+ type: "text",
57
+ height: chordHeight,
58
+ dim: attr,
59
+ position: "left"
60
+ }));
61
+ break;
62
+ case "right":
63
+ roomTakenRight += 4;
64
+ x = roomTakenRight;// TODO-PER: This is just a guess from trial and error
65
+ y = elem.averagepitch;
66
+ abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
67
+ type: "text",
68
+ height: chordHeight,
69
+ dim: attr,
70
+ position: "right"
71
+ }));
72
+ break;
73
+ case "below":
74
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
75
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
76
+ type: "text",
77
+ position: "below",
78
+ height: chordHeight,
79
+ dim: attr,
80
+ realWidth: chordWidth
81
+ }));
82
+ break;
83
+ case "above":
84
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
85
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
86
+ type: "text",
87
+ position: "above",
88
+ height: chordHeight,
89
+ dim: attr,
90
+ realWidth: chordWidth
91
+ }));
92
+ break;
93
+ default:
94
+ if (rel_position) {
95
+ var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
96
+ abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
97
+ position: "relative",
54
98
  type: "text",
55
- position: "below",
56
99
  height: chordHeight,
57
- dim: attr,
58
- realWidth: chordWidth
100
+ dim: attr
59
101
  }));
60
- break;
61
- case "above":
102
+ } else {
62
103
  // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
63
- abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
64
- type: "text",
65
- position: "above",
66
- height: chordHeight,
67
- dim: attr,
68
- realWidth: chordWidth
69
- }));
70
- break;
71
- default:
72
- if (rel_position) {
73
- var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
74
- abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
75
- position: "relative",
76
- type: "text",
104
+ var pos2 = 'above';
105
+ if (elem.positioning && elem.positioning.chordPosition)
106
+ pos2 = elem.positioning.chordPosition;
107
+
108
+ if (pos2 !== 'hidden') {
109
+ abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
110
+ type: "chord",
111
+ position: pos2,
77
112
  height: chordHeight,
78
- dim: attr
113
+ dim: attr,
114
+ realWidth: chordWidth
79
115
  }));
80
- } else {
81
- // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
82
- var pos2 = 'above';
83
- if (elem.positioning && elem.positioning.chordPosition)
84
- pos2 = elem.positioning.chordPosition;
85
-
86
- if (pos2 !== 'hidden') {
87
- abselem.addCentered(new RelativeElement(chord, noteheadWidth / 2, chordWidth, undefined, {
88
- type: "chord",
89
- position: pos2,
90
- height: chordHeight,
91
- dim: attr,
92
- realWidth: chordWidth
93
- }));
94
- }
95
116
  }
96
- }
117
+ }
97
118
  }
98
119
  }
99
120
  return { roomTaken: roomTaken, roomTakenRight: roomTakenRight };
100
- };
101
-
121
+ }
102
122
  module.exports = addChord;
@@ -8,10 +8,10 @@ function addTextIf(rows, params, getTextSize) {
8
8
 
9
9
  if (params.marginTop)
10
10
  rows.push({ move: params.marginTop });
11
- var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar };
11
+ var attr = { left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar, 'dominant-baseline': params['dominant-baseline'] };
12
12
  if (params.absElemType)
13
13
  attr.absElemType = params.absElemType;
14
- if (!params.inGroup)
14
+ if (!params.inGroup && params.klass)
15
15
  attr.klass = params.klass;
16
16
  if (params.name)
17
17
  attr.name = params.name;
@@ -14,10 +14,10 @@ var Decoration = function Decoration() {
14
14
  this.minBottom = 0;
15
15
  };
16
16
 
17
- var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch) {
17
+ var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove) {
18
18
  var yPos;
19
19
  for (var i = 0; i < decoration.length; i++) {
20
- if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent") {
20
+ if (decoration[i] === "staccato" || decoration[i] === "tenuto" || (decoration[i] === "accent" && !accentAbove)) {
21
21
  var symbol = "scripts." + decoration[i];
22
22
  if (decoration[i] === "accent") symbol = "scripts.sforzato";
23
23
  if (yPos === undefined)
@@ -123,7 +123,7 @@ var compoundDecoration = function (decoration, pitch, width, abselem, dir) {
123
123
  }
124
124
  };
125
125
 
126
- var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom) {
126
+ var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom, accentAbove) {
127
127
  function incrementPlacement(placement, height) {
128
128
  if (placement === 'above')
129
129
  yPos.above += height;
@@ -263,6 +263,12 @@ var stackedDecoration = function (decoration, width, abselem, yPos, positioning,
263
263
  case "mark":
264
264
  abselem.klass = "mark";
265
265
  break;
266
+ case "accent":
267
+ if (accentAbove) {
268
+ symbolDecoration("scripts.sforzato", positioning);
269
+ hasOne = true;
270
+ }
271
+ break;
266
272
  }
267
273
  }
268
274
  return hasOne;
@@ -313,10 +319,12 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
313
319
  crescendo = { start: this.startCrescendoX, stop: abselem };
314
320
  this.startCrescendoX = undefined;
315
321
  break;
322
+ case '~(':
316
323
  case "glissando(":
317
324
  this.startGlissandoX = abselem;
318
325
  glissando = undefined;
319
326
  break;
327
+ case '~)':
320
328
  case "glissando)":
321
329
  glissando = { start: this.startGlissandoX, stop: abselem };
322
330
  this.startGlissandoX = undefined;
@@ -334,7 +342,7 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
334
342
  }
335
343
  };
336
344
 
337
- Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
345
+ Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals, accentAbove) {
338
346
  if (!positioning)
339
347
  positioning = { ornamentPosition: 'above', volumePosition: hasVocals ? 'above' : 'below', dynamicPosition: hasVocals ? 'above' : 'below' };
340
348
  // These decorations don't affect the placement of other decorations
@@ -343,14 +351,14 @@ Decoration.prototype.createDecoration = function (voice, decoration, pitch, widt
343
351
  compoundDecoration(decoration, pitch, width, abselem, dir);
344
352
 
345
353
  // treat staccato, accent, and tenuto first (may need to shift other markers)
346
- var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch);
354
+ var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, accentAbove);
347
355
  // yPos is an object containing 'above' and 'below'. That is the placement of the next symbol on either side.
348
356
 
349
357
  yPos.above = Math.max(yPos.above, this.minTop);
350
- var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom);
351
- if (hasOne) {
358
+ var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom, accentAbove);
359
+ //if (hasOne) {
352
360
  // abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
353
- }
361
+ //}
354
362
  leftDecoration(decoration, abselem, roomtaken);
355
363
  };
356
364
 
@@ -1,68 +1,83 @@
1
1
  const addTextIf = require("../add-text-if");
2
+ const richText = require("./rich-text");
2
3
 
3
- function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ function BottomText(metaText, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
4
5
  this.rows = [];
5
6
  if (metaText.unalignedWords && metaText.unalignedWords.length > 0)
6
- this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, getTextSize);
7
- this.extraText(metaText, paddingLeft, spacing, getTextSize);
7
+ this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, shouldAddClasses, getTextSize);
8
+ this.extraText(metaText, paddingLeft, spacing, shouldAddClasses, getTextSize);
8
9
  if (metaText.footer && isPrint)
9
10
  this.footer(metaText.footer, width, paddingLeft, getTextSize);
10
11
  }
11
12
 
12
- BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) {
13
- var klass = 'meta-bottom unaligned-words';
13
+ BottomText.prototype.unalignedWords = function (unalignedWords, marginLeft, spacing, shouldAddClasses, getTextSize) {
14
+ var klass = shouldAddClasses ? 'abcjs-unaligned-words' : ''
14
15
  var defFont = 'wordsfont';
15
- this.rows.push({ startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words" });
16
16
  var space = getTextSize.calc("i", defFont, klass);
17
-
17
+
18
18
  this.rows.push({ move: spacing.words });
19
+
20
+ addMultiLine(this.rows, '', unalignedWords, marginLeft, defFont, "unalignedWords", "unalignedWords", klass, "unalignedWords", spacing, shouldAddClasses, getTextSize)
21
+ this.rows.push({ move: space.height });
22
+ }
23
+
24
+ function addSingleLine(rows, preface, text, marginLeft, klass, shouldAddClasses, getTextSize) {
25
+ if (text) {
26
+ if (preface) {
27
+ if (typeof text === 'string')
28
+ text = preface + text
29
+ else
30
+ text = [{text: preface}].concat(text)
31
+ }
32
+ klass = shouldAddClasses ? 'abcjs-extra-text '+klass : ''
33
+ richText(rows, text, 'historyfont', klass, "description", marginLeft, {absElemType: "extraText", anchor: 'start'}, getTextSize)
34
+ }
35
+
36
+ }
19
37
 
20
- for (var j = 0; j < unalignedWords.length; j++) {
21
- if (unalignedWords[j] === '')
22
- this.rows.push({ move: space.height });
23
- else if (typeof unalignedWords[j] === 'string') {
24
- addTextIf(this.rows, { marginLeft: paddingLeft, text: unalignedWords[j], font: defFont, klass: klass, inGroup: true, name: "words" }, getTextSize);
38
+ function addMultiLine(rows, preface, content, marginLeft, defFont, absElemType, groupName, klass, name, spacing, shouldAddClasses, getTextSize) {
39
+ if (content) {
40
+ klass = shouldAddClasses ? 'abcjs-extra-text '+klass : ''
41
+ var size = getTextSize.calc("A", defFont, klass);
42
+ if (typeof content === 'string') {
43
+ if (preface)
44
+ content = preface + "\n" + content
45
+ addTextIf(rows, { marginLeft: marginLeft, text: content, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle', klass: klass }, getTextSize);
46
+ //rows.push({move: size.height*3/4})
25
47
  } else {
26
- var largestY = 0;
27
- var offsetX = 0;
28
- for (var k = 0; k < unalignedWords[j].length; k++) {
29
- var thisWord = unalignedWords[j][k];
30
- var font = (thisWord.font) ? thisWord.font : defFont;
31
- this.rows.push({
32
- left: paddingLeft + offsetX,
33
- text: thisWord.text,
34
- font: font,
35
- anchor: 'start'
36
- });
37
- var size = getTextSize.calc(thisWord.text, defFont, klass);
38
- largestY = Math.max(largestY, size.height);
39
- offsetX += size.width;
40
- // If the phrase ends in a space, then that is not counted in the width, so we need to add that in ourselves.
41
- if (thisWord.text[thisWord.text.length - 1] === ' ') {
42
- offsetX += space.width;
43
- }
48
+ rows.push({ startGroup: groupName, klass: klass, name: name });
49
+ rows.push({move: spacing.info})
50
+ if (preface) {
51
+ addTextIf(rows, { marginLeft: marginLeft, text: preface, font: defFont, absElemType: "extraText", name: name, 'dominant-baseline': 'middle' }, getTextSize);
52
+ rows.push({move: size.height*3/4})
44
53
  }
45
- this.rows.push({ move: largestY });
54
+
55
+ for (var j = 0; j < content.length; j++) {
56
+ richText(rows, content[j], defFont, '', name, marginLeft, {anchor: 'start'}, getTextSize)
57
+ // TODO-PER: Hack! the string and rich lines should have used up the same amount of space without this.
58
+ if (j < content.length-1 && typeof content[j] === 'string' && typeof content[j+1] !== 'string')
59
+ rows.push({move: size.height*3/4})
60
+ }
61
+ rows.push({ endGroup: groupName, absElemType: absElemType, startChar: -1, endChar: -1, name: name });
62
+ rows.push({move: size.height})
46
63
  }
47
64
  }
48
- this.rows.push({ move: space.height * 2 });
49
- this.rows.push({ endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords" });
50
65
  }
66
+ BottomText.prototype.extraText = function (metaText, marginLeft, spacing, shouldAddClasses, getTextSize) {
67
+ addSingleLine(this.rows, "Book: ", metaText.book, marginLeft, 'abcjs-book', shouldAddClasses, getTextSize)
68
+ addSingleLine(this.rows, "Source: ", metaText.source, marginLeft, 'abcjs-source', shouldAddClasses, getTextSize)
69
+ addSingleLine(this.rows, "Discography: ", metaText.discography, marginLeft, 'abcjs-discography', shouldAddClasses, getTextSize)
70
+
71
+ addMultiLine(this.rows, 'Notes:', metaText.notes, marginLeft, 'historyfont', "extraText", "notes", 'abcjs-notes', "description", spacing, shouldAddClasses, getTextSize)
72
+
73
+ addSingleLine(this.rows, "Transcription: ", metaText.transcription, marginLeft, 'abcjs-transcription', shouldAddClasses, getTextSize)
74
+
75
+ addMultiLine(this.rows, "History:", metaText.history, marginLeft, 'historyfont', "extraText", "history", 'abcjs-history', "description", spacing, shouldAddClasses, getTextSize)
76
+
77
+ addSingleLine(this.rows, "Copyright: ", metaText['abc-copyright'], marginLeft, 'abcjs-copyright', shouldAddClasses, getTextSize)
78
+ addSingleLine(this.rows, "Creator: ", metaText['abc-creator'], marginLeft, 'abcjs-creator', shouldAddClasses, getTextSize)
79
+ addSingleLine(this.rows, "Edited By: ", metaText['abc-edited-by'], marginLeft, 'abcjs-edited-by', shouldAddClasses, getTextSize)
51
80
 
52
- BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) {
53
- var extraText = "";
54
- if (metaText.book) extraText += "Book: " + metaText.book + "\n";
55
- if (metaText.source) extraText += "Source: " + metaText.source + "\n";
56
- if (metaText.discography) extraText += "Discography: " + metaText.discography + "\n";
57
- if (metaText.notes) extraText += "Notes: " + metaText.notes + "\n";
58
- if (metaText.transcription) extraText += "Transcription: " + metaText.transcription + "\n";
59
- if (metaText.history) extraText += "History: " + metaText.history + "\n";
60
- if (metaText['abc-copyright']) extraText += "Copyright: " + metaText['abc-copyright'] + "\n";
61
- if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n";
62
- if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n";
63
- if (extraText.length > 0) {
64
- addTextIf(this.rows, { marginLeft: marginLeft, text: extraText, font: 'historyfont', klass: 'meta-bottom extra-text', marginTop: spacing.info, absElemType: "extraText", name: "description" }, getTextSize);
65
- }
66
81
  }
67
82
 
68
83
  BottomText.prototype.footer = function (footer, width, paddingLeft, getTextSize) {
@@ -0,0 +1,51 @@
1
+ const addTextIf = require("../add-text-if");
2
+
3
+ function richText(rows, str, defFont, klass, name, paddingLeft, attr, getTextSize) {
4
+ var space = getTextSize.calc("i", defFont, klass);
5
+ if (str === '') {
6
+ rows.push({ move: space.height });
7
+ } else {
8
+ if (typeof str === 'string') {
9
+ addTextIf(rows, { marginLeft: paddingLeft, text: str, font: defFont, klass: klass, marginTop: attr.marginTop, anchor: attr.anchor, absElemType: attr.absElemType, info: attr.info, name: name }, getTextSize);
10
+ return
11
+ }
12
+ if (attr.marginTop)
13
+ rows.push({move: attr.marginTop})
14
+
15
+ var largestY = 0;
16
+ var gap = 0;
17
+ var row = {
18
+ left: paddingLeft,
19
+ anchor: attr.anchor,
20
+ phrases: []
21
+ }
22
+ if (klass)
23
+ row.klass = klass
24
+ rows.push(row)
25
+ for (var k = 0; k < str.length; k++) {
26
+ var thisWord = str[k];
27
+ var font = (thisWord.font) ? thisWord.font : getTextSize.attr(defFont, klass).font;
28
+ var phrase = {
29
+ content: thisWord.text,
30
+ }
31
+ if (font)
32
+ phrase.attrs = {
33
+ "font-family": getTextSize.getFamily(font.face),
34
+ "font-size": font.size,
35
+ "font-weight": font.weight,
36
+ "font-style": font.style,
37
+ "font-decoration": font.decoration,
38
+ }
39
+ //if (thisWord.text) {
40
+ row.phrases.push(phrase);
41
+ var size = getTextSize.calc(thisWord.text, font, klass);
42
+ largestY = Math.max(largestY, size.height);
43
+ if (thisWord.text[thisWord.text.length - 1] === ' ') {
44
+ gap = space.width
45
+ }
46
+ }
47
+ rows.push({ move: largestY });
48
+ }
49
+ }
50
+
51
+ module.exports = richText;
@@ -1,6 +1,7 @@
1
1
  const addTextIf = require("../add-text-if");
2
+ const richText = require("./rich-text");
2
3
 
3
- function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, paddingLeft, spacing, shouldAddClasses, getTextSize) {
4
5
  this.rows = [];
5
6
 
6
7
  if (metaText.header && isPrint) {
@@ -18,12 +19,14 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
18
19
  var tAnchor = formatting.titleleft ? 'start' : 'middle';
19
20
  var tLeft = formatting.titleleft ? paddingLeft : paddingLeft + width / 2;
20
21
  if (metaText.title) {
21
- addTextIf(this.rows, { marginLeft: tLeft, text: metaText.title, font: 'titlefont', klass: 'title meta-top', marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title, name: "title" }, getTextSize);
22
+ var klass = shouldAddClasses ? 'abcjs-title' : ''
23
+ richText(this.rows, metaText.title, "titlefont", klass, 'title', tLeft, {marginTop: spacing.title, anchor: tAnchor, absElemType: "title", info: metaTextInfo.title}, getTextSize)
22
24
  }
23
25
  if (lines.length) {
24
26
  var index = 0;
25
27
  while (index < lines.length && lines[index].subtitle) {
26
- addTextIf(this.rows, { marginLeft: tLeft, text: lines[index].subtitle.text, font: 'subtitlefont', klass: 'text meta-top subtitle', marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle, name: "subtitle" }, getTextSize);
28
+ var klass = shouldAddClasses ? 'abcjs-text abcjs-subtitle' : ''
29
+ richText(this.rows, lines[index].subtitle.text, "subtitlefont", klass, 'subtitle', tLeft, {marginTop: spacing.subtitle, anchor: tAnchor, absElemType: "subtitle", info: lines[index].subtitle}, getTextSize)
27
30
  index++;
28
31
  }
29
32
  }
@@ -32,22 +35,45 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
32
35
  this.rows.push({ move: spacing.composer });
33
36
  if (metaText.rhythm && metaText.rhythm.length > 0) {
34
37
  var noMove = !!(metaText.composer || metaText.origin);
35
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: 'meta-top rhythm', absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
38
+ var klass = shouldAddClasses ? 'abcjs-rhythm' : ''
39
+ addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.rhythm, font: 'infofont', klass: klass, absElemType: "rhythm", noMove: noMove, info: metaTextInfo.rhythm, name: "rhythm" }, getTextSize);
36
40
  }
37
- var composerLine = "";
38
- if (metaText.composer) composerLine += metaText.composer;
39
- if (metaText.origin) composerLine += ' (' + metaText.origin + ')';
40
- if (composerLine.length > 0) {
41
- addTextIf(this.rows, { marginLeft: paddingLeft + width, text: composerLine, font: 'composerfont', klass: 'meta-top composer', anchor: "end", absElemType: "composer", info: metaTextInfo.composer, name: "composer" }, getTextSize);
41
+ var hasSimpleComposerLine = true
42
+ if (metaText.composer && typeof metaText.composer !== 'string')
43
+ hasSimpleComposerLine = false
44
+ if (metaText.origin && typeof metaText.origin !== 'string')
45
+ hasSimpleComposerLine = false
46
+
47
+ var composerLine = metaText.composer ? metaText.composer : '';
48
+ if (metaText.origin) {
49
+ if (typeof composerLine === 'string' && typeof metaText.origin === 'string')
50
+ composerLine += ' (' + metaText.origin + ')';
51
+ else if (typeof composerLine === 'string' && typeof metaText.origin !== 'string') {
52
+ composerLine = [{text:composerLine}]
53
+ composerLine.push({text:" ("})
54
+ composerLine = composerLine.concat(metaText.origin)
55
+ composerLine.push({text:")"})
56
+ } else {
57
+ composerLine.push({text:" ("})
58
+ composerLine = composerLine.concat(metaText.origin)
59
+ composerLine.push({text:")"})
60
+ }
61
+ }
62
+ if (composerLine) {
63
+ var klass = shouldAddClasses ? 'abcjs-composer' : ''
64
+ richText(this.rows, composerLine, 'composerfont', klass, "composer", paddingLeft+width, {anchor: "end", absElemType: "composer", info: metaTextInfo.composer, ingroup: true}, getTextSize)
42
65
  }
43
66
  }
44
67
 
45
68
  if (metaText.author && metaText.author.length > 0) {
46
- addTextIf(this.rows, { marginLeft: paddingLeft + width, text: metaText.author, font: 'composerfont', klass: 'meta-top author', anchor: "end", absElemType: "author", info: metaTextInfo.author, name: "author" }, getTextSize);
69
+ var klass = shouldAddClasses ? 'abcjs-author' : ''
70
+ richText(this.rows, metaText.author, 'composerfont', klass, "author", paddingLeft+width, {anchor: "end", absElemType: "author", info: metaTextInfo.author}, getTextSize)
47
71
  }
48
72
 
49
73
  if (metaText.partOrder && metaText.partOrder.length > 0) {
50
- addTextIf(this.rows, { marginLeft: paddingLeft, text: metaText.partOrder, font: 'partsfont', klass: 'meta-top part-order', absElemType: "partOrder", info: metaTextInfo.partOrder, name: "part-order" }, getTextSize);
74
+ var klass = shouldAddClasses ? 'abcjs-part-order' : ''
75
+ richText(this.rows, metaText.partOrder, 'partsfont', klass, "part-order", paddingLeft, {absElemType: "partOrder", info: metaTextInfo.partOrder, anchor: 'start'}, getTextSize)
76
+
51
77
  }
52
78
  }
53
79
 
@@ -86,7 +86,7 @@ var glyphs =
86
86
  's': { d: [['M', 4.47, -8.73], ['c', 0.09, 0.00, 0.36, -0.03, 0.57, -0.03], ['c', 0.75, 0.03, 1.29, 0.24, 1.71, 0.63], ['c', 0.51, 0.54, 0.66, 1.26, 0.36, 1.83], ['c', -0.24, 0.42, -0.63, 0.57, -1.11, 0.42], ['c', -0.33, -0.09, -0.60, -0.36, -0.60, -0.57], ['c', 0.00, -0.03, 0.06, -0.21, 0.15, -0.39], ['c', 0.12, -0.21, 0.15, -0.33, 0.18, -0.48], ['c', 0.00, -0.24, -0.06, -0.48, -0.15, -0.60], ['c', -0.15, -0.21, -0.42, -0.24, -0.75, -0.15], ['c', -0.27, 0.06, -0.48, 0.18, -0.69, 0.36], ['c', -0.39, 0.39, -0.51, 0.96, -0.33, 1.38], ['c', 0.09, 0.21, 0.42, 0.51, 0.78, 0.72], ['c', 1.11, 0.69, 1.59, 1.11, 1.89, 1.68], ['c', 0.21, 0.39, 0.24, 0.78, 0.15, 1.29], ['c', -0.18, 1.20, -1.17, 2.16, -2.52, 2.52], ['c', -1.02, 0.24, -1.95, 0.12, -2.70, -0.42], ['c', -0.72, -0.51, -0.99, -1.47, -0.60, -2.19], ['c', 0.24, -0.48, 0.72, -0.63, 1.17, -0.42], ['c', 0.33, 0.18, 0.54, 0.45, 0.57, 0.81], ['c', 0.00, 0.21, -0.03, 0.30, -0.33, 0.51], ['c', -0.33, 0.24, -0.39, 0.42, -0.27, 0.69], ['c', 0.06, 0.15, 0.21, 0.27, 0.45, 0.33], ['c', 0.30, 0.09, 0.87, 0.09, 1.20, 0.00], ['c', 0.75, -0.21, 1.23, -0.72, 1.29, -1.35], ['c', 0.03, -0.42, -0.15, -0.81, -0.54, -1.20], ['c', -0.24, -0.24, -0.48, -0.42, -1.41, -1.02], ['c', -0.69, -0.42, -1.05, -0.93, -1.05, -1.47], ['c', 0.00, -0.39, 0.12, -0.87, 0.30, -1.23], ['c', 0.27, -0.57, 0.78, -1.05, 1.38, -1.35], ['c', 0.24, -0.12, 0.63, -0.27, 0.90, -0.30], ['z']], w: 6.632, h: 8.758 },
87
87
  'z': { d: [['M', 2.64, -7.95], ['c', 0.36, -0.09, 0.81, -0.03, 1.71, 0.27], ['c', 0.78, 0.21, 0.96, 0.27, 1.74, 0.30], ['c', 0.87, 0.06, 1.02, 0.03, 1.38, -0.21], ['c', 0.21, -0.15, 0.33, -0.15, 0.48, -0.06], ['c', 0.15, 0.09, 0.21, 0.30, 0.15, 0.45], ['c', -0.03, 0.06, -1.26, 1.26, -2.76, 2.67], ['l', -2.73, 2.55], ['l', 0.54, 0.03], ['c', 0.54, 0.03, 0.72, 0.03, 2.01, 0.15], ['c', 0.36, 0.03, 0.90, 0.06, 1.20, 0.09], ['c', 0.66, 0.00, 0.81, -0.03, 1.02, -0.24], ['c', 0.30, -0.30, 0.39, -0.72, 0.27, -1.23], ['c', -0.06, -0.27, -0.06, -0.27, -0.03, -0.39], ['c', 0.15, -0.30, 0.54, -0.27, 0.69, 0.03], ['c', 0.15, 0.33, 0.27, 1.02, 0.27, 1.50], ['c', 0.00, 1.47, -1.11, 2.70, -2.52, 2.79], ['c', -0.57, 0.03, -1.02, -0.09, -2.01, -0.51], ['c', -1.02, -0.42, -1.23, -0.48, -2.13, -0.54], ['c', -0.81, -0.06, -0.96, -0.03, -1.26, 0.18], ['c', -0.12, 0.06, -0.24, 0.12, -0.27, 0.12], ['c', -0.27, 0.00, -0.45, -0.30, -0.36, -0.51], ['c', 0.03, -0.06, 1.32, -1.32, 2.91, -2.79], ['l', 2.88, -2.73], ['c', -0.03, 0.00, -0.21, 0.03, -0.42, 0.06], ['c', -0.21, 0.03, -0.78, 0.09, -1.23, 0.12], ['c', -1.11, 0.12, -1.23, 0.15, -1.95, 0.27], ['c', -0.72, 0.15, -1.17, 0.18, -1.29, 0.09], ['c', -0.27, -0.18, -0.21, -0.75, 0.12, -1.26], ['c', 0.39, -0.60, 0.93, -1.02, 1.59, -1.20], ['z']], w: 8.573, h: 8.743 },
88
88
  '+': { d: [['M', 3.48, -9.3], ['c', 0.18, -0.09, 0.36, -0.09, 0.54, 0.00], ['c', 0.18, 0.09, 0.24, 0.15, 0.33, 0.30], ['l', 0.06, 0.15], ['l', 0.00, 1.29], ['l', 0.00, 1.29], ['l', 1.29, 0.00], ['c', 1.23, 0.00, 1.29, 0.00, 1.41, 0.06], ['c', 0.06, 0.03, 0.15, 0.09, 0.18, 0.12], ['c', 0.12, 0.09, 0.21, 0.33, 0.21, 0.48], ['c', 0.00, 0.15, -0.09, 0.39, -0.21, 0.48], ['c', -0.03, 0.03, -0.12, 0.09, -0.18, 0.12], ['c', -0.12, 0.06, -0.18, 0.06, -1.41, 0.06], ['l', -1.29, 0.00], ['l', 0.00, 1.29], ['c', 0.00, 1.23, 0.00, 1.29, -0.06, 1.41], ['c', -0.09, 0.18, -0.15, 0.24, -0.30, 0.33], ['c', -0.21, 0.09, -0.39, 0.09, -0.57, 0.00], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.06, -0.12, -0.06, -0.18, -0.06, -1.41], ['l', 0.00, -1.29], ['l', -1.29, 0.00], ['c', -1.23, 0.00, -1.29, 0.00, -1.41, -0.06], ['c', -0.18, -0.09, -0.24, -0.15, -0.33, -0.33], ['c', -0.09, -0.18, -0.09, -0.36, 0.00, -0.54], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['l', 0.15, -0.06], ['l', 1.26, 0.00], ['l', 1.29, 0.00], ['l', 0.00, -1.29], ['c', 0.00, -1.23, 0.00, -1.29, 0.06, -1.41], ['c', 0.09, -0.18, 0.15, -0.24, 0.33, -0.33], ['z']], w: 7.507, h: 7.515 },
89
- ',': { d: [['M', 1.32, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']], w: 3.452, h: 8.143 },
89
+ ',': { d: [['M', 1.85, -3.36], ['c', 0.57, -0.15, 1.17, 0.03, 1.59, 0.45], ['c', 0.45, 0.45, 0.60, 0.96, 0.51, 1.89], ['c', -0.09, 1.23, -0.42, 2.46, -0.99, 3.93], ['c', -0.30, 0.72, -0.72, 1.62, -0.78, 1.68], ['c', -0.18, 0.21, -0.51, 0.18, -0.66, -0.06], ['c', -0.03, -0.06, -0.06, -0.15, -0.06, -0.18], ['c', 0.00, -0.06, 0.12, -0.33, 0.24, -0.63], ['c', 0.84, -1.80, 1.02, -2.61, 0.69, -3.24], ['c', -0.12, -0.24, -0.27, -0.36, -0.75, -0.60], ['c', -0.36, -0.15, -0.42, -0.21, -0.60, -0.39], ['c', -0.69, -0.69, -0.69, -1.71, 0.00, -2.40], ['c', 0.21, -0.21, 0.51, -0.39, 0.81, -0.45], ['z']], w: 3.452, h: 8.143 },
90
90
  '-': { d: [['M', 0.18, -5.34], ['c', 0.09, -0.06, 0.15, -0.06, 2.31, -0.06], ['c', 2.46, 0.00, 2.37, 0.00, 2.46, 0.21], ['c', 0.12, 0.21, 0.03, 0.42, -0.15, 0.54], ['c', -0.09, 0.06, -0.15, 0.06, -2.28, 0.06], ['c', -2.16, 0.00, -2.22, 0.00, -2.31, -0.06], ['c', -0.27, -0.15, -0.27, -0.54, -0.03, -0.69], ['z']], w: 5.001, h: 0.81 },
91
91
  '.': { d: [['M', 1.32, -3.36], ['c', 1.05, -0.27, 2.10, 0.57, 2.10, 1.65], ['c', 0.00, 1.08, -1.05, 1.92, -2.10, 1.65], ['c', -0.90, -0.21, -1.50, -1.14, -1.26, -2.04], ['c', 0.12, -0.63, 0.63, -1.11, 1.26, -1.26], ['z']], w: 3.413, h: 3.402 },
92
92
  'scripts.wedge': { d: [['M', -3.66, -7.44], ['c', 0.06, -0.09, 0.00, -0.09, 0.81, 0.03], ['c', 1.86, 0.30, 3.84, 0.30, 5.73, 0.00], ['c', 0.78, -0.12, 0.72, -0.12, 0.78, -0.03], ['c', 0.15, 0.15, 0.12, 0.24, -0.24, 0.60], ['c', -0.93, 0.93, -1.98, 2.76, -2.67, 4.62], ['c', -0.30, 0.78, -0.51, 1.71, -0.51, 2.13], ['c', 0.00, 0.15, 0.00, 0.18, -0.06, 0.27], ['c', -0.12, 0.09, -0.24, 0.09, -0.36, 0.00], ['c', -0.06, -0.09, -0.06, -0.12, -0.06, -0.27], ['c', 0.00, -0.42, -0.21, -1.35, -0.51, -2.13], ['c', -0.69, -1.86, -1.74, -3.69, -2.67, -4.62], ['c', -0.36, -0.36, -0.39, -0.45, -0.24, -0.60], ['z']], w: 7.49, h: 7.752 },
@@ -105,7 +105,7 @@ glyphs['noteheads.slash.quarter'] = { d: [['M', 9, -6], ['l', 0, 4], ['l', -9, 9
105
105
 
106
106
  glyphs['noteheads.harmonic.quarter'] = { d: [['M', 3.63, -4.02], ['c', 0.09, -0.06, 0.18, -0.09, 0.24, -0.03], ['c', 0.03, 0.03, 0.87, 0.93, 1.83, 2.01], ['c', 1.50, 1.65, 1.80, 1.98, 1.80, 2.04], ['c', 0.00, 0.06, -0.30, 0.39, -1.80, 2.04], ['c', -0.96, 1.08, -1.80, 1.98, -1.83, 2.01], ['c', -0.06, 0.06, -0.15, 0.03, -0.24, -0.03], ['c', -0.12, -0.09, -3.54, -3.84, -3.60, -3.93], ['c', -0.03, -0.03, -0.03, -0.09, -0.03, -0.15], ['c', 0.03, -0.06, 3.45, -3.84, 3.63, -3.96], ['z']], w: 7.5, h: 8.165 };
107
107
 
108
- glyphs['noteheads.triangle.quarter'] = { d: [['M', 0, 0], ['l', 9, 0], ['l', -4.5, -9], ['z']], w: 9, h: 9 };
108
+ glyphs['noteheads.triangle.quarter'] = { d: [['M', 0, 4], ['l', 9, 0], ['l', -4.5, -9], ['z']], w: 9, h: 9 };
109
109
 
110
110
  var pathClone = function (pathArray) {
111
111
  var res = [];
@@ -16,7 +16,10 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
16
16
  drawTempo(renderer, child);
17
17
  break;
18
18
  default:
19
- drawRelativeElement(renderer, child, bartop);
19
+ var el = drawRelativeElement(renderer, child, bartop);
20
+ if (child.type === "symbol" && child.c && child.c.indexOf('notehead') >= 0) {
21
+ el.setAttribute('class', 'abcjs-notehead')
22
+ }
20
23
  }
21
24
  }
22
25
  var klass = params.type;
@@ -6,7 +6,10 @@ var Selectables = require('./selectables');
6
6
 
7
7
  function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber, lineOffset) {
8
8
  var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber);
9
- renderer.paper.openGroup()
9
+ var groupClasses = {}
10
+ if (classes.shouldAddClasses)
11
+ groupClasses.klass = "abcjs-meta-top"
12
+ renderer.paper.openGroup(groupClasses)
10
13
  renderer.moveY(renderer.padding.top);
11
14
  nonMusic(renderer, abcTune.topText, selectables);
12
15
  renderer.paper.closeGroup()
@@ -16,7 +19,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
16
19
  classes.incrLine();
17
20
  var abcLine = abcTune.lines[line];
18
21
  if (abcLine.staff) {
19
- renderer.paper.openGroup()
22
+ if (classes.shouldAddClasses)
23
+ groupClasses.klass = "abcjs-staff l" + classes.lineNumber
24
+ renderer.paper.openGroup(groupClasses)
20
25
  if (abcLine.vskip) {
21
26
  renderer.moveY(abcLine.vskip);
22
27
  }
@@ -27,7 +32,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
27
32
  staffgroups.push(staffgroup);
28
33
  renderer.paper.closeGroup()
29
34
  } else if (abcLine.nonMusic) {
30
- renderer.paper.openGroup()
35
+ if (classes.shouldAddClasses)
36
+ groupClasses.klass = "abcjs-non-music"
37
+ renderer.paper.openGroup(groupClasses)
31
38
  nonMusic(renderer, abcLine.nonMusic, selectables);
32
39
  renderer.paper.closeGroup()
33
40
  }
@@ -35,7 +42,9 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
35
42
 
36
43
  classes.reset();
37
44
  if (abcTune.bottomText && abcTune.bottomText.rows && abcTune.bottomText.rows.length > 0) {
38
- renderer.paper.openGroup()
45
+ if (classes.shouldAddClasses)
46
+ groupClasses.klass = "abcjs-meta-bottom"
47
+ renderer.paper.openGroup(groupClasses)
39
48
  renderer.moveY(24); // TODO-PER: Empirically discovered. What variable should this be?
40
49
  nonMusic(renderer, abcTune.bottomText, selectables);
41
50
  renderer.paper.closeGroup()