abcjs 6.0.0-beta.32 → 6.0.0-beta.36

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 (97) hide show
  1. package/README.md +13 -7
  2. package/RELEASE.md +130 -0
  3. package/dist/abcjs-basic-min.js +2 -2
  4. package/dist/abcjs-basic.js +3763 -825
  5. package/dist/abcjs-basic.js.map +1 -1
  6. package/dist/abcjs-plugin-min.js +2 -2
  7. package/dist/report-basic.html +37 -0
  8. package/dist/report-before-glyph-compress.html +37 -0
  9. package/dist/report-brown-ts-target-es5.html +37 -0
  10. package/dist/report-dev-orig-no-babel.html +37 -0
  11. package/dist/report-synth.html +37 -0
  12. package/docker-build.sh +1 -0
  13. package/glyphs.json +1 -0
  14. package/package.json +9 -9
  15. package/src/api/abc_tablatures.js +144 -0
  16. package/src/api/abc_timing_callbacks.js +49 -26
  17. package/src/api/abc_tunebook.js +10 -1
  18. package/src/api/abc_tunebook_svg.js +16 -22
  19. package/src/data/abc_tune.js +90 -25
  20. package/src/data/deline-tune.js +199 -0
  21. package/src/edit/abc_editor.js +33 -11
  22. package/src/midi/abc_midi_create.js +6 -2
  23. package/src/parse/abc_parse.js +10 -6
  24. package/src/parse/abc_parse_directive.js +19 -12
  25. package/src/parse/abc_parse_header.js +12 -12
  26. package/src/parse/abc_parse_music.js +15 -5
  27. package/src/parse/tune-builder.js +23 -30
  28. package/src/parse/wrap_lines.js +13 -36
  29. package/src/synth/abc_midi_flattener.js +44 -29
  30. package/src/synth/abc_midi_sequencer.js +52 -13
  31. package/src/synth/create-synth.js +22 -7
  32. package/src/synth/load-note.js +31 -65
  33. package/src/synth/place-note.js +59 -60
  34. package/src/synth/register-audio-context.js +4 -1
  35. package/src/synth/supports-audio.js +9 -8
  36. package/src/synth/synth-controller.js +5 -3
  37. package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
  38. package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
  39. package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
  40. package/src/tablatures/instruments/string-patterns.js +277 -0
  41. package/src/tablatures/instruments/string-tablature.js +56 -0
  42. package/src/tablatures/instruments/tab-note.js +282 -0
  43. package/src/tablatures/instruments/tab-notes.js +41 -0
  44. package/src/tablatures/instruments/violin/tab-violin.js +47 -0
  45. package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
  46. package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
  47. package/src/tablatures/tab-absolute-elements.js +310 -0
  48. package/src/tablatures/tab-common.js +29 -0
  49. package/src/tablatures/tab-renderer.js +243 -0
  50. package/src/tablatures/transposer.js +110 -0
  51. package/src/test/abc_parser_lint.js +62 -6
  52. package/src/write/abc_absolute_element.js +2 -2
  53. package/src/write/abc_abstract_engraver.js +9 -7
  54. package/src/write/abc_create_key_signature.js +1 -0
  55. package/src/write/abc_create_note_head.js +1 -1
  56. package/src/write/abc_engraver_controller.js +22 -9
  57. package/src/write/abc_glyphs.js +5 -2
  58. package/src/write/abc_relative_element.js +11 -3
  59. package/src/write/abc_renderer.js +5 -1
  60. package/src/write/add-chord.js +5 -2
  61. package/src/write/add-text-if.js +33 -0
  62. package/src/write/bottom-text.js +8 -29
  63. package/src/write/draw/absolute.js +12 -14
  64. package/src/write/draw/brace.js +3 -3
  65. package/src/write/draw/crescendo.js +1 -1
  66. package/src/write/draw/draw.js +3 -4
  67. package/src/write/draw/dynamics.js +8 -1
  68. package/src/write/draw/ending.js +4 -3
  69. package/src/write/draw/group-elements.js +10 -8
  70. package/src/write/draw/non-music.js +11 -6
  71. package/src/write/draw/print-line.js +24 -0
  72. package/src/write/draw/print-stem.js +12 -11
  73. package/src/write/draw/print-symbol.js +11 -10
  74. package/src/write/draw/relative.js +33 -13
  75. package/src/write/draw/selectables.js +9 -6
  76. package/src/write/draw/staff-group.js +45 -9
  77. package/src/write/draw/staff-line.js +3 -17
  78. package/src/write/draw/staff.js +15 -2
  79. package/src/write/draw/tab-line.js +40 -0
  80. package/src/write/draw/tempo.js +7 -7
  81. package/src/write/draw/text.js +11 -4
  82. package/src/write/draw/tie.js +2 -2
  83. package/src/write/draw/triplet.js +3 -3
  84. package/src/write/draw/voice.js +10 -2
  85. package/src/write/format-jazz-chord.js +15 -0
  86. package/src/write/free-text.js +20 -12
  87. package/src/write/layout/VoiceElements.js +33 -1
  88. package/src/write/layout/beam.js +2 -0
  89. package/src/write/layout/staffGroup.js +37 -2
  90. package/src/write/layout/voice.js +2 -1
  91. package/src/write/selection.js +15 -5
  92. package/src/write/separator.js +1 -1
  93. package/src/write/subtitle.js +3 -3
  94. package/src/write/svg.js +41 -14
  95. package/src/write/top-text.js +19 -25
  96. package/types/index.d.ts +1007 -39
  97. package/version.js +1 -1
@@ -11,17 +11,12 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
11
11
  elementGroup.beginGroup(renderer.paper, renderer.controller);
12
12
  for (var i=0; i<params.children.length; i++) {
13
13
  var child = params.children[i];
14
- var el;
15
14
  switch (child.type) {
16
15
  case "TempoElement":
17
- el = drawTempo(renderer, child);
18
- if (el)
19
- params.elemset = params.elemset.concat(el);
16
+ drawTempo(renderer, child);
20
17
  break;
21
18
  default:
22
- el = drawRelativeElement(renderer, child, bartop);
23
- if (el)
24
- params.elemset.push(el);
19
+ drawRelativeElement(renderer, child, bartop);
25
20
  }
26
21
  }
27
22
  var klass = params.type;
@@ -35,16 +30,19 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
35
30
  }
36
31
  }
37
32
  }
38
- var g = elementGroup.endGroup(klass);
33
+ var g = elementGroup.endGroup(klass, params.type);
39
34
  if (g) {
40
- if (isTempo && params.elemset.length > 0) {
41
- // If this is a tempo element there are text portions that are in params.elemset[0] already.
42
- // The graphic portion (the drawn note) is in g and that should just be added to the text so that it is a single element for selecting.
43
- renderer.paper.moveElementToChild(params.elemset[0], g);
44
- selectables.add(params, params.elemset[0], false, staffPos);
35
+ if (isTempo) {
36
+ params.startChar = params.abcelem.startChar;
37
+ params.endChar = params.abcelem.endChar;
38
+ selectables.add(params, g, false, staffPos);
45
39
  } else {
46
40
  params.elemset.push(g);
47
- selectables.add(params, g, params.type === 'note', staffPos);
41
+ var isSelectable = false;
42
+ if (params.type === 'note' || params.type === 'tabNumber') {
43
+ isSelectable = true;
44
+ }
45
+ selectables.add(params, g, isSelectable, staffPos);
48
46
  }
49
47
  } else if (params.elemset.length > 0)
50
48
  selectables.add(params, params.elemset[0], params.type === 'note', staffPos);
@@ -45,7 +45,7 @@ function straightPath(renderer, xLeft, yTop, yBottom, type) {
45
45
  -wCurve*0.1, -hCurve*0.3,
46
46
  -wCurve, -hCurve-spacing.STEP // left bottom
47
47
  );
48
- return renderer.paper.path({path:pathString, stroke:renderer.foregroundColor, fill:renderer.foregroundColor, 'class': renderer.controller.classes.generate(type)});
48
+ return renderer.paper.path({path:pathString, stroke:renderer.foregroundColor, fill:renderer.foregroundColor, 'class': renderer.controller.classes.generate(type), "data-name": type});
49
49
  }
50
50
 
51
51
  function curvyPath(renderer, xLeft, yTop, yBottom, type) {
@@ -61,7 +61,7 @@ function curvyPath(renderer, xLeft, yTop, yBottom, type) {
61
61
  [0, 17.5, -7.5, 6.6, -5, 20, 0],
62
62
  [yHeight/2, yHeight/1.46, yHeight/1.22, yHeight, yHeight/1.19, yHeight/1.42, yHeight/2]);
63
63
 
64
- return renderer.paper.path({path:pathString, stroke:renderer.foregroundColor, fill:renderer.foregroundColor, 'class': renderer.controller.classes.generate(type)});
64
+ return renderer.paper.path({path:pathString, stroke:renderer.foregroundColor, fill:renderer.foregroundColor, 'class': renderer.controller.classes.generate(type), "data-name": type});
65
65
  }
66
66
 
67
67
  function curve(xLeft, yTop, xCurve, yCurve) {
@@ -78,7 +78,7 @@ function curve(xLeft, yTop, xCurve, yCurve) {
78
78
  var draw = function (renderer, xLeft, yTop, yBottom, type, header, selectables) {//Tony
79
79
  var ret;
80
80
  if (header) {
81
- renderer.paper.openGroup({klass: renderer.controller.classes.generate("staff-extra voice-name")});
81
+ renderer.paper.openGroup({klass: renderer.controller.classes.generate("staff-extra voice-name"), "data-name": type});
82
82
  var position = yTop + (yBottom - yTop) / 2;
83
83
  position = position - renderer.controller.getTextSize.baselineToCenter(header, "voicefont", 'staff-extra voice-name', 0, 1);
84
84
 
@@ -32,7 +32,7 @@ var drawLine = function (renderer, y1, y2, y3, y4, left, right) {
32
32
 
33
33
  var pathString = sprintf("M %f %f L %f %f M %f %f L %f %f",
34
34
  left, y1, right, y2, left, y3, right, y4);
35
- return printPath(renderer, {path:pathString, highlight: "stroke", stroke:renderer.foregroundColor, 'class': renderer.controller.classes.generate('dynamics decoration')});
35
+ return printPath(renderer, {path:pathString, highlight: "stroke", stroke:renderer.foregroundColor, 'class': renderer.controller.classes.generate('dynamics decoration'), "data-name": "dynamics"});
36
36
  };
37
37
 
38
38
  module.exports = drawCrescendo;
@@ -9,7 +9,6 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
9
9
  renderer.moveY(renderer.padding.top);
10
10
  nonMusic(renderer, abcTune.topText, selectables);
11
11
  renderer.moveY(renderer.spacing.music);
12
-
13
12
  var staffgroups = [];
14
13
  for (var line = 0; line < abcTune.lines.length; line++) {
15
14
  classes.incrLine();
@@ -20,7 +19,7 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
20
19
  }
21
20
  if (staffgroups.length >= 1)
22
21
  addStaffPadding(renderer, renderer.spacing.staffSeparation, staffgroups[staffgroups.length - 1], abcLine.staffGroup);
23
- var staffgroup = engraveStaffLine(renderer, abcLine.staffGroup, selectables);
22
+ var staffgroup = engraveStaffLine(renderer, abcLine.staffGroup, selectables,line);
24
23
  staffgroup.line = line; // If there are non-music lines then the staffgroup array won't line up with the line array, so this keeps track.
25
24
  staffgroups.push(staffgroup);
26
25
  } else if (abcLine.nonMusic) {
@@ -35,8 +34,8 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
35
34
  return { staffgroups: staffgroups, selectables: selectables.getElements() };
36
35
  }
37
36
 
38
- function engraveStaffLine(renderer, staffGroup, selectables) {
39
- drawStaffGroup(renderer, staffGroup, selectables);
37
+ function engraveStaffLine(renderer, staffGroup, selectables,lineNumber) {
38
+ drawStaffGroup(renderer, staffGroup, selectables,lineNumber);
40
39
  var height = staffGroup.height * spacing.STEP;
41
40
  renderer.y += height;
42
41
  return staffGroup;
@@ -5,7 +5,14 @@ function drawDynamics(renderer, params, selectables) {
5
5
  window.console.error("Dynamic Element y-coordinate not set.");
6
6
  var scalex = 1;
7
7
  var scaley = 1;
8
- var el = printSymbol(renderer, params.anchor.x, params.pitch, params.dec, scalex, scaley, renderer.controller.classes.generate('decoration dynamics'));
8
+ var el = printSymbol(renderer, params.anchor.x, params.pitch, params.dec, {
9
+ scalex: scalex,
10
+ scaley: scaley,
11
+ klass: renderer.controller.classes.generate('decoration dynamics'),
12
+ fill:renderer.foregroundColor,
13
+ stroke: "none",
14
+ name: "dynamics"
15
+ });
9
16
  selectables.wrapSvgEl({el_type: "dynamicDecoration", startChar: -1, endChar: -1, decoration: params.dec}, el);
10
17
  return [el];
11
18
  }
@@ -25,8 +25,8 @@ function drawEnding(renderer, params, linestartx, lineendx, selectables) {
25
25
  pathString += sprintf("M %f %f L %f %f ",
26
26
  linestartx, y, lineendx, y);
27
27
 
28
- renderer.paper.openGroup({klass: renderer.controller.classes.generate("ending")});
29
- printPath(renderer, {path: pathString, stroke: renderer.foregroundColor, fill: renderer.foregroundColor});
28
+ renderer.paper.openGroup({klass: renderer.controller.classes.generate("ending"), "data-name": "ending"});
29
+ printPath(renderer, {path: pathString, stroke: renderer.foregroundColor, fill: renderer.foregroundColor, "data-name": "line"});
30
30
  if (params.anchor1)
31
31
  renderText(renderer, {
32
32
  x: roundNumber(linestartx + 5),
@@ -35,7 +35,8 @@ function drawEnding(renderer, params, linestartx, lineendx, selectables) {
35
35
  type: 'repeatfont',
36
36
  klass: 'ending',
37
37
  anchor: "start",
38
- noClass: true
38
+ noClass: true,
39
+ name: params.text
39
40
  });
40
41
  var g = renderer.paper.closeGroup();
41
42
  selectables.wrapSvgEl({el_type: "ending", startChar: -1, endChar: -1}, g);
@@ -14,6 +14,7 @@ var roundNumber = require("./round-number");
14
14
  this.path = [];
15
15
  this.lastM = [0, 0];
16
16
  this.ingroup = true;
17
+ this.paper.openGroup();
17
18
  };
18
19
 
19
20
  Group.prototype.isInGroup = function() {
@@ -41,20 +42,21 @@ var roundNumber = require("./round-number");
41
42
  /**
42
43
  * End a group of glyphs that will always be moved, scaled and highlighted together
43
44
  */
44
- Group.prototype.endGroup = function (klass) {
45
+ Group.prototype.endGroup = function (klass, name) {
45
46
  this.ingroup = false;
46
- if (this.path.length === 0) return null;
47
+ //if (this.path.length === 0) return null;
47
48
  var path = "";
48
49
  for (var i = 0; i < this.path.length; i++)
49
50
  path += this.path[i].join(" ");
50
- var ret = this.paper.path({
51
- path: path,
52
- stroke: "none",
53
- fill: this.controller.renderer.foregroundColor,
54
- 'class': this.controller.classes.generate(klass)
55
- });
56
51
  this.path = [];
57
52
 
53
+ var ret = this.paper.closeGroup();
54
+ if (ret) {
55
+ ret.setAttribute("class", this.controller.classes.generate(klass))
56
+ ret.setAttribute("fill", this.controller.renderer.foregroundColor)
57
+ ret.setAttribute("stroke", "none")
58
+ ret.setAttribute("data-name", name)
59
+ }
58
60
  return ret;
59
61
  };
60
62
 
@@ -4,7 +4,9 @@ var renderText = require('./text');
4
4
  function nonMusic(renderer, obj, selectables) {
5
5
  for (var i = 0; i < obj.rows.length; i++) {
6
6
  var row = obj.rows[i];
7
- if (row.move) {
7
+ if (row.absmove) {
8
+ renderer.absolutemoveY(row.absmove);
9
+ } else if (row.move) {
8
10
  renderer.moveY(row.move);
9
11
  } else if (row.text) {
10
12
  var x = row.left ? row.left : 0;
@@ -14,28 +16,31 @@ function nonMusic(renderer, obj, selectables) {
14
16
  text: row.text,
15
17
  type: row.font,
16
18
  klass: row.klass,
19
+ name: row.name,
17
20
  anchor: row.anchor
18
21
  });
19
22
  if (row.absElemType) {
20
23
  selectables.wrapSvgEl({
21
24
  el_type: row.absElemType,
22
- startChar: -1,
23
- endChar: -1,
25
+ name: row.name,
26
+ startChar: row.startChar,
27
+ endChar: row.endChar,
24
28
  text: row.text
25
29
  }, el);
26
30
  }
27
31
  } else if (row.separator) {
28
32
  drawSeparator(renderer, row.separator)
29
33
  } else if (row.startGroup) {
30
- renderer.paper.openGroup({klass: row.klass});
34
+ renderer.paper.openGroup({klass: row.klass, "data-name": row.name});
31
35
  } else if (row.endGroup) {
32
36
  // TODO-PER: also create a history element with the title "row.endGroup"
33
37
  var g = renderer.paper.closeGroup();
34
38
  if (row.absElemType)
35
39
  selectables.wrapSvgEl({
36
40
  el_type: row.absElemType,
37
- startChar: -1,
38
- endChar: -1,
41
+ name: row.name,
42
+ startChar: row.startChar,
43
+ endChar: row.endChar,
39
44
  text: ""
40
45
  }, g);
41
46
  }
@@ -0,0 +1,24 @@
1
+ var sprintf = require('./sprintf');
2
+ var roundNumber = require("./round-number");
3
+
4
+ function printLine(renderer, x1, x2, y , klass, name ,dy ) {
5
+ if (!dy ) dy = 0.35;
6
+ var fill = renderer.foregroundColor;
7
+ x1 = roundNumber(x1);
8
+ x2 = roundNumber(x2);
9
+ var y1 = roundNumber(y - dy);
10
+ var y2 = roundNumber(y + dy);
11
+ var pathString = sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y1, x2, y1,
12
+ x2, y2, x1, y2);
13
+ var options = { path: pathString, stroke: "none", fill: fill };
14
+ if (name)
15
+ options['data-name'] = name;
16
+ if (klass)
17
+ options['class'] = klass;
18
+ var ret = renderer.paper.pathToBack(options);
19
+
20
+ return ret;
21
+ }
22
+
23
+ module.exports = printLine;
24
+
@@ -1,7 +1,7 @@
1
1
  var elementGroup = require('./group-elements');
2
2
  var roundNumber = require("./round-number");
3
3
 
4
- function printStem(renderer, x, dx, y1, y2) {
4
+ function printStem(renderer, x, dx, y1, y2, klass, name) {
5
5
  if (dx<0 || y1<y2) { // correct path "handedness" for intersection with other elements
6
6
  var tmp = roundNumber(y2);
7
7
  y2 = roundNumber(y1);
@@ -12,18 +12,19 @@ function printStem(renderer, x, dx, y1, y2) {
12
12
  }
13
13
  x = roundNumber(x);
14
14
  var x2 = roundNumber(x+dx);
15
- var fill = renderer.foregroundColor;
16
15
  var pathArray = [["M",x,y1],["L", x, y2],["L", x2, y2],["L",x2,y1],["z"]];
17
- if (elementGroup.isInGroup()) {
18
- elementGroup.addPath(pathArray);
19
- } else {
20
- var path = "";
21
- for (var i = 0; i < pathArray.length; i++)
22
- path += pathArray[i].join(" ");
23
- var ret = renderer.paper.pathToBack({path:path, stroke:"none", fill:fill, 'class': renderer.controller.classes.generate('stem')});
24
-
25
- return ret;
16
+ var attr = { path: ""};
17
+ for (var i = 0; i < pathArray.length; i++)
18
+ attr.path += pathArray[i].join(" ");
19
+ if (klass)
20
+ attr['class'] = klass;
21
+ if (name)
22
+ attr['data-name'] = name;
23
+ if (!elementGroup.isInGroup()) {
24
+ attr.stroke ="none";
25
+ attr.fill = renderer.foregroundColor;
26
26
  }
27
+ return renderer.paper.pathToBack(attr);
27
28
  }
28
29
 
29
30
  module.exports = printStem;
@@ -7,22 +7,23 @@ var elementGroup = require('./group-elements');
7
7
  * if symbol is a multichar string without a . (as in scripts.staccato) 1 symbol per char is assumed
8
8
  * not scaled if not in printgroup
9
9
  */
10
- function printSymbol(renderer, x, offset, symbol, scalex, scaley, klass) {
10
+ function printSymbol(renderer, x, offset, symbol, options) {
11
+ // TODO-PER: what happened to scalex, and scaley? That might have been a bug introduced in refactoring
11
12
  var el;
12
13
  var ycorr;
13
14
  if (!symbol) return null;
14
15
  if (symbol.length > 1 && symbol.indexOf(".") < 0) {
15
- renderer.paper.openGroup({klass: klass});
16
+ renderer.paper.openGroup({"data-name": options.name, klass: options.klass});
16
17
  var dx = 0;
17
18
  for (var i = 0; i < symbol.length; i++) {
18
19
  var s = symbol.charAt(i);
19
20
  ycorr = glyphs.getYCorr(s);
20
- el = glyphs.printSymbol(x + dx, renderer.calcY(offset + ycorr), s, renderer.paper, '', "none", renderer.foregroundColor);
21
+ el = glyphs.printSymbol(x + dx, renderer.calcY(offset + ycorr), s, renderer.paper, {stroke: options.stroke, fill: options.fill, "data-name": options.name});
21
22
  if (el) {
22
23
  if (i < symbol.length - 1)
23
24
  dx += kernSymbols(s, symbol.charAt(i + 1), glyphs.getSymbolWidth(s));
24
25
  } else {
25
- renderText(renderer, { x: x, y: renderer.y, text: "no symbol:" + symbol, type: "debugfont", klass: 'debug-msg', anchor: 'start'});
26
+ renderText(renderer, { x: x, y: renderer.y, text: "no symbol:" + symbol, type: "debugfont", klass: 'debug-msg', anchor: 'start'}, false);
26
27
  }
27
28
  }
28
29
  var g = renderer.paper.closeGroup();
@@ -30,14 +31,14 @@ function printSymbol(renderer, x, offset, symbol, scalex, scaley, klass) {
30
31
  } else {
31
32
  ycorr = glyphs.getYCorr(symbol);
32
33
  if (elementGroup.isInGroup()) {
33
- elementGroup.addPath(glyphs.getPathForSymbol(x, renderer.calcY(offset + ycorr), symbol, scalex, scaley));
34
+ el = glyphs.printSymbol(x, renderer.calcY(offset + ycorr), symbol, renderer.paper, {"data-name": options.name});
34
35
  } else {
35
- el = glyphs.printSymbol(x, renderer.calcY(offset + ycorr), symbol, renderer.paper, klass, "none", renderer.foregroundColor);
36
- if (el) {
37
- return el;
38
- } else
39
- renderText(renderer, { x: x, y: renderer.y, text: "no symbol:" + symbol, type: "debugfont", klass: 'debug-msg', anchor: 'start'});
36
+ el = glyphs.printSymbol(x, renderer.calcY(offset + ycorr), symbol, renderer.paper, {klass: options.klass, stroke: options.stroke, fill: options.fill, "data-name": options.name});
37
+ }
38
+ if (el) {
39
+ return el;
40
40
  }
41
+ renderText(renderer, { x: x, y: renderer.y, text: "no symbol:" + symbol, type: "debugfont", klass: 'debug-msg', anchor: 'start'}, false);
41
42
  return null;
42
43
  }
43
44
  }
@@ -9,40 +9,60 @@ function drawRelativeElement(renderer, params, bartop) {
9
9
  var y = renderer.calcY(params.pitch);
10
10
  switch(params.type) {
11
11
  case "symbol":
12
- if (params.c===null) return null;
12
+ if (params.c === null) return null;
13
13
  var klass = "symbol";
14
14
  if (params.klass) klass += " " + params.klass;
15
- params.graphelem = printSymbol(renderer, params.x, params.pitch, params.c, params.scalex, params.scaley, renderer.controller.classes.generate(klass), "none", renderer.foregroundColor); break;
15
+ params.graphelem = printSymbol(renderer, params.x, params.pitch, params.c, {
16
+ scalex: params.scalex,
17
+ scaley: params.scaley,
18
+ klass: renderer.controller.classes.generate(klass),
19
+ // fill:"none",
20
+ // stroke: renderer.foregroundColor,
21
+ name: params.name
22
+ });
23
+ break;
16
24
  case "debug":
17
- params.graphelem = renderText(renderer, { x: params.x, y: renderer.calcY(15), text: ""+params.c, type: "debugfont", klass: renderer.controller.classes.generate('debug-msg'), anchor: 'start', centerVertically: false, dim: params.dim}); break;
25
+ params.graphelem = renderText(renderer, { x: params.x, y: renderer.calcY(15), text: "" + params.c, type: "debugfont", klass: renderer.controller.classes.generate('debug-msg'), anchor: 'start', centerVertically: false, dim: params.dim }, false);
26
+ break;
27
+ case "tabNumber":
28
+ var hAnchor = "middle";
29
+ var tabFont = "tabnumberfont";
30
+ var tabClass = 'tab-number';
31
+ if (params.isGrace) {
32
+ tabFont = "tabgracefont";
33
+ y += 2.5;
34
+ tabClass = 'tab-grace'
35
+ }
36
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: "" + params.c, type: tabFont, klass: renderer.controller.classes.generate(tabClass), anchor: hAnchor, centerVertically: false, dim: params.dim , cursor: 'default'}, false);
37
+ break;
18
38
  case "barNumber":
19
- params.graphelem = renderText(renderer, { x: params.x, y: y, text: ""+params.c, type: "measurefont", klass: renderer.controller.classes.generate('bar-number'), anchor: "middle", dim: params.dim});
39
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: ""+params.c, type: "measurefont", klass: renderer.controller.classes.generate('bar-number'), anchor: "middle", dim: params.dim, name: "bar-number"}, true);
20
40
  break;
21
41
  case "lyric":
22
- params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: "vocalfont", klass: renderer.controller.classes.generate('lyric'), anchor: "middle", dim: params.dim});
42
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: "vocalfont", klass: renderer.controller.classes.generate('lyric'), anchor: "middle", dim: params.dim, name: "lyric"}, false);
23
43
  break;
24
44
  case "chord":
25
- params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'gchordfont', klass: renderer.controller.classes.generate("chord"), anchor: "middle", dim: params.dim, lane: params.getLane()});
45
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'gchordfont', klass: renderer.controller.classes.generate("chord"), anchor: "middle", dim: params.dim, lane: params.getLane(), name: "chord"}, false);
26
46
  break;
27
47
  case "decoration":
28
48
  // The +6 is to compensate for the placement of text in svg: to be on the same row as symbols, the y-coord needs to compensate for the center line.
29
- params.graphelem = renderText(renderer, { x: params.x, y: y+6, text: params.c, type: 'annotationfont', klass: renderer.controller.classes.generate("annotation"), anchor: "middle", centerVertically: true, dim: params.dim});
49
+ params.graphelem = renderText(renderer, { x: params.x, y: y+6, text: params.c, type: 'annotationfont', klass: renderer.controller.classes.generate("annotation"), anchor: "middle", centerVertically: true, dim: params.dim}, false);
30
50
  break;
31
51
  case "text":
32
- params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'annotationfont', klass: renderer.controller.classes.generate("annotation"), anchor: "start", centerVertically: params.centerVertically, dim: params.dim, lane: params.getLane()});
52
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'annotationfont', klass: renderer.controller.classes.generate("annotation"), anchor: "start", centerVertically: params.centerVertically, dim: params.dim, lane: params.getLane(), name: "annotation"}, false);
33
53
  break;
34
54
  case "multimeasure-text":
35
- params.graphelem = renderText(renderer, { x: params.x+params.w/2, y: y, text: params.c, type: 'tempofont', klass: renderer.controller.classes.generate("rest"), anchor: "middle", centerVertically: false, dim: params.dim});
55
+ params.graphelem = renderText(renderer, { x: params.x+params.w/2, y: y, text: params.c, type: 'tempofont', klass: renderer.controller.classes.generate("rest"), anchor: "middle", centerVertically: false, dim: params.dim}, false);
36
56
  break;
37
57
  case "part":
38
- params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'partsfont', klass: renderer.controller.classes.generate("part"), anchor: "start", dim: params.dim});
58
+ params.graphelem = renderText(renderer, { x: params.x, y: y, text: params.c, type: 'partsfont', klass: renderer.controller.classes.generate("part"), anchor: "start", dim: params.dim, name: params.c}, true);
39
59
  break;
40
60
  case "bar":
41
- params.graphelem = printStem(renderer, params.x, params.linewidth, y, (bartop)?bartop:renderer.calcY(params.pitch2)); break; // bartop can't be 0
61
+ params.graphelem = printStem(renderer, params.x, params.linewidth, y, (bartop)?bartop:renderer.calcY(params.pitch2), null, "bar"); break; // bartop can't be 0
42
62
  case "stem":
43
- params.graphelem = printStem(renderer, params.x, params.linewidth, y, renderer.calcY(params.pitch2)); break;
63
+ params.graphelem = printStem(renderer, params.x, params.linewidth, y, renderer.calcY(params.pitch2), 'abcjs-stem', 'stem'); break;
44
64
  case "ledger":
45
- params.graphelem = printStaffLine(renderer, params.x, params.x+params.w, params.pitch, renderer.controller.classes.generate("ledger")); break;
65
+ params.graphelem = printStaffLine(renderer, params.x, params.x+params.w, params.pitch, "abcjs-ledger", "ledger"); break;
46
66
  }
47
67
  if (params.scalex!==1 && params.graphelem) {
48
68
  scaleExistingElem(renderer.paper, params.graphelem, params.scalex, params.scaley, params.x, y);
@@ -10,9 +10,9 @@ function Selectables(paper, selectTypes, tuneNumber) {
10
10
 
11
11
  Selectables.prototype.getElements = function () {
12
12
  return this.elements;
13
- }
13
+ };
14
14
 
15
- Selectables.prototype.add = function (absEl, svgEl, isNote, staffPos) {
15
+ Selectables.prototype.add = function (absEl, svgEl, isNoteOrTabNumber, staffPos) {
16
16
  if (!this.canSelect(absEl))
17
17
  return;
18
18
  var params;
@@ -21,7 +21,7 @@ Selectables.prototype.add = function (absEl, svgEl, isNote, staffPos) {
21
21
  else
22
22
  params = { selectable: true, tabindex: 0, "data-index": this.elements.length};
23
23
  this.paper.setAttributeOnElement(svgEl, params);
24
- var sel = { absEl: absEl, svgEl: svgEl, isDraggable: isNote };
24
+ var sel = { absEl: absEl, svgEl: svgEl, isDraggable: isNoteOrTabNumber };
25
25
  if (staffPos !== undefined)
26
26
  sel.staffPos = staffPos;
27
27
  this.elements.push(sel);
@@ -36,8 +36,11 @@ Selectables.prototype.canSelect = function (absEl) {
36
36
  if (this.selectTypes === true)
37
37
  return true;
38
38
  if (this.selectTypes === undefined) {
39
- // by default, only notes can be clicked.
40
- return absEl.abcelem.el_type === 'note';
39
+ // by default, only notes and tab numbers can be clicked.
40
+ if (absEl.abcelem.el_type === 'note' || absEl.abcelem.el_type === 'tabNumber') {
41
+ return true;
42
+ }
43
+ return false;
41
44
  }
42
45
  return this.selectTypes.indexOf(absEl.abcelem.el_type) >= 0;
43
46
  };
@@ -49,7 +52,7 @@ Selectables.prototype.wrapSvgEl = function(abcelem, el) {
49
52
  elemset: [el],
50
53
  highlight: highlight,
51
54
  unhighlight: unhighlight
52
- }
55
+ };
53
56
  this.add(absEl, el, false);
54
57
  };
55
58
 
@@ -4,8 +4,9 @@ var drawVoice = require('./voice');
4
4
  var printStaff = require('./staff');
5
5
  var printDebugBox = require('./debug-box');
6
6
  var printStem = require('./print-stem');
7
+ var nonMusic = require('./non-music');
7
8
 
8
- function drawStaffGroup(renderer, params, selectables) {
9
+ function drawStaffGroup(renderer, params, selectables,lineNumber) {
9
10
  // We enter this method with renderer.y pointing to the topmost coordinate that we're allowed to draw.
10
11
  // All of the children that will be drawn have a relative "pitch" set, where zero is the first ledger line below the staff.
11
12
  // renderer.y will be offset at the beginning of each staff by the amount required to make the relative pitch work.
@@ -14,7 +15,7 @@ function drawStaffGroup(renderer, params, selectables) {
14
15
  var colorIndex;
15
16
 
16
17
  // An invisible marker is useful to be able to find where each system starts.
17
- addInvisibleMarker(renderer,"abcjs-top-of-system");
18
+ addInvisibleMarker(renderer, "abcjs-top-of-system");
18
19
 
19
20
  var startY = renderer.y; // So that it can be restored after we're done.
20
21
  // Set the absolute Y position for each staff here, so the voice drawing below can just use if.
@@ -28,7 +29,7 @@ function drawStaffGroup(renderer, params, selectables) {
28
29
  boxAllElements(renderer, params.voices, staff1.voices);
29
30
  }
30
31
  if (renderer.showDebug.indexOf("grid") >= 0) {
31
- renderer.paper.dottedLine({x1: renderer.padding.left, x2: renderer.padding.left+renderer.controller.width, y1: startY, y2: startY, stroke: "#0000ff"})
32
+ renderer.paper.dottedLine({x1: renderer.padding.left, x2: renderer.padding.left+renderer.controller.width, y1: startY, y2: startY, stroke: "#0000ff"});
32
33
  printDebugBox(renderer,
33
34
  { x: renderer.padding.left,
34
35
  y: renderer.calcY(staff1.originalTop),
@@ -68,20 +69,40 @@ function drawStaffGroup(renderer, params, selectables) {
68
69
  var topLine; // these are to connect multiple staves. We need to remember where they are.
69
70
  var bottomLine;
70
71
 
72
+ var linePitch = 2;
71
73
  var bartop = 0;
72
74
  for (var i=0;i<params.voices.length;i++) {
73
75
  var staff = params.voices[i].staff;
74
- renderer.y = staff.absoluteY;
76
+ var tabName = params.voices[i].tabNameInfos;
77
+ renderer.y = staff.absoluteY ;
75
78
  renderer.controller.classes.incrVoice();
76
79
  //renderer.y = staff.y;
77
80
  // offset for starting the counting at middle C
78
81
  if (!params.voices[i].duplicate) {
79
82
  // renderer.moveY(spacing.STEP, staff.top);
80
83
  if (!topLine) topLine = renderer.calcY(10);
81
- bottomLine = renderer.calcY(2);
84
+ bottomLine = renderer.calcY(linePitch);
82
85
  if (staff.lines !== 0) {
86
+ if (staff.linePitch) {
87
+ linePitch = staff.linePitch;
88
+ }
83
89
  renderer.controller.classes.newMeasure();
84
- printStaff(renderer, params.startx, params.w, staff.lines);
90
+ var lines = printStaff(renderer, params.startx, params.w, staff.lines, staff.linePitch, staff.dy);
91
+ bottomLine = lines[1];
92
+ staff.bottomLine = bottomLine;
93
+ staff.topLine = lines[0];
94
+ // rework bartop when tabs are present with current staff
95
+ if (staff.hasTab) {
96
+ // do not link to staff above (ugly looking)
97
+ bartop = staff.topLine;
98
+ }
99
+ if (staff.hasStaff) {
100
+ // this is a tab
101
+ bartop = staff.hasStaff.topLine;
102
+ params.voices[i].barto = true;
103
+ params.voices[i].topLine = topLine;
104
+ }
105
+
85
106
  }
86
107
  printBrace(renderer, staff.absoluteY, params.brace, i, selectables);
87
108
  printBrace(renderer, staff.absoluteY, params.bracket, i, selectables);
@@ -91,9 +112,21 @@ function drawStaffGroup(renderer, params, selectables) {
91
112
  zero: renderer.y,
92
113
  height: params.height*spacing.STEP
93
114
  });
115
+ var tabNameHeight = 0;
116
+ if (tabName) {
117
+ // print tab infos on staffBottom
118
+ var r = { rows: [] };
119
+ r.rows.push({ absmove: bottomLine + 2 });
120
+ var leftMargin = 8;
121
+ r.rows.push({ left: params.startx+leftMargin, text: tabName.name, font: 'tablabelfont', klass: 'text instrument-name', anchor: 'start' });
122
+ r.rows.push({ move: tabName.textSize.height });
123
+ nonMusic(renderer, r);
124
+ tabNameHeight = tabName.textSize.height;
125
+ }
126
+
94
127
  renderer.controller.classes.newMeasure();
95
128
  if (!params.voices[i].duplicate) {
96
- bartop = renderer.calcY(2); // This connects the bar lines between two different staves.
129
+ bartop = renderer.calcY(2 + tabNameHeight); // This connects the bar lines between two different staves.
97
130
  // if (staff.bottom < 0)
98
131
  // renderer.moveY(spacing.STEP, -staff.bottom);
99
132
  }
@@ -101,8 +134,11 @@ function drawStaffGroup(renderer, params, selectables) {
101
134
  renderer.controller.classes.newMeasure();
102
135
 
103
136
  // connect all the staves together with a vertical line
104
- if (params.staffs.length>1) {
105
- printStem(renderer, params.startx, 0.6, topLine, bottomLine);
137
+ var staffSize = params.staffs.length;
138
+ if (staffSize > 1) {
139
+ topLine = params.staffs[0].topLine;
140
+ bottomLine = params.staffs[staffSize - 1].bottomLine;
141
+ printStem(renderer, params.startx, 0.6, topLine, bottomLine, null);
106
142
  }
107
143
  renderer.y = startY;
108
144
 
@@ -1,22 +1,8 @@
1
- var sprintf = require('./sprintf');
2
- var roundNumber = require("./round-number");
1
+ var printLine = require('./print-line');
3
2
 
4
- function printStaffLine(renderer, x1,x2, pitch, klass) {
5
- var dy = 0.35;
6
- var fill = renderer.foregroundColor;
3
+ function printStaffLine(renderer, x1,x2, pitch, klass, name , dy) {
7
4
  var y = renderer.calcY(pitch);
8
- x1 = roundNumber(x1);
9
- x2 = roundNumber(x2);
10
- var y1 = roundNumber(y-dy);
11
- var y2 = roundNumber(y+dy);
12
- var pathString = sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y1, x2, y1,
13
- x2, y2, x1, y2);
14
- var options = {path:pathString, stroke:"none", fill:fill};
15
- if (klass)
16
- options['class'] = klass;
17
- var ret = renderer.paper.pathToBack(options);
18
-
19
- return ret;
5
+ return printLine(renderer,x1,x2,y,klass,name,dy);
20
6
  }
21
7
 
22
8
  module.exports = printStaffLine;
@@ -1,18 +1,31 @@
1
1
  var printStaffLine = require('./staff-line');
2
2
 
3
- function printStaff(renderer, startx, endx, numLines) {
3
+ function printStaff(renderer, startx, endx, numLines , linePitch , dy) {
4
4
  var klass = "abcjs-top-line";
5
+ var pitch = 2;
6
+ if (linePitch) {
7
+ pitch = linePitch;
8
+ }
5
9
  renderer.paper.openGroup({ prepend: true, klass: renderer.controller.classes.generate("abcjs-staff") });
6
10
  // If there is one line, it is the B line. Otherwise, the bottom line is the E line.
11
+ var firstYLine = 0;
12
+ var lastYLine = 0;
7
13
  if (numLines === 1) {
8
14
  printStaffLine(renderer, startx,endx,6, klass);
9
15
  } else {
16
+
10
17
  for (var i = numLines - 1; i >= 0; i--) {
11
- printStaffLine(renderer, startx, endx, (i + 1) * 2, klass);
18
+ var curpitch = (i + 1) * pitch;
19
+ lastYLine = renderer.calcY(curpitch);
20
+ if (firstYLine == 0) {
21
+ firstYLine = lastYLine;
22
+ }
23
+ printStaffLine(renderer, startx, endx, curpitch, klass , null , dy) ;
12
24
  klass = undefined;
13
25
  }
14
26
  }
15
27
  renderer.paper.closeGroup();
28
+ return [firstYLine,lastYLine];
16
29
  }
17
30
 
18
31
  module.exports = printStaff;