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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/abcjs/api/abc_animation.js +224 -0
- data/app/assets/javascripts/abcjs/api/abc_tunebook.js +158 -154
- data/app/assets/javascripts/abcjs/data/abc_tune.js +35 -1
- data/app/assets/javascripts/abcjs/edit/abc_editor.js +18 -17
- data/app/assets/javascripts/abcjs/parse/abc_parse.js +23 -6
- data/app/assets/javascripts/abcjs/parse/abc_parse_header.js +5 -1
- data/app/assets/javascripts/abcjs/{write/raphael.js → raphael.js} +2562 -266
- data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +163 -0
- data/app/assets/javascripts/abcjs/write/abc_beam_element.js +162 -0
- data/app/assets/javascripts/abcjs/write/abc_cresendo_element.js +46 -0
- data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +36 -0
- data/app/assets/javascripts/abcjs/write/abc_ending_element.js +53 -0
- data/app/assets/javascripts/abcjs/write/abc_glyphs.js +6 -3
- data/app/assets/javascripts/abcjs/write/abc_layout.js +84 -29
- data/app/assets/javascripts/abcjs/write/abc_relative_element.js +72 -0
- data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +225 -0
- data/app/assets/javascripts/abcjs/write/abc_tie_element.js +83 -0
- data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +85 -0
- data/app/assets/javascripts/abcjs/write/abc_voice_element.js +177 -0
- data/app/assets/javascripts/abcjs/write/abc_write.js +65 -28
- data/lib/abcjs-rails/version.rb +1 -1
- metadata +24 -14
- data/app/assets/javascripts/abcjs/write/abc_graphelements.js +0 -790
data/lib/abcjs-rails/version.rb
CHANGED
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.
|
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:
|
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
|
-
-
|
35
|
-
-
|
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
|
-
-
|
53
|
-
-
|
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.
|
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
|
-
};
|