abcjs-rails 1.8 → 1.11

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 (25) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/abcjs/api/abc_animation.js +224 -0
  4. data/app/assets/javascripts/abcjs/api/abc_tunebook.js +158 -154
  5. data/app/assets/javascripts/abcjs/data/abc_tune.js +35 -1
  6. data/app/assets/javascripts/abcjs/edit/abc_editor.js +18 -17
  7. data/app/assets/javascripts/abcjs/parse/abc_parse.js +23 -6
  8. data/app/assets/javascripts/abcjs/parse/abc_parse_header.js +5 -1
  9. data/app/assets/javascripts/abcjs/{write/raphael.js → raphael.js} +2562 -266
  10. data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +163 -0
  11. data/app/assets/javascripts/abcjs/write/abc_beam_element.js +162 -0
  12. data/app/assets/javascripts/abcjs/write/abc_cresendo_element.js +46 -0
  13. data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +36 -0
  14. data/app/assets/javascripts/abcjs/write/abc_ending_element.js +53 -0
  15. data/app/assets/javascripts/abcjs/write/abc_glyphs.js +6 -3
  16. data/app/assets/javascripts/abcjs/write/abc_layout.js +84 -29
  17. data/app/assets/javascripts/abcjs/write/abc_relative_element.js +72 -0
  18. data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +225 -0
  19. data/app/assets/javascripts/abcjs/write/abc_tie_element.js +83 -0
  20. data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +85 -0
  21. data/app/assets/javascripts/abcjs/write/abc_voice_element.js +177 -0
  22. data/app/assets/javascripts/abcjs/write/abc_write.js +65 -28
  23. data/lib/abcjs-rails/version.rb +1 -1
  24. metadata +24 -14
  25. data/app/assets/javascripts/abcjs/write/abc_graphelements.js +0 -790
@@ -1,5 +1,5 @@
1
1
  module Abcjs
2
2
  module Rails
3
- VERSION = "1.8"
3
+ VERSION = "1.11"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abcjs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.8'
4
+ version: '1.11'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Rosen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-12 00:00:00.000000000 Z
11
+ date: 2014-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  description: Delivery of the abcjs javascript library.
@@ -31,8 +31,10 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - lib/abcjs-rails/version.rb
35
- - lib/abcjs-rails.rb
34
+ - LICENSE
35
+ - README.md
36
+ - app/assets/javascripts/abcjs-rails.js
37
+ - app/assets/javascripts/abcjs/api/abc_animation.js
36
38
  - app/assets/javascripts/abcjs/api/abc_tunebook.js
37
39
  - app/assets/javascripts/abcjs/data/abc_tune.js
38
40
  - app/assets/javascripts/abcjs/edit/abc_editor.js
@@ -43,15 +45,23 @@ files:
43
45
  - app/assets/javascripts/abcjs/parse/abc_parse_header.js
44
46
  - app/assets/javascripts/abcjs/parse/abc_parse_key_voice.js
45
47
  - app/assets/javascripts/abcjs/parse/abc_tokenizer.js
48
+ - app/assets/javascripts/abcjs/raphael.js
49
+ - app/assets/javascripts/abcjs/write/abc_absolute_element.js
50
+ - app/assets/javascripts/abcjs/write/abc_beam_element.js
51
+ - app/assets/javascripts/abcjs/write/abc_cresendo_element.js
52
+ - app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js
53
+ - app/assets/javascripts/abcjs/write/abc_ending_element.js
46
54
  - app/assets/javascripts/abcjs/write/abc_glyphs.js
47
- - app/assets/javascripts/abcjs/write/abc_graphelements.js
48
55
  - app/assets/javascripts/abcjs/write/abc_layout.js
56
+ - app/assets/javascripts/abcjs/write/abc_relative_element.js
57
+ - app/assets/javascripts/abcjs/write/abc_staff_group_element.js
58
+ - app/assets/javascripts/abcjs/write/abc_tie_element.js
59
+ - app/assets/javascripts/abcjs/write/abc_triplet_element.js
60
+ - app/assets/javascripts/abcjs/write/abc_voice_element.js
49
61
  - app/assets/javascripts/abcjs/write/abc_write.js
50
- - app/assets/javascripts/abcjs/write/raphael.js
51
62
  - app/assets/javascripts/abcjs/write/sprintf.js
52
- - app/assets/javascripts/abcjs-rails.js
53
- - LICENSE
54
- - README.md
63
+ - lib/abcjs-rails.rb
64
+ - lib/abcjs-rails/version.rb
55
65
  homepage: http://paulrosen.net
56
66
  licenses: []
57
67
  metadata: {}
@@ -61,17 +71,17 @@ require_paths:
61
71
  - lib
62
72
  required_ruby_version: !ruby/object:Gem::Requirement
63
73
  requirements:
64
- - - '>='
74
+ - - ">="
65
75
  - !ruby/object:Gem::Version
66
76
  version: '0'
67
77
  required_rubygems_version: !ruby/object:Gem::Requirement
68
78
  requirements:
69
- - - '>='
79
+ - - ">="
70
80
  - !ruby/object:Gem::Version
71
81
  version: '0'
72
82
  requirements: []
73
83
  rubyforge_project:
74
- rubygems_version: 2.1.11
84
+ rubygems_version: 2.2.2
75
85
  signing_key:
76
86
  specification_version: 4
77
87
  summary: This packages the abcjs javascript files in a gem for easy reuse in Rails
@@ -1,790 +0,0 @@
1
- // abc_graphelements.js: All the drawable and layoutable datastructures to be printed by ABCJS.write.Printer
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
- /*global window, ABCJS */
18
-
19
- if (!window.ABCJS)
20
- window.ABCJS = {};
21
-
22
- if (!window.ABCJS.write)
23
- window.ABCJS.write = {};
24
-
25
- ABCJS.write.StaffGroupElement = function() {
26
- this.voices = [];
27
- this.staffs = [];
28
- this.stafflines = [];
29
- };
30
-
31
- ABCJS.write.StaffGroupElement.prototype.addVoice = function (voice, staffnumber, stafflines) {
32
- this.voices[this.voices.length] = voice;
33
- if (!this.staffs[staffnumber]) {
34
- this.staffs[this.staffs.length] = {top:0, highest: 7, lowest: 7};
35
- this.stafflines[this.stafflines.length] = stafflines;
36
- }
37
- voice.staff = this.staffs[staffnumber];
38
- };
39
-
40
- ABCJS.write.StaffGroupElement.prototype.finished = function() {
41
- for (var i=0;i<this.voices.length;i++) {
42
- if (!this.voices[i].layoutEnded()) return false;
43
- }
44
- return true;
45
- };
46
-
47
- ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, printer, debug) {
48
- this.spacingunits = 0; // number of space units taken up (as opposed to fixed width). Layout engine then decides how many a pixels a space unit should be
49
- this.minspace = 1000; // a big number to start off with
50
- var x = printer.paddingleft*printer.scale;
51
-
52
- // find out how much space will be taken up by voice headers
53
- var voiceheaderw = 0;
54
- for (var i=0;i<this.voices.length;i++) {
55
- if(this.voices[i].header) {
56
- var t = printer.paper.text(100*printer.scale, -10*printer.scale, this.voices[i].header).attr({"font-size":12*printer.scale, "font-family":"serif", 'font-weight':'bold'}); // code duplicated below // don't scale this as we ask for the bbox
57
- voiceheaderw = Math.max(voiceheaderw,t.getBBox().width);
58
- t.remove();
59
- }
60
- }
61
- x=x+voiceheaderw*(1/printer.scale)*1.1; // 10% of 0 is 0
62
- this.startx=x;
63
-
64
- var currentduration = 0;
65
- if (debug) console.log("init layout");
66
- for (i=0;i<this.voices.length;i++) {
67
- this.voices[i].beginLayout(x);
68
- }
69
-
70
- while (!this.finished()) {
71
- // find first duration level to be laid out among candidates across voices
72
- currentduration= null; // candidate smallest duration level
73
- for (i=0;i<this.voices.length;i++) {
74
- if (!this.voices[i].layoutEnded() && (!currentduration || this.voices[i].getDurationIndex()<currentduration))
75
- currentduration=this.voices[i].getDurationIndex();
76
- }
77
- if (debug) console.log("currentduration: ",currentduration);
78
-
79
-
80
- // isolate voices at current duration level
81
- var currentvoices = [];
82
- var othervoices = [];
83
- for (i=0;i<this.voices.length;i++) {
84
- if (this.voices[i].getDurationIndex() !== currentduration) {
85
- othervoices.push(this.voices[i]);
86
- //console.log("out: voice ",i);
87
- } else {
88
- currentvoices.push(this.voices[i]);
89
- if (debug) console.log("in: voice ",i);
90
- }
91
- }
92
-
93
- // among the current duration level find the one which needs starting furthest right
94
- var spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
95
- for (i=0;i<currentvoices.length;i++) {
96
- if (currentvoices[i].nextx>x) {
97
- x=currentvoices[i].nextx;
98
- spacingunit=currentvoices[i].spacingunits;
99
- }
100
- }
101
- this.spacingunits+=spacingunit;
102
- this.minspace = Math.min(this.minspace,spacingunit);
103
-
104
- // remove the value of already counted spacing units in other voices (e.g. if a voice had planned to use up 5 spacing units but is not in line to be laid out at this duration level - where we've used 2 spacing units - then we must use up 3 spacing units, not 5)
105
- for (i=0;i<othervoices.length;i++) {
106
- if (othervoices[i].spacingunits-=spacingunit);
107
- }
108
-
109
- for (i=0;i<currentvoices.length;i++) {
110
- var voicechildx = currentvoices[i].layoutOneItem(x,spacing);
111
- var dx = voicechildx-x;
112
- if (dx>0) {
113
- x = voicechildx; //update x
114
- for (var j=0;j<i;j++) { // shift over all previously laid out elements
115
- currentvoices[j].shiftRight(dx);
116
- }
117
- }
118
- }
119
-
120
- // update indexes of currently laid out elems
121
- for (i=0;i<currentvoices.length;i++) {
122
- var voice = currentvoices[i];
123
- voice.updateIndices();
124
- }
125
- } // finished laying out
126
-
127
-
128
- // find the greatest remaining x as a base for the width
129
- for (i=0;i<this.voices.length;i++) {
130
- if (this.voices[i].nextx>x) {
131
- x=this.voices[i].nextx;
132
- spacingunit=this.voices[i].spacingunits;
133
- }
134
- }
135
- this.spacingunits+=spacingunit;
136
- this.w = x;
137
-
138
- for (i=0;i<this.voices.length;i++) {
139
- this.voices[i].w=this.w;
140
- }
141
- };
142
-
143
- ABCJS.write.StaffGroupElement.prototype.draw = function (printer, y) {
144
-
145
- this.y = y;
146
- for (var i=0;i<this.staffs.length;i++) {
147
- var shiftabove = this.staffs[i].highest - ((i===0)? 20 : 15);
148
- var shiftbelow = this.staffs[i].lowest - ((i===this.staffs.length-1)? 0 : 0);
149
- this.staffs[i].top = y;
150
- if (shiftabove > 0) y+= shiftabove*ABCJS.write.spacing.STEP;
151
- this.staffs[i].y = y;
152
- y+= ABCJS.write.spacing.STAVEHEIGHT*0.9; // position of the words
153
- if (shiftbelow < 0) y-= shiftbelow*ABCJS.write.spacing.STEP;
154
- this.staffs[i].bottom = y;
155
- }
156
- this.height = y-this.y;
157
-
158
- var bartop = 0;
159
- for (i=0;i<this.voices.length;i++) {
160
- this.voices[i].draw(printer, bartop);
161
- bartop = this.voices[i].barbottom;
162
- }
163
-
164
- if (this.staffs.length>1) {
165
- printer.y = this.staffs[0].y;
166
- var top = printer.calcY(10);
167
- printer.y = this.staffs[this.staffs.length-1].y;
168
- var bottom = printer.calcY(2);
169
- printer.printStem(this.startx, 0.6, top, bottom);
170
- }
171
-
172
- for (i=0;i<this.staffs.length;i++) {
173
- if (this.stafflines[i] === 0) continue;
174
- printer.y = this.staffs[i].y;
175
- // TODO-PER: stafflines should always have been set somewhere, so this shouldn't be necessary.
176
- if (this.stafflines[i] === undefined)
177
- this.stafflines[i] = 5;
178
- printer.printStave(this.startx,this.w, this.stafflines[i]);
179
- }
180
-
181
- };
182
-
183
- ABCJS.write.VoiceElement = function(voicenumber, voicetotal) {
184
- this.children = [];
185
- this.beams = [];
186
- this.otherchildren = []; // ties, slurs, triplets
187
- this.w = 0;
188
- this.duplicate = false;
189
- this.voicenumber = voicenumber; //number of the voice on a given stave (not staffgroup)
190
- this.voicetotal = voicetotal;
191
- };
192
-
193
- ABCJS.write.VoiceElement.prototype.addChild = function (child) {
194
- this.children[this.children.length] = child;
195
- };
196
-
197
- ABCJS.write.VoiceElement.prototype.addOther = function (child) {
198
- if (child instanceof ABCJS.write.BeamElem) {
199
- this.beams.push(child);
200
- } else {
201
- this.otherchildren.push(child);
202
- }
203
- };
204
-
205
- ABCJS.write.VoiceElement.prototype.updateIndices = function () {
206
- if (!this.layoutEnded()) {
207
- this.durationindex += this.children[this.i].duration;
208
- if (this.children[this.i].duration===0) this.durationindex = Math.round(this.durationindex*64)/64; // everytime we meet a barline, do rounding to nearest 64th
209
- this.i++;
210
- this.minx = this.nextminx;
211
- }
212
- };
213
-
214
- ABCJS.write.VoiceElement.prototype.layoutEnded = function () {
215
- return (this.i>=this.children.length);
216
- };
217
-
218
- ABCJS.write.VoiceElement.prototype.getDurationIndex = function () {
219
- return this.durationindex - (this.children[this.i] && (this.children[this.i].duration>0)?0:0.0000005); // if the ith element doesn't have a duration (is not a note), its duration index is fractionally before. This enables CLEF KEYSIG TIMESIG PART, etc. to be laid out before we get to the first note of other voices
220
- };
221
-
222
- ABCJS.write.VoiceElement.prototype.beginLayout = function (startx) {
223
- this.i=0;
224
- this.durationindex=0;
225
- this.ii=this.children.length;
226
- this.startx=startx;
227
- this.minx=startx; // furthest left to where negatively positioned elements are allowed to go
228
- this.nextminx=startx;
229
- this.nextx=startx; // x position where the next element of this voice should be placed assuming no other voices
230
- this.spacingunits=0; // units of spacing used in current iteration due to duration
231
- };
232
-
233
- // Try to layout the element at index this.i
234
- // x - position to try to layout the element at
235
- // spacing - base spacing
236
- ABCJS.write.VoiceElement.prototype.layoutOneItem = function (x, spacing) {
237
- var child = this.children[this.i];
238
- if (!child) return 0;
239
- var er = x - this.minx; // available extrawidth to the left
240
- if (er<child.getExtraWidth()) { // shift right by needed amount
241
- x+=child.getExtraWidth()-er;
242
- }
243
- child.x=x;
244
- x+=(spacing*Math.sqrt(child.duration*8)); // add necessary duration space
245
- this.nextminx = child.x+child.getMinWidth(); // add necessary layout space
246
- if (this.i!==this.ii-1) this.nextminx+=child.minspacing; // add minimumspacing except on last elem
247
- if (this.nextminx > x) {
248
- x = this.nextminx;
249
- this.spacingunits=0;
250
- } else {
251
- this.spacingunits=Math.sqrt(child.duration*8);
252
- }
253
- this.nextx = x;
254
- // contribute to staff y position
255
- this.staff.highest = Math.max(child.top,this.staff.highest);
256
- this.staff.lowest = Math.min(child.bottom,this.staff.lowest);
257
- return child.x;
258
- };
259
-
260
- ABCJS.write.VoiceElement.prototype.shiftRight = function (dx) {
261
- var child = this.children[this.i];
262
- if (!child) return;
263
- child.x+=dx;
264
- this.nextminx+=dx;
265
- this.nextx+=dx;
266
- };
267
-
268
- ABCJS.write.VoiceElement.prototype.draw = function (printer, bartop) {
269
- var width = this.w-1;
270
- printer.y = this.staff.y;
271
- printer.staffbottom = this.staff.bottom;
272
- this.barbottom = printer.calcY(2);
273
-
274
- if (this.header) { // print voice name
275
- var textpitch = 12 - (this.voicenumber+1)*(12/(this.voicetotal+1));
276
- var headerX = (this.startx-printer.paddingleft)/2+printer.paddingleft;
277
- headerX = headerX*printer.scale;
278
- printer.paper.text(headerX, printer.calcY(textpitch)*printer.scale, this.header).attr({"font-size":12*printer.scale, "font-family":"serif", 'font-weight':'bold'}); // code duplicated above
279
- }
280
-
281
- for (var i=0, ii=this.children.length; i<ii; i++) {
282
- this.children[i].draw(printer, (this.barto || i===ii-1)?bartop:0);
283
- }
284
- window.ABCJS.parse.each(this.beams, function(beam) {
285
- beam.draw(printer); // beams must be drawn first for proper printing of triplets, slurs and ties.
286
- });
287
- window.ABCJS.parse.each(this.otherchildren, function(child) {
288
- child.draw(printer,this.startx+10,width);
289
- });
290
-
291
- };
292
-
293
- // duration - actual musical duration - different from notehead duration in triplets. refer to abcelem to get the notehead duration
294
- // minspacing - spacing which must be taken on top of the width defined by the duration
295
- ABCJS.write.AbsoluteElement = function(abcelem, duration, minspacing) {
296
- this.abcelem = abcelem;
297
- this.duration = duration;
298
- this.minspacing = minspacing || 0;
299
- this.x = 0;
300
- this.children = [];
301
- this.heads = [];
302
- this.extra = [];
303
- this.extraw = 0;
304
- this.decs = [];
305
- this.w = 0;
306
- this.right = [];
307
- this.invisible = false;
308
- this.bottom = 7;
309
- this.top = 7;
310
- };
311
-
312
- ABCJS.write.AbsoluteElement.prototype.getMinWidth = function () { // absolute space taken to the right of the note
313
- return this.w;
314
- };
315
-
316
- ABCJS.write.AbsoluteElement.prototype.getExtraWidth = function () { // space needed to the left of the note
317
- return -this.extraw;
318
- };
319
-
320
- ABCJS.write.AbsoluteElement.prototype.addExtra = function (extra) {
321
- if (extra.dx<this.extraw) this.extraw = extra.dx;
322
- this.extra[this.extra.length] = extra;
323
- this.addChild(extra);
324
- };
325
-
326
- ABCJS.write.AbsoluteElement.prototype.addHead = function (head) {
327
- if (head.dx<this.extraw) this.extraw = head.dx;
328
- this.heads[this.heads.length] = head;
329
- this.addRight(head);
330
- };
331
-
332
- ABCJS.write.AbsoluteElement.prototype.addRight = function (right) {
333
- if (right.dx+right.w>this.w) this.w = right.dx+right.w;
334
- this.right[this.right.length] = right;
335
- this.addChild(right);
336
- };
337
-
338
- ABCJS.write.AbsoluteElement.prototype.addChild = function (child) {
339
- child.parent = this;
340
- this.children[this.children.length] = child;
341
- this.pushTop(child.top);
342
- this.pushBottom(child.bottom);
343
- };
344
-
345
- ABCJS.write.AbsoluteElement.prototype.pushTop = function (top) {
346
- this.top = Math.max(top, this.top);
347
- };
348
-
349
- ABCJS.write.AbsoluteElement.prototype.pushBottom = function (bottom) {
350
- this.bottom = Math.min(bottom, this.bottom);
351
- };
352
-
353
- ABCJS.write.AbsoluteElement.prototype.draw = function (printer, bartop) {
354
- this.elemset = printer.paper.set();
355
- if (this.invisible) return;
356
- printer.beginGroup();
357
- for (var i=0; i<this.children.length; i++) {
358
- this.elemset.push(this.children[i].draw(printer,this.x, bartop));
359
- }
360
- this.elemset.push(printer.endGroup());
361
- if (this.klass)
362
- this.setClass("mark", "", "#00ff00");
363
- var self = this;
364
- this.elemset.mouseup(function (e) {
365
- printer.notifySelect(self);
366
- });
367
- this.abcelem.abselem = this;
368
-
369
- var spacing = ABCJS.write.spacing.STEP*printer.scale;
370
-
371
- var start = function () {
372
- // storing original relative coordinates
373
- this.dy = 0;
374
- },
375
- move = function (dx, dy) {
376
- // move will be called with dx and dy
377
- dy = Math.round(dy/spacing)*spacing;
378
- this.translate(0, -this.dy);
379
- this.dy = dy;
380
- this.translate(0,this.dy);
381
- },
382
- up = function () {
383
- var delta = -Math.round(this.dy/spacing);
384
- self.abcelem.pitches[0].pitch += delta;
385
- self.abcelem.pitches[0].verticalPos += delta;
386
- printer.notifyChange();
387
- };
388
- if (this.abcelem.el_type==="note" && printer.editable)
389
- this.elemset.drag(move, start, up);
390
- };
391
-
392
- ABCJS.write.AbsoluteElement.prototype.isIE=/*@cc_on!@*/false;//IE detector
393
-
394
- ABCJS.write.AbsoluteElement.prototype.setClass = function (addClass, removeClass, color) {
395
- this.elemset.attr({fill:color});
396
- if (!this.isIE) {
397
- for (var i = 0; i < this.elemset.length; i++) {
398
- if (this.elemset[i][0].setAttribute) {
399
- var kls = this.elemset[i][0].getAttribute("class");
400
- if (!kls) kls = "";
401
- kls = kls.replace(removeClass, "");
402
- kls = kls.replace(addClass, "");
403
- if (addClass.length > 0) {
404
- if (kls.length > 0 && kls.charAt(kls.length-1) !== ' ') kls += " ";
405
- kls += addClass;
406
- }
407
- this.elemset[i][0].setAttribute("class", kls);
408
- }
409
- }
410
- }
411
- };
412
-
413
- ABCJS.write.AbsoluteElement.prototype.highlight = function () {
414
- this.setClass("note_selected", "", "#ff0000");
415
- };
416
-
417
- ABCJS.write.AbsoluteElement.prototype.unhighlight = function () {
418
- this.setClass("", "note_selected", "#000000");
419
- };
420
-
421
- ABCJS.write.RelativeElement = function(c, dx, w, pitch, opt) {
422
- opt = opt || {};
423
- this.x = 0;
424
- this.c = c; // character or path or string
425
- this.dx = dx; // relative x position
426
- this.w = w; // minimum width taken up by this element (can include gratuitous space)
427
- this.pitch = pitch; // relative y position by pitch
428
- this.scalex = opt.scalex || 1; // should the character/path be scaled?
429
- this.scaley = opt.scaley || 1; // should the character/path be scaled?
430
- this.type = opt.type || "symbol"; // cheap types.
431
- this.pitch2 = opt.pitch2;
432
- this.linewidth = opt.linewidth;
433
- this.attributes = opt.attributes; // only present on textual elements
434
- this.top = pitch + ((opt.extreme==="above")? 7 : 0);
435
- this.bottom = pitch - ((opt.extreme==="below")? 7 : 0);
436
- };
437
-
438
- ABCJS.write.RelativeElement.prototype.draw = function (printer, x, bartop) {
439
- this.x = x+this.dx;
440
- switch(this.type) {
441
- case "symbol":
442
- if (this.c===null) return null;
443
- this.graphelem = printer.printSymbol(this.x, this.pitch, this.c, this.scalex, this.scaley); break;
444
- case "debug":
445
- this.graphelem = printer.debugMsg(this.x, this.c); break;
446
- case "debugLow":
447
- this.graphelem = printer.printLyrics(this.x, this.c); break;
448
- case "text":
449
- this.graphelem = printer.printText(this.x, this.pitch, this.c);
450
- break;
451
- case "bar":
452
- this.graphelem = printer.printStem(this.x, this.linewidth, printer.calcY(this.pitch), (bartop)?bartop:printer.calcY(this.pitch2)); break; // bartop can't be 0
453
- case "stem":
454
- this.graphelem = printer.printStem(this.x, this.linewidth, printer.calcY(this.pitch), printer.calcY(this.pitch2)); break;
455
- case "ledger":
456
- this.graphelem = printer.printStaveLine(this.x, this.x+this.w, this.pitch); break;
457
- }
458
- if (this.scalex!==1 && this.graphelem) {
459
- this.graphelem.scale(this.scalex, this.scaley, this.x, printer.calcY(this.pitch));
460
- }
461
- if (this.attributes) {
462
- this.graphelem.attr(this.attributes);
463
- }
464
- return this.graphelem;
465
- };
466
-
467
- ABCJS.write.EndingElem = function(text, anchor1, anchor2) {
468
- this.text = text; // text to be displayed top left
469
- this.anchor1 = anchor1; // must have a .x property or be null (means starts at the "beginning" of the line - after keysig)
470
- this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
471
- };
472
-
473
- ABCJS.write.EndingElem.prototype.draw = function (printer, linestartx, lineendx) {
474
- var pathString;
475
- if (this.anchor1) {
476
- linestartx = this.anchor1.x+this.anchor1.w;
477
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
478
- linestartx, printer.y, linestartx, printer.y+10);
479
- printer.printPath({path:pathString, stroke:"#000000", fill:"#000000"}); //TODO scale
480
- printer.printText(linestartx+5*printer.scale, 18.5, this.text).attr({"font-size":""+10*printer.scale+"px"});
481
- }
482
-
483
- if (this.anchor2) {
484
- lineendx = this.anchor2.x;
485
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
486
- lineendx, printer.y, lineendx, printer.y+10);
487
- printer.printPath({path:pathString, stroke:"#000000", fill:"#000000"}); // TODO scale
488
- }
489
-
490
-
491
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
492
- linestartx, printer.y, lineendx, printer.y);
493
- printer.printPath({path:pathString, stroke:"#000000", fill:"#000000"}); // TODO scale
494
- };
495
-
496
- ABCJS.write.TieElem = function(anchor1, anchor2, above, forceandshift) {
497
- this.anchor1 = anchor1; // must have a .x and a .pitch, and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
498
- this.anchor2 = anchor2; // must have a .x and a .pitch property or be null (means ends at the end of the line)
499
- this.above = above; // true if the arc curves above
500
- this.force = forceandshift; // force the arc curve, regardless of beaming if true
501
- // move by +7 "up" by -7 if "down"
502
- };
503
-
504
- ABCJS.write.TieElem.prototype.draw = function (printer, linestartx, lineendx) {
505
- var startpitch;
506
- var endpitch;
507
-
508
- if (this.startlimitelem) {
509
- linestartx = this.startlimitelem.x+this.startlimitelem.w;
510
- }
511
-
512
- if (this.endlimitelem) {
513
- lineendx = this.endlimitelem.x;
514
- }
515
- // PER: We might have to override the natural slur direction if the first and last notes are not in the
516
- // save direction. We always put the slur up in this case. The one case that works out wrong is that we always
517
- // want the slur to be up when the last note is stem down. We can tell the stem direction if the top is
518
- // equal to the pitch: if so, there is no stem above it.
519
- if (!this.force && this.anchor2 && this.anchor2.pitch === this.anchor2.top)
520
- this.above = true;
521
-
522
- if (this.anchor1) {
523
- linestartx = this.anchor1.x;
524
- startpitch = this.above ? this.anchor1.highestVert : this.anchor1.pitch;
525
- if (!this.anchor2) {
526
- endpitch = this.above ? this.anchor1.highestVert : this.anchor1.pitch;
527
- }
528
- }
529
-
530
- if (this.anchor2) {
531
- lineendx = this.anchor2.x;
532
- endpitch = this.above ? this.anchor2.highestVert : this.anchor2.pitch;
533
- if (!this.anchor1) {
534
- startpitch = this.above ? this.anchor2.highestVert : this.anchor2.pitch;
535
- }
536
- }
537
-
538
- // if (this.anchor1 && this.anchor2) {
539
- // if ((!this.force && this.anchor1.parent.beam && this.anchor2.parent.beam &&
540
- // this.anchor1.parent.beam.asc===this.anchor2.parent.beam.asc) ||
541
- // ((this.force==="up") || this.force==="down") && this.anchor1.parent.beam && this.anchor2.parent.beam && this.anchor1.parent.beam===this.anchor2.parent.beam) {
542
- // this.above = !this.anchor1.parent.beam.asc;
543
- // preservebeamdir = true;
544
- // }
545
- // }
546
-
547
- // var pitchshift = 0;
548
- // if (this.force==="up" && !preservebeamdir) pitchshift = 7;
549
- // if (this.force==="down" && !preservebeamdir) pitchshift = -7;
550
-
551
- // printer.debugMsgLow(linestartx, debugMsg);
552
- printer.drawArc(linestartx, lineendx, startpitch, endpitch, this.above);
553
-
554
- };
555
-
556
- ABCJS.write.DynamicDecoration = function(anchor, dec) {
557
- this.anchor = anchor;
558
- this.dec = dec;
559
- };
560
-
561
- ABCJS.write.DynamicDecoration.prototype.draw = function(printer, linestartx, lineendx) {
562
- var ypos = printer.layouter.minY - 7;
563
- var scalex = 1; // TODO-PER: do the scaling
564
- var scaley = 1;
565
- printer.printSymbol(this.anchor.x, ypos, this.dec, scalex, scaley);
566
- };
567
-
568
- ABCJS.write.CrescendoElem = function(anchor1, anchor2, dir) {
569
- this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
570
- this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
571
- this.dir = dir; // either "<" or ">"
572
- };
573
-
574
- ABCJS.write.CrescendoElem.prototype.draw = function (printer, linestartx, lineendx) {
575
- if (this.dir === "<") {
576
- this.drawLine(printer, 0, -4);
577
- this.drawLine(printer, 0, 4);
578
- } else {
579
- this.drawLine(printer, -4, 0);
580
- this.drawLine(printer, 4, 0);
581
- }
582
- };
583
-
584
- ABCJS.write.CrescendoElem.prototype.drawLine = function (printer, y1, y2) {
585
- var ypos = printer.layouter.minY - 7;
586
- var pathString = ABCJS.write.sprintf("M %f %f L %f %f",
587
- this.anchor1.x, printer.calcY(ypos)+y1-4, this.anchor2.x, printer.calcY(ypos)+y2-4);
588
- printer.printPath({path:pathString, stroke:"#000000"});
589
- };
590
-
591
- ABCJS.write.TripletElem = function(number, anchor1, anchor2, above) {
592
- this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
593
- this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
594
- this.above = above;
595
- this.number = number;
596
- };
597
-
598
- ABCJS.write.TripletElem.prototype.draw = function (printer, linestartx, lineendx) {
599
- // TODO end and beginning of line
600
- if (this.anchor1 && this.anchor2) {
601
- var ypos = this.above?16:-1; // PER: Just bumped this up from 14 to make (3z2B2B2 (3B2B2z2 succeed. There's probably a better way.
602
-
603
- if (this.anchor1.parent.beam &&
604
- this.anchor1.parent.beam===this.anchor2.parent.beam) {
605
- var beam = this.anchor1.parent.beam;
606
- this.above = beam.asc;
607
- ypos = beam.pos;
608
- } else {
609
- this.drawLine(printer,printer.calcY(ypos));
610
- }
611
- var xsum = this.anchor1.x+this.anchor2.x;
612
- var ydelta = 0;
613
- if (beam) {
614
- if (this.above) {
615
- xsum += (this.anchor2.w + this.anchor1.w);
616
- ydelta = 4;
617
- } else {
618
- ydelta = -4;
619
- }
620
- } else {
621
- xsum += this.anchor2.w;
622
- }
623
-
624
-
625
- printer.printText(xsum/2, ypos+ydelta, this.number, "middle").attr({"font-size":"10px", 'font-style': 'italic' });
626
-
627
- }
628
- };
629
-
630
- ABCJS.write.TripletElem.prototype.drawLine = function (printer, y) {
631
- var pathString;
632
- var linestartx = this.anchor1.x;
633
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
634
- linestartx, y, linestartx, y+5);
635
- printer.printPath({path:pathString, stroke:"#000000"});
636
-
637
- var lineendx = this.anchor2.x+this.anchor2.w;
638
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
639
- lineendx, y, lineendx, y+5);
640
- printer.printPath({path:pathString, stroke:"#000000"});
641
-
642
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
643
- linestartx, y, (linestartx+lineendx)/2-5, y);
644
- printer.printPath({path:pathString, stroke:"#000000"});
645
-
646
-
647
- pathString = ABCJS.write.sprintf("M %f %f L %f %f",
648
- (linestartx+lineendx)/2+5, y, lineendx, y);
649
- printer.printPath({path:pathString, stroke:"#000000"});
650
-
651
- };
652
-
653
- ABCJS.write.BeamElem = function(type, flat) {
654
- this.isflat = (flat);
655
- this.isgrace = (type && type==="grace");
656
- this.forceup = (type && type==="up");
657
- this.forcedown = (type && type==="down");
658
- this.elems = []; // all the ABCJS.write.AbsoluteElements
659
- this.total = 0;
660
- this.dy = (this.asc)?ABCJS.write.spacing.STEP*1.2:-ABCJS.write.spacing.STEP*1.2;
661
- if (this.isgrace) this.dy = this.dy*0.4;
662
- this.allrests = true;
663
- };
664
-
665
- ABCJS.write.BeamElem.prototype.add = function(abselem) {
666
- var pitch = abselem.abcelem.averagepitch;
667
- if (pitch===undefined) return; // don't include elements like spacers in beams
668
- this.allrests = this.allrests && abselem.abcelem.rest;
669
- abselem.beam = this;
670
- this.elems.push(abselem);
671
- //var pitch = abselem.abcelem.averagepitch;
672
- this.total += pitch; // TODO CHORD (get pitches from abselem.heads)
673
- if (!this.min || abselem.abcelem.minpitch<this.min) {
674
- this.min = abselem.abcelem.minpitch;
675
- }
676
- if (!this.max || abselem.abcelem.maxpitch>this.max) {
677
- this.max = abselem.abcelem.maxpitch;
678
- }
679
- };
680
-
681
- ABCJS.write.BeamElem.prototype.average = function() {
682
- try {
683
- return this.total/this.elems.length;
684
- } catch (e) {
685
- return 0;
686
- }
687
- };
688
-
689
- ABCJS.write.BeamElem.prototype.draw = function(printer) {
690
- if (this.elems.length === 0 || this.allrests) return;
691
- this.drawBeam(printer);
692
- this.drawStems(printer);
693
- };
694
-
695
- ABCJS.write.BeamElem.prototype.calcDir = function() {
696
- var average = this.average();
697
- // var barpos = (this.isgrace)? 5:7;
698
- this.asc = (this.forceup || this.isgrace || average<6) && (!this.forcedown); // hardcoded 6 is B
699
- return this.asc;
700
- };
701
-
702
- ABCJS.write.BeamElem.prototype.drawBeam = function(printer) {
703
- var average = this.average();
704
- var barpos = (this.isgrace)? 5:7;
705
- this.calcDir();
706
-
707
- var barminpos = this.asc ? 5 : 8; //PER: I just bumped up the minimum height for notes with descending stems to clear a rest in the middle of them.
708
- this.pos = Math.round(this.asc ? Math.max(average+barpos,this.max+barminpos) : Math.min(average-barpos,this.min-barminpos));
709
- var slant = this.elems[0].abcelem.averagepitch-this.elems[this.elems.length-1].abcelem.averagepitch;
710
- if (this.isflat) slant=0;
711
- var maxslant = this.elems.length/2;
712
-
713
- if (slant>maxslant) slant = maxslant;
714
- if (slant<-maxslant) slant = -maxslant;
715
- this.starty = printer.calcY(this.pos+Math.floor(slant/2));
716
- this.endy = printer.calcY(this.pos+Math.floor(-slant/2));
717
-
718
- var starthead = this.elems[0].heads[(this.asc)? 0: this.elems[0].heads.length-1];
719
- var endhead = this.elems[this.elems.length-1].heads[(this.asc)? 0: this.elems[this.elems.length-1].heads.length-1];
720
- this.startx = starthead.x;
721
- if(this.asc) this.startx+=starthead.w-0.6;
722
- this.endx = endhead.x;
723
- if(this.asc) this.endx+=endhead.w;
724
-
725
- // PER: if the notes are too high or too low, make the beam go down to the middle
726
- if (this.asc && this.pos < 6) {
727
- this.starty = printer.calcY(6);
728
- this.endy = printer.calcY(6);
729
- } else if (!this.asc && this.pos > 6) {
730
- this.starty = printer.calcY(6);
731
- this.endy = printer.calcY(6);
732
- }
733
-
734
- var pathString = "M"+this.startx+" "+this.starty+" L"+this.endx+" "+this.endy+
735
- "L"+this.endx+" "+(this.endy+this.dy) +" L"+this.startx+" "+(this.starty+this.dy)+"z";
736
- printer.printPath({path:pathString, stroke:"none", fill:"#000000"});
737
- };
738
-
739
- ABCJS.write.BeamElem.prototype.drawStems = function(printer) {
740
- var auxbeams = []; // auxbeam will be {x, y, durlog, single} auxbeam[0] should match with durlog=-4 (16th) (j=-4-durlog)
741
- printer.beginGroup();
742
- for (var i=0,ii=this.elems.length; i<ii; i++) {
743
- if (this.elems[i].abcelem.rest)
744
- continue;
745
- var furthesthead = this.elems[i].heads[(this.asc)? 0: this.elems[i].heads.length-1];
746
- var ovaldelta = (this.isgrace)?1/3:1/5;
747
- var pitch = furthesthead.pitch + ((this.asc) ? ovaldelta : -ovaldelta);
748
- var y = printer.calcY(pitch);
749
- var x = furthesthead.x + ((this.asc) ? furthesthead.w: 0);
750
- var bary=this.getBarYAt(x);
751
- var dx = (this.asc) ? -0.6 : 0.6;
752
- printer.printStem(x,dx,y,bary);
753
-
754
- var sy = (this.asc) ? 1.5*ABCJS.write.spacing.STEP: -1.5*ABCJS.write.spacing.STEP;
755
- if (this.isgrace) sy = sy*2/3;
756
- for (var durlog=ABCJS.write.getDurlog(this.elems[i].abcelem.duration); durlog<-3; durlog++) { // get the duration via abcelem because of triplets
757
- if (auxbeams[-4-durlog]) {
758
- auxbeams[-4-durlog].single = false;
759
- } else {
760
- auxbeams[-4-durlog] = {x:x+((this.asc)?-0.6:0), y:bary+sy*(-4-durlog+1),
761
- durlog:durlog, single:true};
762
- }
763
- }
764
-
765
- for (var j=auxbeams.length-1;j>=0;j--) {
766
- if (i===ii-1 || ABCJS.write.getDurlog(this.elems[i+1].abcelem.duration)>(-j-4)) {
767
-
768
- var auxbeamendx = x;
769
- var auxbeamendy = bary + sy*(j+1);
770
-
771
-
772
- if (auxbeams[j].single) {
773
- auxbeamendx = (i===0) ? x+5 : x-5;
774
- auxbeamendy = this.getBarYAt(auxbeamendx) + sy*(j+1);
775
- }
776
- // TODO I think they are drawn from front to back, hence the small x difference with the main beam
777
-
778
- var pathString ="M"+auxbeams[j].x+" "+auxbeams[j].y+" L"+auxbeamendx+" "+auxbeamendy+
779
- "L"+auxbeamendx+" "+(auxbeamendy+this.dy) +" L"+auxbeams[j].x+" "+(auxbeams[j].y+this.dy)+"z";
780
- printer.printPath({path:pathString, stroke:"none", fill:"#000000"});
781
- auxbeams = auxbeams.slice(0,j);
782
- }
783
- }
784
- }
785
- printer.endGroup();
786
- };
787
-
788
- ABCJS.write.BeamElem.prototype.getBarYAt = function(x) {
789
- return this.starty + (this.endy-this.starty)/(this.endx-this.startx)*(x-this.startx);
790
- };