abcjs-rails 1.11 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/abcjs/api/abc_animation.js +41 -1
  3. data/app/assets/javascripts/abcjs/api/abc_tunebook.js +5 -0
  4. data/app/assets/javascripts/abcjs/data/abc_tune.js +4 -3
  5. data/app/assets/javascripts/abcjs/edit/abc_editor.js +10 -0
  6. data/app/assets/javascripts/abcjs/parse/abc_parse.js +120 -19
  7. data/app/assets/javascripts/abcjs/parse/abc_parse_directive.js +456 -115
  8. data/app/assets/javascripts/abcjs/raphael.js +2 -2
  9. data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +111 -4
  10. data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +899 -0
  11. data/app/assets/javascripts/abcjs/write/abc_beam_element.js +263 -37
  12. data/app/assets/javascripts/abcjs/write/abc_create_clef.js +76 -0
  13. data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +41 -0
  14. data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +51 -0
  15. data/app/assets/javascripts/abcjs/write/{abc_cresendo_element.js → abc_crescendo_element.js} +32 -1
  16. data/app/assets/javascripts/abcjs/write/abc_decoration.js +321 -0
  17. data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +22 -1
  18. data/app/assets/javascripts/abcjs/write/abc_ending_element.js +31 -1
  19. data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +359 -0
  20. data/app/assets/javascripts/abcjs/write/abc_glyphs.js +119 -9
  21. data/app/assets/javascripts/abcjs/write/abc_layout.js +2 -2
  22. data/app/assets/javascripts/abcjs/write/abc_relative_element.js +106 -8
  23. data/app/assets/javascripts/abcjs/write/abc_renderer.js +754 -0
  24. data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +249 -9
  25. data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +104 -0
  26. data/app/assets/javascripts/abcjs/write/abc_tie_element.js +69 -22
  27. data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +77 -10
  28. data/app/assets/javascripts/abcjs/write/abc_voice_element.js +100 -8
  29. data/app/assets/javascripts/abcjs/write/abc_write.js +64 -68
  30. data/lib/abcjs-rails/version.rb +1 -1
  31. metadata +12 -4
@@ -447,7 +447,7 @@ ABCJS.write.Layout.prototype.printNote = function(elem, nostem, dontDraw) { //st
447
447
  window.ABCJS.parse.each(elem.lyric, function(ly) {
448
448
  lyricStr += ly.syllable + ly.divider + "\n";
449
449
  });
450
- abselem.addRight(new ABCJS.write.RelativeElement(lyricStr, 0, lyricStr.length*5, 0, {type:"debugLow"}));
450
+ abselem.addRight(new ABCJS.write.RelativeElement(lyricStr, 0, lyricStr.length*5, 0, {type:"lyric"}));
451
451
  }
452
452
 
453
453
  if (!dontDraw && elem.gracenotes !== undefined) {
@@ -507,7 +507,7 @@ ABCJS.write.Layout.prototype.printNote = function(elem, nostem, dontDraw) { //st
507
507
  }
508
508
 
509
509
  if (elem.barNumber) {
510
- abselem.addChild(new ABCJS.write.RelativeElement(elem.barNumber, -10, 0, 0, {type:"debug"}));
510
+ abselem.addChild(new ABCJS.write.RelativeElement(elem.barNumber, -15, 0, 13, {type:"barNumber"}));
511
511
  }
512
512
 
513
513
  // ledger lines
@@ -34,39 +34,137 @@ ABCJS.write.RelativeElement = function(c, dx, w, pitch, opt) {
34
34
  this.type = opt.type || "symbol"; // cheap types.
35
35
  this.pitch2 = opt.pitch2;
36
36
  this.linewidth = opt.linewidth;
37
- this.attributes = opt.attributes; // only present on textual elements
38
- this.top = pitch + ((opt.extreme==="above")? 7 : 0);
39
- this.bottom = pitch - ((opt.extreme==="below")? 7 : 0);
37
+ this.klass = opt.klass;
38
+ this.top = pitch;
39
+ if (this.pitch2 !== undefined && this.pitch2 > this.top) this.top = this.pitch2;
40
+ this.bottom = pitch;
41
+ if (this.pitch2 !== undefined && this.pitch2 < this.bottom) this.bottom = this.pitch2;
42
+ if (opt.thickness) {
43
+ this.top += opt.thickness/2;
44
+ this.bottom -= opt.thickness/2;
45
+ }
46
+ if (opt.stemHeight) {
47
+ if (opt.stemHeight > 0)
48
+ this.top += opt.stemHeight;
49
+ else
50
+ this.bottom += opt.stemHeight;
51
+ }
52
+ //if (this.type === "symbol") {
53
+ // var offset = ABCJS.write.glyphs.getYCorr(this.c);
54
+ // this.top += offset;
55
+ // this.bottom += offset;
56
+ //}
57
+ this.centerVertically = false;
58
+ // TODO-PER: this should use the current font to determine the height. That requires the font to be passed in here, so refactor to store the font now instead of resolving it at draw time. This will allow the font to be changed mid-line, too.
59
+ var multiplier;
60
+ switch (this.type) {
61
+ case "debug":
62
+ this.chordHeightAbove = 3;
63
+ break;
64
+ case "lyric":
65
+ multiplier = this.c.split("\n").length;
66
+ if (opt.position && opt.position === 'below')
67
+ this.lyricHeightBelow = 3*multiplier;
68
+ else
69
+ this.lyricHeightAbove = 3*multiplier;
70
+ break;
71
+ case "chord":
72
+ multiplier = this.c.split("\n").length;
73
+ if (opt.position && opt.position === 'below')
74
+ this.chordHeightBelow = 4*multiplier;
75
+ else
76
+ this.chordHeightAbove = 4*multiplier;
77
+ break;
78
+ case "text":
79
+ multiplier = this.c.split("\n").length;
80
+ if (this.pitch === undefined) {
81
+ if (opt.position && opt.position === 'below')
82
+ this.chordHeightBelow = 4*multiplier;
83
+ else
84
+ this.chordHeightAbove = 4*multiplier;
85
+ } else
86
+ this.centerVertically = true;
87
+ break;
88
+ case "part": this.partHeightAbove = 6; break;
89
+ }
40
90
  };
41
91
 
92
+ <<<<<<< HEAD
93
+ ABCJS.write.RelativeElement.prototype.setX = function (x) {
94
+ =======
42
95
  ABCJS.write.RelativeElement.prototype.draw = function (renderer, x, bartop) {
96
+ >>>>>>> origin/master
43
97
  this.x = x+this.dx;
98
+ };
99
+
100
+ ABCJS.write.RelativeElement.prototype.draw = function (renderer, bartop) {
101
+ if (this.pitch === undefined)
102
+ window.console.error(this.type + " Relative Element y-coordinate not set.");
103
+ var y = renderer.calcY(this.pitch);
44
104
  switch(this.type) {
45
105
  case "symbol":
46
106
  if (this.c===null) return null;
107
+ <<<<<<< HEAD
108
+ var klass = "symbol";
109
+ if (this.klass) klass += " " + this.klass;
110
+ this.graphelem = renderer.printSymbol(this.x, this.pitch, this.c, this.scalex, this.scaley, renderer.addClasses(klass)); break;
111
+ case "debug":
112
+ this.graphelem = renderer.renderText(this.x, renderer.calcY(15), ""+this.c, "debugfont", 'debug-msg', 'start'); break;
113
+ case "barNumber":
114
+ this.graphelem = renderer.renderText(this.x, y, ""+this.c, "measurefont", 'bar-number', "start");
115
+ break;
116
+ case "lyric":
117
+ this.graphelem = renderer.renderText(this.x, y, this.c, "vocalfont", 'abc-lyric', "middle");
118
+ break;
119
+ case "chord":
120
+ this.graphelem = renderer.renderText(this.x, y, this.c, 'gchordfont', "chord", "middle");
121
+ break;
122
+ case "decoration":
123
+ this.graphelem = renderer.renderText(this.x, y, this.c, 'annotationfont', "annotation", "middle", true);
124
+ break;
125
+ case "text":
126
+ this.graphelem = renderer.renderText(this.x, y, this.c, 'annotationfont', "annotation", "start", this.centerVertically);
127
+ break;
128
+ case "part":
129
+ this.graphelem = renderer.renderText(this.x, y, this.c, 'partsfont', "part", "start");
130
+ break;
131
+ case "bar":
132
+ this.graphelem = renderer.printStem(this.x, this.linewidth, y, (bartop)?bartop:renderer.calcY(this.pitch2)); break; // bartop can't be 0
133
+ case "stem":
134
+ this.graphelem = renderer.printStem(this.x, this.linewidth, y, renderer.calcY(this.pitch2)); break;
135
+ =======
47
136
  this.graphelem = renderer.printSymbol(this.x, this.pitch, this.c, this.scalex, this.scaley, renderer.addClasses('symbol')); break;
48
137
  case "debug":
49
- this.graphelem = renderer.debugMsg(this.x, this.c); break;
50
- case "debugLow":
51
- this.graphelem = renderer.printLyrics(this.x, this.c); break;
138
+ this.graphelem = renderer.renderText(this.x, this.y, this.c, "debugfont", 'debug-msg', 'start'); break;
139
+ case "barNumber":
140
+ this.graphelem = renderer.renderText(this.x, renderer.calcY(this.pitch), this.c, "measurefont", 'bar-number', "start");
141
+ break;
142
+ case "lyric":
143
+ this.graphelem = renderer.renderText(this.x, renderer.calcY(renderer.layouter.minY-7), this.c, "vocalfont", 'abc-lyric');
144
+ break;
52
145
  case "chord":
53
- this.graphelem = renderer.printText(this.x, this.pitch, this.c, "start", "chord");
146
+ this.graphelem = renderer.renderText(this.x, renderer.calcY(this.pitch), this.c, 'gchordfont', "start", "chord");
54
147
  break;
55
148
  case "text":
56
- this.graphelem = renderer.printText(this.x, this.pitch, this.c, "start", "annotation");
149
+ this.graphelem = renderer.renderText(this.x, renderer.calcY(this.pitch), this.c, 'annotationfont', "start", "annotation");
57
150
  break;
58
151
  case "bar":
59
152
  this.graphelem = renderer.printStem(this.x, this.linewidth, renderer.calcY(this.pitch), (bartop)?bartop:renderer.calcY(this.pitch2)); break; // bartop can't be 0
60
153
  case "stem":
61
154
  this.graphelem = renderer.printStem(this.x, this.linewidth, renderer.calcY(this.pitch), renderer.calcY(this.pitch2)); break;
155
+ >>>>>>> origin/master
62
156
  case "ledger":
63
157
  this.graphelem = renderer.printStaveLine(this.x, this.x+this.w, this.pitch); break;
64
158
  }
65
159
  if (this.scalex!==1 && this.graphelem) {
160
+ <<<<<<< HEAD
161
+ this.graphelem.scale(this.scalex, this.scaley, this.x, y);
162
+ =======
66
163
  this.graphelem.scale(this.scalex, this.scaley, this.x, renderer.calcY(this.pitch));
67
164
  }
68
165
  if (this.attributes) {
69
166
  this.graphelem.attr(this.attributes);
167
+ >>>>>>> origin/master
70
168
  }
71
169
  return this.graphelem;
72
170
  };
@@ -0,0 +1,754 @@
1
+ // abc_renderer.js: API to render to SVG/Raphael/whatever rendering engine
2
+ // Copyright (C) 2010 Gregory Dyke (gregdyke at gmail dot com)
3
+ //
4
+ // This program is free software: you can redistribute it and/or modify
5
+ // it under the terms of the GNU General Public License as published by
6
+ // the Free Software Foundation, either version 3 of the License, or
7
+ // (at your option) any later version.
8
+ //
9
+ // This program is distributed in the hope that it will be useful,
10
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ // GNU General Public License for more details.
13
+ //
14
+ // You should have received a copy of the GNU General Public License
15
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ /*global window, ABCJS, Math, console */
19
+
20
+ if (!window.ABCJS)
21
+ window.ABCJS = {};
22
+
23
+ if (!window.ABCJS.write)
24
+ window.ABCJS.write = {};
25
+
26
+ /**
27
+ * Implements the API for rendering ABCJS Abstract Rendering Structure to a canvas/paper (e.g. SVG, Raphael, etc)
28
+ * @param {Object} paper
29
+ * @param {bool} doRegression
30
+ */
31
+ ABCJS.write.Renderer = function(paper, doRegression) {
32
+ this.paper = paper;
33
+ this.controller = null; //TODO-GD only used when drawing the ABCJS ARS to connect the controller with the elements for highlighting
34
+
35
+ this.space = 3*ABCJS.write.spacing.SPACE;
36
+ this.padding = {}; // renderer's padding is managed by the controller
37
+ this.doRegression = doRegression;
38
+ if (this.doRegression)
39
+ this.regressionLines = [];
40
+ this.reset();
41
+ };
42
+
43
+ ABCJS.write.Renderer.prototype.reset = function() {
44
+
45
+ this.paper.clear();
46
+ this.y = 0;
47
+ this.abctune = null;
48
+ this.lastM = null;
49
+ this.ingroup = false;
50
+ this.path = null;
51
+ this.isPrint = false;
52
+ this.initVerticalSpace();
53
+ if (this.doRegression)
54
+ this.regressionLines = [];
55
+ // HACK-PER: There was a problem in Raphael where every path string that was sent to it was cached.
56
+ // That was causing the browser's memory to steadily grow until the browser went slower and slower until
57
+ // it crashed. The fix to that was a patch to Raphael, so it is only patched on the versions of this library that
58
+ // bundle Raphael with it. Also, if Raphael gets an update, then that patch will be lost. On version 2.1.2 of Raphael,
59
+ // the patch is on line 1542 and 1545 and it is:
60
+ // p[ps].sleep = 1;
61
+ };
62
+
63
+ /**
64
+ * Set whether we are formatting this for the screen, or as a preview for creating a PDF version.
65
+ * @param {bool} isPrint
66
+ */
67
+ ABCJS.write.Renderer.prototype.setPrintMode = function (isPrint) {
68
+ this.isPrint = isPrint;
69
+ };
70
+
71
+ /**
72
+ * Set the size of the canvas.
73
+ * @param {object} maxwidth
74
+ * @param {object} scale
75
+ */
76
+ ABCJS.write.Renderer.prototype.setPaperSize = function (maxwidth, scale) {
77
+ var w = (maxwidth+this.padding.right)*scale;
78
+ var h = (this.y+this.padding.bottom)*scale;
79
+ if (this.isPrint)
80
+ h = Math.max(h, 1056); // 11in x 72pt/in x 1.33px/pt
81
+ // TODO-PER: We are letting the page get as long as it needs now, but eventually that should go to a second page.
82
+ if (this.doRegression)
83
+ this.regressionLines.push("PAPER SIZE: ("+w+","+h+")");
84
+
85
+ this.paper.setSize(w/scale,h/scale);
86
+ // Correct for IE problem in calculating height
87
+ var isIE=/*@cc_on!@*/false;//IE detector
88
+ if (isIE) {
89
+ this.paper.canvas.parentNode.style.width=w+"px";
90
+ this.paper.canvas.parentNode.style.height=""+h+"px";
91
+ } else
92
+ this.paper.canvas.parentNode.setAttribute("style","width:"+w+"px");
93
+ if (scale !== 1) {
94
+ this.paper.canvas.style.transform = "scale("+scale+","+scale+")";
95
+ this.paper.canvas.style['-ms-tranform'] = "scale("+scale+","+scale+")";
96
+ this.paper.canvas.style['-webkit-tranform'] = "scale("+scale+","+scale+")";
97
+ this.paper.canvas.style['transform-origin'] = "0 0";
98
+ this.paper.canvas.style['-ms-transform-origin-x'] = "0";
99
+ this.paper.canvas.style['-ms-transform-origin-y'] = "0";
100
+ this.paper.canvas.style['-webkit-transform-origin-x'] = "0";
101
+ this.paper.canvas.style['-webkit-transform-origin-y'] = "0";
102
+ } else {
103
+ this.paper.canvas.style.transform = "";
104
+ this.paper.canvas.style['-ms-tranform'] = "";
105
+ this.paper.canvas.style['-webkit-tranform'] = "";
106
+ }
107
+ this.paper.canvas.parentNode.style.overflow="hidden";
108
+ this.paper.canvas.parentNode.style.height=""+h+"px";
109
+ };
110
+
111
+ /**
112
+ * Set the padding
113
+ * @param {object} params
114
+ */
115
+ ABCJS.write.Renderer.prototype.setPaddingOverride = function(params) {
116
+ this.paddingOverride = { top: params.paddingtop, bottom: params.paddingbottom,
117
+ right: params.paddingright, left: params.paddingleft };
118
+ };
119
+
120
+ /**
121
+ * Set the padding
122
+ * @param {object} params
123
+ */
124
+ ABCJS.write.Renderer.prototype.setPadding = function(abctune) {
125
+ // If the padding is set in the tune, then use that.
126
+ // Otherwise, if the padding is set in the override, use that.
127
+ // Otherwise, use the defaults (there are a different set of defaults for screen and print.)
128
+ function setPaddingVariable(self, paddingKey, formattingKey, printDefault, screenDefault) {
129
+ if (abctune.formatting[formattingKey] !== undefined)
130
+ self.padding[paddingKey] = abctune.formatting[formattingKey];
131
+ else if (self.paddingOverride[paddingKey] !== undefined)
132
+ self.padding[paddingKey] = self.paddingOverride[paddingKey];
133
+ else if (abctune.media === 'print')
134
+ self.padding[paddingKey] = printDefault;
135
+ else
136
+ self.padding[paddingKey] = screenDefault;
137
+ }
138
+ // 1cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 38px
139
+ // 1.8cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 68px
140
+ setPaddingVariable(this, 'top', 'topmargin', 38, 15);
141
+ setPaddingVariable(this, 'bottom', 'bottommargin', 38, 15);
142
+ setPaddingVariable(this, 'left', 'leftmargin', 68, 15);
143
+ setPaddingVariable(this, 'right', 'rightmargin', 68, 15);
144
+ };
145
+
146
+ /**
147
+ * Some of the items on the page are not scaled, so adjust them in the opposite direction of scaling to cancel out the scaling.
148
+ * @param {float} scale
149
+ */
150
+ ABCJS.write.Renderer.prototype.adjustNonScaledItems = function (scale) {
151
+ this.padding.top /= scale;
152
+ this.padding.bottom /= scale;
153
+ this.padding.left /= scale;
154
+ this.padding.right /= scale;
155
+ this.abctune.formatting.headerfont.size /= scale;
156
+ this.abctune.formatting.footerfont.size /= scale;
157
+ };
158
+
159
+ /**
160
+ * Set the the values for all the configurable vertical space options.
161
+ */
162
+ ABCJS.write.Renderer.prototype.initVerticalSpace = function() {
163
+ // conversion: 37.7953 = conversion factor for cm to px.
164
+ // All of the following values are in px.
165
+ this.spacing = {
166
+ composer: 7.56, // Set the vertical space above the composer.
167
+ graceBefore: 8.67, // Define the space before, inside and after the grace notes.
168
+ graceInside: 10.67,
169
+ graceAfter: 16,
170
+ info: 0, // Set the vertical space above the infoline.
171
+ lineSkipFactor: 1.1, // Set the factor for spacing between lines of text. (multiply this by the font size)
172
+ music: 7.56, // Set the vertical space above the first staff.
173
+ paragraphSkipFactor: 0.4, // Set the factor for spacing between text paragraphs. (multiply this by the font size)
174
+ parts: 11.33, // Set the vertical space above a new part.
175
+ slurHeight: 1.0, // Set the slur height factor.
176
+ staffSeparation: 61.33, // Do not put a staff system closer than <unit> from the previous system.
177
+ stemHeight: 26.67+10, // Set the stem height.
178
+ subtitle: 3.78, // Set the vertical space above the subtitle.
179
+ systemStaffSeparation: 48, // Do not place the staves closer than <unit> inside a system. * This values applies to all staves when in the tune header. Otherwise, it applies to the next staff
180
+ text: 18.9, // Set the vertical space above the history.
181
+ title: 7.56, // Set the vertical space above the title.
182
+ top: 30.24, //Set the vertical space above the tunes and on the top of the continuation pages.
183
+ vocal: 30.67, // Set the vertical space above the lyrics under the staves.
184
+ words: 0 // Set the vertical space above the lyrics at the end of the tune.
185
+ };
186
+ /*
187
+ TODO-PER: Handle the x-coordinate spacing items, too.
188
+ maxshrink <float>Default: 0.65
189
+ Set how much to compress horizontally when music line breaks
190
+ are automatic.
191
+ <float> must be between 0 (natural spacing)
192
+ and 1 (max shrinking).
193
+
194
+ // This next value is used to compute the natural spacing of
195
+ // the notes. The base spacing of the crotchet is always
196
+ // 40 pts. When the duration of a note type is twice the
197
+ // duration of an other note type, its spacing is multiplied
198
+ // by this factor.
199
+ // The default value causes the note spacing to be multiplied
200
+ // by 2 when its duration is multiplied by 4, i.e. the
201
+ // space of the semibreve is 80 pts and the space of the
202
+ // semiquaver is 20 pts.
203
+ // Setting this value to 1 sets all note spacing to 40 pts.
204
+ noteSpacingFactor: 1.414, // Set the note spacing factor to <float> (range 1..2).
205
+
206
+ scale <float> Default: 0.75 Set the page scale factor. Note that the header and footer are not scaled.
207
+
208
+ stretchlast <float>Default: 0.8
209
+ Stretch the last music line of a tune when it exceeds
210
+ the <float> fraction of the page width.
211
+ <float> range is 0.0 to 1.0.
212
+ */
213
+ };
214
+
215
+ ABCJS.write.Renderer.prototype.setVerticalSpace = function(formatting) {
216
+ // conversion from pts to px 4/3
217
+ if (formatting.staffsep !== undefined)
218
+ this.spacing.staffSeparation = formatting.staffsep *4/3;
219
+ if (formatting.composerspace !== undefined)
220
+ this.spacing.composer = formatting.composerspace *4/3;
221
+ if (formatting.partsspace !== undefined)
222
+ this.spacing.parts = formatting.partsspace *4/3;
223
+ if (formatting.textspace !== undefined)
224
+ this.spacing.text = formatting.textspace *4/3;
225
+ if (formatting.musicspace !== undefined)
226
+ this.spacing.music = formatting.musicspace *4/3;
227
+ if (formatting.titlespace !== undefined)
228
+ this.spacing.title = formatting.titlespace *4/3;
229
+ if (formatting.sysstaffsep !== undefined)
230
+ this.spacing.systemStaffSeparation = formatting.sysstaffsep *4/3;
231
+ if (formatting.subtitlespace !== undefined)
232
+ this.spacing.subtitle = formatting.subtitlespace *4/3;
233
+ if (formatting.topspace !== undefined)
234
+ this.spacing.top = formatting.topspace *4/3;
235
+ if (formatting.vocalspace !== undefined)
236
+ this.spacing.vocal = formatting.vocalspace *4/3;
237
+ if (formatting.wordsspace !== undefined)
238
+ this.spacing.words = formatting.wordsspace *4/3;
239
+ };
240
+
241
+ /**
242
+ * Leave space at the top of the paper
243
+ * @param {object} abctune
244
+ */
245
+ ABCJS.write.Renderer.prototype.topMargin = function(abctune) {
246
+ this.moveY(this.padding.top);
247
+ };
248
+
249
+ /**
250
+ * Leave space before printing the music
251
+ */
252
+ ABCJS.write.Renderer.prototype.addMusicPadding = function() {
253
+ this.moveY(this.spacing.music);
254
+ };
255
+
256
+ /**
257
+ * Leave space before printing a staff system
258
+ */
259
+ ABCJS.write.Renderer.prototype.addStaffPadding = function(lastStaffGroup, thisStaffGroup) {
260
+ var lastStaff = lastStaffGroup.staffs[lastStaffGroup.staffs.length-1];
261
+ var lastBottomLine = -(lastStaff.bottom - 2); // The 2 is because the scale goes to 2 below the last line.
262
+ var nextTopLine = thisStaffGroup.staffs[0].top - 10; // Because 10 represents the top line.
263
+ var naturalSeparation = nextTopLine + lastBottomLine; // This is how far apart they'd be without extra spacing
264
+ var separationInPixels = naturalSeparation * ABCJS.write.spacing.STEP;
265
+ if (separationInPixels < this.spacing.staffSeparation)
266
+ this.moveY(this.spacing.staffSeparation-separationInPixels);
267
+ };
268
+
269
+ /**
270
+ * Text that goes above the score
271
+ * @param {number} width
272
+ * @param {object} abctune
273
+ */
274
+ ABCJS.write.Renderer.prototype.engraveTopText = function(width, abctune) {
275
+ if (abctune.metaText.header && this.isPrint) {
276
+ // Note: whether there is a header or not doesn't change any other positioning, so this doesn't change the Y-coordinate.
277
+ // This text goes above the margin, so we'll temporarily move up.
278
+ var headerTextHeight = this.getTextSize("XXXX", "headerfont", 'header meta-top').height;
279
+ this.y -=headerTextHeight;
280
+ this.outputTextIf(this.padding.left, abctune.metaText.header.left, 'headerfont', 'header meta-top', 0, null, 'start');
281
+ this.outputTextIf(this.padding.left + width / 2, abctune.metaText.header.center, 'headerfont', 'header meta-top', 0, null, 'middle');
282
+ this.outputTextIf(this.padding.left + width, abctune.metaText.header.right, 'headerfont', 'header meta-top', 0, null, 'end');
283
+ this.y += headerTextHeight;
284
+ }
285
+ if (this.isPrint)
286
+ this.moveY(this.spacing.top);
287
+ this.outputTextIf(this.padding.left + width / 2, abctune.metaText.title, 'titlefont', 'title meta-top', this.spacing.title, 0, 'middle');
288
+ if (abctune.lines[0])
289
+ this.outputTextIf(this.padding.left + width / 2, abctune.lines[0].subtitle, 'subtitlefont', 'text meta-top', this.spacing.subtitle, 0, 'middle');
290
+
291
+ if (abctune.metaText.rhythm || abctune.metaText.origin || abctune.metaText.composer) {
292
+ this.moveY(this.spacing.composer);
293
+ var rSpace = this.outputTextIf(this.padding.left, abctune.metaText.rhythm, 'infofont', 'meta-top', 0, null, "start");
294
+
295
+ var composerLine = "";
296
+ if (abctune.metaText.composer) composerLine += abctune.metaText.composer;
297
+ if (abctune.metaText.origin) composerLine += ' (' + abctune.metaText.origin + ')';
298
+ if (composerLine.length > 0) {
299
+ var space = this.outputTextIf(this.padding.left + width, composerLine, 'composerfont', 'meta-top', 0, null, "end");
300
+ this.moveY(space[1]);
301
+ } else {
302
+ this.moveY(rSpace[1]);
303
+ }
304
+ // TODO-PER: The following is a hack to make the elements line up with abcm2ps. Don't know where the extra space is coming from.
305
+ this.moveY(-6);
306
+ //} else if (this.isPrint) {
307
+ // // abcm2ps adds this space whether there is anything to write or not.
308
+ // this.moveY(this.spacing.composer);
309
+ // var space2 = this.getTextSize("M", 'composerfont', 'meta-top');
310
+ // this.moveY(space2.height);
311
+ }
312
+
313
+ this.outputTextIf(this.padding.left + width, abctune.metaText.author, 'composerfont', 'meta-top', 0, 0, "end");
314
+ //this.skipSpaceY();
315
+
316
+ this.outputTextIf(this.padding.left, abctune.metaText.partOrder, 'partsfont', 'meta-bottom', 0, 0, "start");
317
+ };
318
+
319
+ /**
320
+ * Text that goes below the score
321
+ * @param {number} width
322
+ * @param {object} abctune
323
+ */
324
+ ABCJS.write.Renderer.prototype.engraveExtraText = function(width, abctune) {
325
+ this.lineNumber = null;
326
+ this.measureNumber = null;
327
+
328
+ var extraText;
329
+ if (abctune.metaText.unalignedWords) {
330
+ extraText = "";
331
+ for (var j = 0; j < abctune.metaText.unalignedWords.length; j++) {
332
+ if (typeof abctune.metaText.unalignedWords[j] === 'string')
333
+ extraText += abctune.metaText.unalignedWords[j] + "\n";
334
+ else {
335
+ for (var k = 0; k < abctune.metaText.unalignedWords[j].length; k++) {
336
+ extraText += " FONT " + abctune.metaText.unalignedWords[j][k].text;
337
+ }
338
+ extraText += "\n";
339
+ }
340
+ }
341
+ this.outputTextIf(this.padding.left + ABCJS.write.spacing.INDENT, extraText, 'wordsfont', 'meta-bottom', this.spacing.words, 2, "start");
342
+ }
343
+
344
+ extraText = "";
345
+ if (abctune.metaText.book) extraText += "Book: " + abctune.metaText.book + "\n";
346
+ if (abctune.metaText.source) extraText += "Source: " + abctune.metaText.source + "\n";
347
+ if (abctune.metaText.discography) extraText += "Discography: " + abctune.metaText.discography + "\n";
348
+ if (abctune.metaText.notes) extraText += "Notes: " + abctune.metaText.notes + "\n";
349
+ if (abctune.metaText.transcription) extraText += "Transcription: " + abctune.metaText.transcription + "\n";
350
+ if (abctune.metaText.history) extraText += "History: " + abctune.metaText.history + "\n";
351
+ if (abctune.metaText['abc-copyright']) extraText += "Copyright: " + abctune.metaText['abc-copyright'] + "\n";
352
+ if (abctune.metaText['abc-creator']) extraText += "Creator: " + abctune.metaText['abc-creator'] + "\n";
353
+ if (abctune.metaText['abc-edited-by']) extraText += "Edited By: " + abctune.metaText['abc-edited-by'] + "\n";
354
+ this.outputTextIf(this.padding.left, extraText, 'historyfont', 'meta-bottom', this.spacing.info, 0, "start");
355
+
356
+ if (abctune.metaText.footer && this.isPrint) {
357
+ // Note: whether there is a footer or not doesn't change any other positioning, so this doesn't change the Y-coordinate.
358
+ this.outputTextIf(this.padding.left, abctune.metaText.footer.left, 'footerfont', 'header meta-bottom', 0, null, 'start');
359
+ this.outputTextIf(this.padding.left + width / 2, abctune.metaText.footer.center, 'footerfont', 'header meta-bottom', 0, null, 'middle');
360
+ this.outputTextIf(this.padding.left + width, abctune.metaText.footer.right, 'footerfont', 'header meta-bottom', 0, null, 'end');
361
+ }
362
+ };
363
+
364
+ /**
365
+ * Output text defined with %%text.
366
+ * @param {array or string} text
367
+ */
368
+ ABCJS.write.Renderer.prototype.outputFreeText = function (text) {
369
+ if (typeof text === 'string')
370
+ this.outputTextIf(this.padding.left, text, 'textfont', 'defined-text', 0, 1, "start");
371
+ else {
372
+ var str = "";
373
+ for (var i = 0; i < text.length; i++) {
374
+ str += " FONT " + text[i].text;
375
+ }
376
+ this.outputTextIf(this.padding.left, str, 'textfont', 'defined-text', 0, 1, "start");
377
+ }
378
+ };
379
+
380
+ /**
381
+ * Output an extra subtitle that is defined later in the tune.
382
+ */
383
+ ABCJS.write.Renderer.prototype.outputSubtitle = function (width, subtitle) {
384
+ this.outputTextIf(this.padding.left + width / 2, subtitle, 'subtitlefont', 'text meta-top', this.spacing.subtitle, 0, 'middle');
385
+ };
386
+
387
+ /**
388
+ * Begin a group of glyphs that will always be moved, scaled and highlighted together
389
+ */
390
+ ABCJS.write.Renderer.prototype.beginGroup = function () {
391
+ this.path = [];
392
+ this.lastM = [0,0];
393
+ this.ingroup = true;
394
+ };
395
+
396
+ /**
397
+ * Add a path to the current group
398
+ * @param {Array} path
399
+ * @private
400
+ */
401
+ ABCJS.write.Renderer.prototype.addPath = function (path) {
402
+ path = path || [];
403
+ if (path.length===0) return;
404
+ path[0][0]="m";
405
+ path[0][1]-=this.lastM[0];
406
+ path[0][2]-=this.lastM[1];
407
+ this.lastM[0]+=path[0][1];
408
+ this.lastM[1]+=path[0][2];
409
+ this.path.push(path[0]);
410
+ for (var i=1,ii=path.length;i<ii;i++) {
411
+ if (path[i][0]==="m") {
412
+ this.lastM[0]+=path[i][1];
413
+ this.lastM[1]+=path[i][2];
414
+ }
415
+ this.path.push(path[i]);
416
+ }
417
+ };
418
+
419
+ /**
420
+ * End a group of glyphs that will always be moved, scaled and highlighted together
421
+ */
422
+ ABCJS.write.Renderer.prototype.endGroup = function (klass) {
423
+ this.ingroup = false;
424
+ if (this.path.length===0) return null;
425
+ var ret = this.paper.path().attr({path:this.path, stroke:"none", fill:"#000000", 'class': this.addClasses(klass)});
426
+ this.path = [];
427
+ if (this.doRegression) this.addToRegression(ret);
428
+
429
+ return ret;
430
+ };
431
+
432
+ /**
433
+ * gets scaled
434
+ * @param {number} x1 start x
435
+ * @param {number} x2 end x
436
+ * @param {number} pitch pitch the stave line is drawn at
437
+ */
438
+ ABCJS.write.Renderer.prototype.printStaveLine = function (x1,x2, pitch, klass) {
439
+ var extraClass = "staff";
440
+ if (klass !== undefined)
441
+ extraClass += " " + klass;
442
+ var isIE=/*@cc_on!@*/false;//IE detector
443
+ var dy = 0.35;
444
+ var fill = "#000000";
445
+ if (isIE) {
446
+ dy = 1;
447
+ fill = "#666666";
448
+ }
449
+ var y = this.calcY(pitch);
450
+ var pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y-dy, x2, y-dy,
451
+ x2, y+dy, x1, y+dy);
452
+ var ret = this.paper.path().attr({path:pathString, stroke:"none", fill:fill, 'class': this.addClasses(extraClass)}).toBack();
453
+ if (this.doRegression) this.addToRegression(ret);
454
+
455
+ return ret;
456
+ };
457
+
458
+ /**
459
+ * gets scaled if not in a group
460
+ * @param {number} x1 x coordinate of the stem
461
+ * @param {number} dx stem width
462
+ * @param {number} y1 y coordinate of the stem bottom
463
+ * @param {number} y2 y coordinate of the stem top
464
+ */
465
+ ABCJS.write.Renderer.prototype.printStem = function (x, dx, y1, y2) {
466
+ if (dx<0) { // correct path "handedness" for intersection with other elements
467
+ var tmp = y2;
468
+ y2 = y1;
469
+ y1 = tmp;
470
+ }
471
+ var isIE=/*@cc_on!@*/false;//IE detector
472
+ var fill = "#000000";
473
+ if (isIE && dx<1) {
474
+ dx = 1;
475
+ fill = "#666666";
476
+ }
477
+ if (~~x === x) x+=0.05; // raphael does weird rounding (for VML)
478
+ var pathArray = [["M",x,y1],["L", x, y2],["L", x+dx, y2],["L",x+dx,y1],["z"]];
479
+ if (!isIE && this.ingroup) {
480
+ this.addPath(pathArray);
481
+ } else {
482
+ var ret = this.paper.path().attr({path:pathArray, stroke:"none", fill:fill, 'class': this.addClasses('stem')}).toBack();
483
+ if (this.doRegression) this.addToRegression(ret);
484
+
485
+ return ret;
486
+ }
487
+ };
488
+
489
+ function kernSymbols(lastSymbol, thisSymbol, lastSymbolWidth) {
490
+ // This is just some adjustments to make it look better.
491
+ var width = lastSymbolWidth;
492
+ if (lastSymbol === 'f' && thisSymbol === 'f')
493
+ width = width*2/3;
494
+ if (lastSymbol === 'p' && thisSymbol === 'p')
495
+ width = width*5/6;
496
+ if (lastSymbol === 'f' && thisSymbol === 'z')
497
+ width = width*5/8;
498
+ return width;
499
+ }
500
+
501
+ /**
502
+ * assumes this.y is set appropriately
503
+ * if symbol is a multichar string without a . (as in scripts.staccato) 1 symbol per char is assumed
504
+ * not scaled if not in printgroup
505
+ */
506
+ ABCJS.write.Renderer.prototype.printSymbol = function(x, offset, symbol, scalex, scaley, klass) {
507
+ var el;
508
+ var ycorr;
509
+ if (!symbol) return null;
510
+ if (symbol.length>0 && symbol.indexOf(".")<0) {
511
+ var elemset = this.paper.set();
512
+ var dx =0;
513
+ for (var i=0; i<symbol.length; i++) {
514
+ var s = symbol.charAt(i);
515
+ ycorr = ABCJS.write.glyphs.getYCorr(s);
516
+ el = ABCJS.write.glyphs.printSymbol(x+dx, this.calcY(offset+ycorr), s, this.paper, klass);
517
+ if (el) {
518
+ if (this.doRegression) this.addToRegression(el);
519
+ elemset.push(el);
520
+ if (i < symbol.length-1)
521
+ dx+= kernSymbols(s, symbol.charAt(i+1), ABCJS.write.glyphs.getSymbolWidth(s));
522
+ } else {
523
+ this.renderText(x, this.y, "no symbol:" +symbol, "debugfont", 'debug-msg', 'start');
524
+ }
525
+ }
526
+ return elemset;
527
+ } else {
528
+ ycorr = ABCJS.write.glyphs.getYCorr(symbol);
529
+ if (this.ingroup) {
530
+ this.addPath(ABCJS.write.glyphs.getPathForSymbol(x, this.calcY(offset+ycorr), symbol, scalex, scaley));
531
+ } else {
532
+ el = ABCJS.write.glyphs.printSymbol(x, this.calcY(offset+ycorr), symbol, this.paper, klass);
533
+ if (el) {
534
+ if (this.doRegression) this.addToRegression(el);
535
+ return el;
536
+ } else
537
+ this.renderText(x, this.y, "no symbol:" +symbol, "debugfont", 'debug-msg', 'start');
538
+ }
539
+ return null;
540
+ }
541
+ };
542
+
543
+
544
+ ABCJS.write.Renderer.prototype.printPath = function (attrs) {
545
+ var ret = this.paper.path().attr(attrs);
546
+ if (this.doRegression) this.addToRegression(ret);
547
+ return ret;
548
+ };
549
+
550
+ ABCJS.write.Renderer.prototype.drawArc = function(x1, x2, pitch1, pitch2, above) {
551
+
552
+
553
+ x1 = x1 + 6;
554
+ x2 = x2 + 4;
555
+ pitch1 = pitch1 + ((above)?1.5:-1.5);
556
+ pitch2 = pitch2 + ((above)?1.5:-1.5);
557
+ var y1 = this.calcY(pitch1);
558
+ var y2 = this.calcY(pitch2);
559
+
560
+ //unit direction vector
561
+ var dx = x2-x1;
562
+ var dy = y2-y1;
563
+ var norm= Math.sqrt(dx*dx+dy*dy);
564
+ var ux = dx/norm;
565
+ var uy = dy/norm;
566
+
567
+ var flatten = norm/3.5;
568
+ var curve = ((above)?-1:1)*Math.min(25, Math.max(4, flatten));
569
+
570
+ var controlx1 = x1+flatten*ux-curve*uy;
571
+ var controly1 = y1+flatten*uy+curve*ux;
572
+ var controlx2 = x2-flatten*ux-curve*uy;
573
+ var controly2 = y2-flatten*uy+curve*ux;
574
+ var thickness = 2;
575
+ var pathString = ABCJS.write.sprintf("M %f %f C %f %f %f %f %f %f C %f %f %f %f %f %f z", x1, y1,
576
+ controlx1, controly1, controlx2, controly2, x2, y2,
577
+ controlx2-thickness*uy, controly2+thickness*ux, controlx1-thickness*uy, controly1+thickness*ux, x1, y1);
578
+ var ret = this.paper.path().attr({path:pathString, stroke:"none", fill:"#000000", 'class': this.addClasses('slur')});
579
+ if (this.doRegression) this.addToRegression(ret);
580
+
581
+ return ret;
582
+ };
583
+ /**
584
+ * Calculates the y for a given pitch value (relative to the stave the renderer is currently printing)
585
+ * @param {number} ofs pitch value (bottom C on a G clef = 0, D=1, etc.)
586
+ */
587
+ ABCJS.write.Renderer.prototype.calcY = function(ofs) {
588
+ return this.y - ofs*ABCJS.write.spacing.STEP;
589
+ };
590
+
591
+ /**
592
+ * Print @param {number} numLines. If there is 1 line it is the B line. Otherwise the bottom line is the E line.
593
+ */
594
+ ABCJS.write.Renderer.prototype.printStave = function (startx, endx, numLines) {
595
+ var klass = "top-line";
596
+ // If there is one line, it is the B line. Otherwise, the bottom line is the E line.
597
+ if (numLines === 1) {
598
+ this.printStaveLine(startx,endx,6, klass);
599
+ return;
600
+ }
601
+ for (var i = numLines-1; i >= 0; i--) {
602
+ this.printStaveLine(startx,endx,(i+1)*2, klass);
603
+ klass = undefined;
604
+ }
605
+ };
606
+
607
+ /**
608
+ *
609
+ * @private
610
+ */
611
+ ABCJS.write.Renderer.prototype.addClasses = function (c) {
612
+ var ret = [];
613
+ if (c.length > 0) ret.push(c);
614
+ if (this.lineNumber !== null) ret.push("l"+this.lineNumber);
615
+ if (this.measureNumber !== null) ret.push("m"+this.measureNumber);
616
+ return ret.join(' ');
617
+ };
618
+
619
+ ABCJS.write.Renderer.prototype.getFontAndAttr = function(type, klass) {
620
+ var font = this.abctune.formatting[type];
621
+ // Raphael deliberately changes the font units to pixels for some reason, so we need to change points to pixels here.
622
+ if (font)
623
+ font = { face: font.face, size: font.size*4/3, decoration: font.decoration, style: font.style, weight: font.weight };
624
+ else
625
+ font = { face: "Arial", size: 12*4/3, decoration: "underline", style: "normal", weight: "normal" };
626
+
627
+ var attr = {"font-size": font.size, 'font-style': font.style,
628
+ "font-family": font.face, 'font-weight': font.weight, 'text-decoration': font.decoration,
629
+ 'class': this.addClasses(klass) };
630
+ attr.font = ""; // There is a spurious font definition that is put on all text elements. This overwrites it.
631
+ return { font: font, attr: attr };
632
+ };
633
+
634
+ ABCJS.write.Renderer.prototype.getTextSize = function(text, type, klass) {
635
+ var hash = this.getFontAndAttr(type, klass);
636
+ var el = this.paper.text(0,0, text).attr(hash.attr);
637
+ var size = el.getBBox();
638
+ el.remove();
639
+ return size;
640
+ };
641
+
642
+ ABCJS.write.Renderer.prototype.renderText = function(x, y, text, type, klass, anchor, centerVertically) {
643
+ var hash = this.getFontAndAttr(type, klass);
644
+ if (anchor)
645
+ hash.attr["text-anchor"] = anchor;
646
+ text = text.replace(/\n\n/g, "\n \n");
647
+ var el = this.paper.text(x, y, text).attr(hash.attr);
648
+ if (!centerVertically) {
649
+ // The text will be placed centered in vertical alignment, so we need to move the box down so that
650
+ // the top of the text is where we've requested.
651
+ var size = el.getBBox();
652
+ el.attr({ "y": y + size.height / 2 });
653
+ if (hash.font.box) {
654
+ this.paper.rect(size.x - 1, size.y - 1, size.width + 2, size.height + 2).attr({"stroke": "#cccccc"});
655
+ }
656
+ }
657
+ if (type === 'debugfont') {
658
+ console.log("Debug msg: " + text);
659
+ el.attr({ stroke: "#ff0000"});
660
+ }
661
+ if (this.doRegression) this.addToRegression(el);
662
+ return el;
663
+ };
664
+
665
+ ABCJS.write.Renderer.prototype.moveY = function (em, numLines) {
666
+ if (numLines === undefined) numLines = 1;
667
+ this.y += em*numLines;
668
+ };
669
+
670
+ ABCJS.write.Renderer.prototype.skipSpaceY = function () {
671
+ this.y += this.space;
672
+ };
673
+
674
+ // Call with 'kind' being the font type to use,
675
+ // if marginBottom === null then don't increment the Y after printing, otherwise that is the extra number of em's to leave below the line.
676
+ // and alignment being "start", "middle", or "end".
677
+ ABCJS.write.Renderer.prototype.outputTextIf = function(x, str, kind, klass, marginTop, marginBottom, alignment) {
678
+ if (str) {
679
+ if (marginTop)
680
+ this.moveY(marginTop);
681
+ var el = this.renderText(x, this.y, str, kind, klass, alignment);
682
+ if (marginBottom !== null) {
683
+ var numLines = str.split("\n").length;
684
+ this.moveY(el.getBBox().height/numLines, (numLines + marginBottom));
685
+ }
686
+ return [el.getBBox().width, el.getBBox().height];
687
+ }
688
+ return [0,0];
689
+ };
690
+
691
+ // For debugging, it is sometimes useful to know where you are vertically.
692
+ ABCJS.write.Renderer.prototype.printHorizontalLine = function (width, vertical, comment) {
693
+ var dy = 0.35;
694
+ var fill = "rgba(0,0,255,.4)";
695
+ var y = this.y;
696
+ if (vertical) y = vertical;
697
+ y = Math.round(y);
698
+ this.paper.text(10, y, ""+Math.round(y)).attr({"text-anchor": "start", "font-size":"18px", fill: fill, stroke: fill });
699
+ var x1 = 50;
700
+ var x2 = width;
701
+ var pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y-dy, x1+x2, y-dy,
702
+ x2, y+dy, x1, y+dy);
703
+ this.paper.path().attr({path:pathString, stroke:"none", fill:fill, 'class': this.addClasses('staff')}).toBack();
704
+ for (var i = 1; i < width/100; i++) {
705
+ pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", i*100-dy, y-5, i*100-dy, y+5,
706
+ i*100+dy, y-5, i*100+dy, y+5);
707
+ this.paper.path().attr({path:pathString, stroke:"none", fill:fill, 'class': this.addClasses('staff')}).toBack();
708
+ }
709
+ if (comment)
710
+ this.paper.text(width+70, y, comment).attr({"text-anchor": "start", "font-size":"18px", fill: fill, stroke: fill });
711
+ };
712
+
713
+ ABCJS.write.Renderer.prototype.printShadedBox = function (x, y, width, height, color, comment) {
714
+ var box = this.paper.rect(x, y, width, height).attr({fill: color, stroke: color });
715
+ if (comment)
716
+ this.paper.text(0, y+7, comment).attr({"text-anchor": "start", "font-size":"14px", fill: "rgba(0,0,255,.4)", stroke: "rgba(0,0,255,.4)" });
717
+ return box;
718
+ };
719
+
720
+ ABCJS.write.Renderer.prototype.printVerticalLine = function (x, y1, y2) {
721
+ var dy = 0.35;
722
+ var fill = "#00aaaa";
723
+ var pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x - dy, y1, x - dy, y2,
724
+ x + dy, y1, x + dy, y2);
725
+ this.paper.path().attr({path: pathString, stroke: "none", fill: fill, 'class': this.addClasses('staff')}).toBack();
726
+ pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x - 20, y1, x - 20, y1+3,
727
+ x, y1, x, y1+3);
728
+ this.paper.path().attr({path: pathString, stroke: "none", fill: fill, 'class': this.addClasses('staff')}).toBack();
729
+ pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x + 20, y2, x + 20, y2+3,
730
+ x, y2, x, y2+3);
731
+ this.paper.path().attr({path: pathString, stroke: "none", fill: fill, 'class': this.addClasses('staff')}).toBack();
732
+
733
+ };
734
+
735
+ /**
736
+ * @private
737
+ */
738
+ ABCJS.write.Renderer.prototype.addToRegression = function (el) {
739
+ var box = el.getBBox();
740
+ //var str = "("+box.x+","+box.y+")["+box.width+","+box.height+"] "
741
+ var str = el.type + ' ' + box.toString() + ' ';
742
+ var attrs = [];
743
+ for (var key in el.attrs) {
744
+ if (el.attrs.hasOwnProperty(key)) {
745
+ if (key === 'class')
746
+ str = el.attrs[key] + " " + str;
747
+ else
748
+ attrs.push(key+": "+el.attrs[key]);
749
+ }
750
+ }
751
+ attrs.sort();
752
+ str += "{ " +attrs.join(" ") + " }";
753
+ this.regressionLines.push(str);
754
+ };