abcjs-rails 1.11 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/abcjs/api/abc_animation.js +41 -1
- data/app/assets/javascripts/abcjs/api/abc_tunebook.js +5 -0
- data/app/assets/javascripts/abcjs/data/abc_tune.js +4 -3
- data/app/assets/javascripts/abcjs/edit/abc_editor.js +10 -0
- data/app/assets/javascripts/abcjs/parse/abc_parse.js +120 -19
- data/app/assets/javascripts/abcjs/parse/abc_parse_directive.js +456 -115
- data/app/assets/javascripts/abcjs/raphael.js +2 -2
- data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +111 -4
- data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +899 -0
- data/app/assets/javascripts/abcjs/write/abc_beam_element.js +263 -37
- data/app/assets/javascripts/abcjs/write/abc_create_clef.js +76 -0
- data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +41 -0
- data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +51 -0
- data/app/assets/javascripts/abcjs/write/{abc_cresendo_element.js → abc_crescendo_element.js} +32 -1
- data/app/assets/javascripts/abcjs/write/abc_decoration.js +321 -0
- data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +22 -1
- data/app/assets/javascripts/abcjs/write/abc_ending_element.js +31 -1
- data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +359 -0
- data/app/assets/javascripts/abcjs/write/abc_glyphs.js +119 -9
- data/app/assets/javascripts/abcjs/write/abc_layout.js +2 -2
- data/app/assets/javascripts/abcjs/write/abc_relative_element.js +106 -8
- data/app/assets/javascripts/abcjs/write/abc_renderer.js +754 -0
- data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +249 -9
- data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +104 -0
- data/app/assets/javascripts/abcjs/write/abc_tie_element.js +69 -22
- data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +77 -10
- data/app/assets/javascripts/abcjs/write/abc_voice_element.js +100 -8
- data/app/assets/javascripts/abcjs/write/abc_write.js +64 -68
- data/lib/abcjs-rails/version.rb +1 -1
- metadata +12 -4
@@ -22,48 +22,94 @@ if (!window.ABCJS)
|
|
22
22
|
if (!window.ABCJS.write)
|
23
23
|
window.ABCJS.write = {};
|
24
24
|
|
25
|
-
ABCJS.write.TieElem = function(anchor1, anchor2, above, forceandshift) {
|
25
|
+
ABCJS.write.TieElem = function(anchor1, anchor2, above, forceandshift, isTie) {
|
26
26
|
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)
|
27
27
|
this.anchor2 = anchor2; // must have a .x and a .pitch property or be null (means ends at the end of the line)
|
28
28
|
this.above = above; // true if the arc curves above
|
29
29
|
this.force = forceandshift; // force the arc curve, regardless of beaming if true
|
30
|
-
|
30
|
+
this.isTie = isTie;
|
31
31
|
};
|
32
32
|
|
33
|
+
<<<<<<< HEAD
|
34
|
+
ABCJS.write.TieElem.prototype.setEndAnchor = function(anchor2) {
|
35
|
+
this.anchor2 = anchor2; // must have a .x and a .pitch property or be null (means ends at the end of the line)
|
36
|
+
};
|
37
|
+
=======
|
33
38
|
ABCJS.write.TieElem.prototype.draw = function (renderer, linestartx, lineendx) {
|
34
39
|
var startpitch;
|
35
40
|
var endpitch;
|
41
|
+
>>>>>>> origin/master
|
36
42
|
|
37
|
-
|
38
|
-
|
39
|
-
|
43
|
+
// If we encounter a repeat sign, then we don't want to extend either a tie or a slur past it, so these are called to be a limit.
|
44
|
+
ABCJS.write.TieElem.prototype.setStartX = function(startLimitElem) {
|
45
|
+
this.startLimitX = startLimitElem;
|
46
|
+
};
|
40
47
|
|
41
|
-
|
42
|
-
|
48
|
+
ABCJS.write.TieElem.prototype.setEndX = function(endLimitElem) {
|
49
|
+
this.endLimitX = endLimitElem;
|
50
|
+
};
|
51
|
+
|
52
|
+
ABCJS.write.TieElem.prototype.setUpperAndLowerElements = function(positionY) {
|
53
|
+
// Doesn't depend on the highest and lowest, so there's nothing to do here.
|
54
|
+
};
|
55
|
+
|
56
|
+
ABCJS.write.TieElem.prototype.layout = function (lineStartX, lineEndX) {
|
57
|
+
function getPitch(anchor, isAbove, isTie) {
|
58
|
+
if (isTie) {
|
59
|
+
// Always go to the note
|
60
|
+
return anchor.pitch;
|
61
|
+
}
|
62
|
+
if (isAbove && anchor.highestVert !== undefined)
|
63
|
+
return anchor.highestVert;
|
64
|
+
return anchor.pitch;
|
43
65
|
}
|
66
|
+
// We now have all of the input variables set, so we can figure out the start and ending x,y coordinates, and finalize the direction of the arc.
|
67
|
+
|
44
68
|
// PER: We might have to override the natural slur direction if the first and last notes are not in the
|
45
|
-
//
|
69
|
+
// same direction. We always put the slur up in this case. The one case that works out wrong is that we always
|
46
70
|
// want the slur to be up when the last note is stem down. We can tell the stem direction if the top is
|
47
71
|
// equal to the pitch: if so, there is no stem above it.
|
48
|
-
if (!this.force && this.anchor2 && this.anchor2.pitch === this.anchor2.
|
72
|
+
if (!this.force && this.anchor2 && this.anchor2.pitch === this.anchor2.highestVert) // TODO-PER: this is a fragile way to detect that there is no stem going up on this note.
|
49
73
|
this.above = true;
|
50
74
|
|
51
|
-
if (this.anchor1)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
}
|
75
|
+
if (this.anchor1)
|
76
|
+
this.startX = this.anchor1.x; // The normal case where there is a starting element to attach to.
|
77
|
+
else if (this.startLimitX)
|
78
|
+
this.startX = this.startLimitX.x+this.startLimitX.w; // if there is no start element, but there is a repeat mark before the start of the line.
|
79
|
+
else
|
80
|
+
this.startX = lineStartX; // There is no element and no repeat mark: extend to the beginning of the line.
|
58
81
|
|
59
|
-
if (this.anchor2)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
82
|
+
if (this.anchor2)
|
83
|
+
this.endX = this.anchor2.x; // The normal case where there is a starting element to attach to.
|
84
|
+
else if (this.endLimitX)
|
85
|
+
this.endX = this.endLimitX.x; // if there is no start element, but there is a repeat mark before the start of the line.
|
86
|
+
else
|
87
|
+
this.endX = lineEndX; // There is no element and no repeat mark: extend to the beginning of the line.
|
88
|
+
|
89
|
+
// For the pitches, if one of the anchors is present, both of the pitches are that anchor. If both are present, then we use both. If neither is present, we use the top of the staff.
|
90
|
+
if (this.anchor1 && this.anchor2) {
|
91
|
+
this.startY = getPitch(this.anchor1, this.above, this.isTie);
|
92
|
+
this.endY = getPitch(this.anchor2, this.above, this.isTie);
|
93
|
+
} else if (this.anchor1) {
|
94
|
+
this.startY = getPitch(this.anchor1, this.above, this.isTie);
|
95
|
+
this.endY = getPitch(this.anchor1, this.above, this.isTie);
|
96
|
+
} else if (this.anchor2) {
|
97
|
+
this.startY = getPitch(this.anchor2, this.above, this.isTie);
|
98
|
+
this.endY = getPitch(this.anchor2, this.above, this.isTie);
|
99
|
+
} else {
|
100
|
+
// This is the case where the slur covers the entire line.
|
101
|
+
// TODO-PER: figure out where the real top and bottom of the line are.
|
102
|
+
this.startY = this.above ? 14 : 0;
|
103
|
+
this.endY = this.above ? 14 : 0;
|
65
104
|
}
|
105
|
+
};
|
106
|
+
|
107
|
+
ABCJS.write.TieElem.prototype.draw = function (renderer, linestartx, lineendx) {
|
108
|
+
this.layout(linestartx, lineendx);
|
66
109
|
|
110
|
+
<<<<<<< HEAD
|
111
|
+
renderer.drawArc(this.startX, this.endX, this.startY, this.endY, this.above);
|
112
|
+
=======
|
67
113
|
// if (this.anchor1 && this.anchor2) {
|
68
114
|
// if ((!this.force && this.anchor1.parent.beam && this.anchor2.parent.beam &&
|
69
115
|
// this.anchor1.parent.beam.asc===this.anchor2.parent.beam.asc) ||
|
@@ -79,5 +125,6 @@ ABCJS.write.TieElem.prototype.draw = function (renderer, linestartx, lineendx) {
|
|
79
125
|
|
80
126
|
// renderer.debugMsgLow(linestartx, debugMsg);
|
81
127
|
renderer.drawArc(linestartx, lineendx, startpitch, endpitch, this.above);
|
128
|
+
>>>>>>> origin/master
|
82
129
|
|
83
130
|
};
|
@@ -22,13 +22,63 @@ if (!window.ABCJS)
|
|
22
22
|
if (!window.ABCJS.write)
|
23
23
|
window.ABCJS.write = {};
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
(function() {
|
26
|
+
"use strict";
|
27
|
+
|
28
|
+
<<<<<<< HEAD
|
29
|
+
ABCJS.write.TripletElem = function(number, anchor1) {
|
30
|
+
this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
|
31
|
+
this.number = number;
|
32
|
+
};
|
33
|
+
|
34
|
+
ABCJS.write.TripletElem.prototype.setCloseAnchor = function(anchor2) {
|
35
|
+
this.anchor2 = anchor2;
|
36
|
+
};
|
37
|
+
|
38
|
+
ABCJS.write.TripletElem.prototype.setUpperAndLowerElements = function(/*positionY*/) {
|
39
|
+
};
|
40
|
+
|
41
|
+
ABCJS.write.TripletElem.prototype.draw = function(renderer) {
|
42
|
+
// TODO end and beginning of line (PER: P.S. I'm not sure this can happen: I think the parser will always specify both the start and end points.)
|
43
|
+
if (this.anchor1 && this.anchor2) {
|
44
|
+
var xTextPos;
|
45
|
+
var yTextPos;
|
46
|
+
var hasBeam = this.anchor1.parent.beam && this.anchor1.parent.beam === this.anchor2.parent.beam;
|
47
|
+
|
48
|
+
if (hasBeam) {
|
49
|
+
// If there is a beam then we don't need to draw anything except the text. The beam could either be above or below.
|
50
|
+
var beam = this.anchor1.parent.beam;
|
51
|
+
var left = beam.isAbove() ? this.anchor1.x + this.anchor1.w : this.anchor1.x;
|
52
|
+
xTextPos = beam.xAtMidpoint(left, this.anchor2.x);
|
53
|
+
yTextPos = beam.heightAtMidpoint(left, this.anchor2.x);
|
54
|
+
yTextPos += beam.isAbove() ? 4 : -4; // This creates some space between the beam and the number.
|
55
|
+
} else {
|
56
|
+
// If there isn't a beam, then we need to draw the bracket and the text. The bracket is always above.
|
57
|
+
// The bracket is never lower than the 'a' line, but is 4 pitches above the first and last notes. If there is
|
58
|
+
// a tall note in the middle, the bracket is horizontal and above the highest note.
|
59
|
+
var startNote = Math.max(this.anchor1.parent.top, 9) + 4;
|
60
|
+
var endNote = Math.max(this.anchor2.parent.top, 9) + 4;
|
61
|
+
// TODO-PER: Do the case where the middle note is really high.
|
62
|
+
xTextPos = this.anchor1.x + (this.anchor2.x + this.anchor2.w - this.anchor1.x) / 2;
|
63
|
+
yTextPos = startNote + (endNote - startNote) / 2;
|
64
|
+
drawBracket(renderer, this.anchor1.x, startNote, this.anchor2.x + this.anchor2.w, endNote);
|
65
|
+
}
|
31
66
|
|
67
|
+
renderer.renderText(xTextPos, renderer.calcY(yTextPos), "" + this.number, 'tripletfont', "triplet", "middle", true);
|
68
|
+
}
|
69
|
+
};
|
70
|
+
|
71
|
+
function drawLine(renderer, l, t, r, b) {
|
72
|
+
var pathString = ABCJS.write.sprintf("M %f %f L %f %f",
|
73
|
+
l, t, r, b);
|
74
|
+
renderer.printPath({path: pathString, stroke: "#000000", 'class': renderer.addClasses('triplet')});
|
75
|
+
}
|
76
|
+
|
77
|
+
function drawBracket(renderer, x1, y1, x2, y2) {
|
78
|
+
y1 = renderer.calcY(y1);
|
79
|
+
y2 = renderer.calcY(y2);
|
80
|
+
var bracketHeight = 5;
|
81
|
+
=======
|
32
82
|
ABCJS.write.TripletElem.prototype.draw = function (renderer, linestartx, lineendx) {
|
33
83
|
// TODO end and beginning of line
|
34
84
|
if (this.anchor1 && this.anchor2) {
|
@@ -55,9 +105,7 @@ ABCJS.write.TripletElem.prototype.draw = function (renderer, linestartx, lineend
|
|
55
105
|
xsum += this.anchor2.w;
|
56
106
|
}
|
57
107
|
|
58
|
-
|
59
|
-
renderer.printText(xsum/2, ypos+ydelta, this.number, "middle", 'triplet').attr({"font-size":"10px", 'font-style': 'italic' });
|
60
|
-
|
108
|
+
renderer.renderText(xsum/2, renderer.calcY(ypos+ydelta), this.number, 'annotationfont', "middle", "triplet"); // TODO-PER: There doesn't seem to be a tripletfont defined.
|
61
109
|
}
|
62
110
|
};
|
63
111
|
|
@@ -76,10 +124,29 @@ ABCJS.write.TripletElem.prototype.drawLine = function (renderer, y) {
|
|
76
124
|
pathString = ABCJS.write.sprintf("M %f %f L %f %f",
|
77
125
|
linestartx, y, (linestartx+lineendx)/2-5, y);
|
78
126
|
renderer.printPath({path:pathString, stroke:"#000000", 'class': renderer.addClasses('triplet')});
|
127
|
+
>>>>>>> origin/master
|
79
128
|
|
129
|
+
// Draw vertical lines at the beginning and end
|
130
|
+
drawLine(renderer, x1, y1, x1, y1 + bracketHeight);
|
131
|
+
drawLine(renderer, x2, y2, x2, y2 + bracketHeight);
|
80
132
|
|
133
|
+
<<<<<<< HEAD
|
134
|
+
// figure out midpoints to draw the broken line.
|
135
|
+
var midX = x1 + (x2-x1)/2;
|
136
|
+
var midY = y1 + (y2-y1)/2;
|
137
|
+
var gapWidth = 8;
|
138
|
+
var slope = (y2 - y1) / (x2 - x1);
|
139
|
+
var leftEndX = midX - gapWidth;
|
140
|
+
var leftEndY = y1 + (leftEndX - x1) * slope;
|
141
|
+
drawLine(renderer, x1, y1, leftEndX, leftEndY);
|
142
|
+
var rightStartX = midX + gapWidth;
|
143
|
+
var rightStartY = y1 + (rightStartX - x1) * slope;
|
144
|
+
drawLine(renderer, rightStartX, rightStartY, x2, y2);
|
145
|
+
}
|
146
|
+
})();
|
147
|
+
=======
|
81
148
|
pathString = ABCJS.write.sprintf("M %f %f L %f %f",
|
82
149
|
(linestartx+lineendx)/2+5, y, lineendx, y);
|
83
150
|
renderer.printPath({path:pathString, stroke:"#000000", 'class': renderer.addClasses('triplet')});
|
151
|
+
>>>>>>> origin/master
|
84
152
|
|
85
|
-
};
|
@@ -30,6 +30,22 @@ ABCJS.write.VoiceElement = function(voicenumber, voicetotal) {
|
|
30
30
|
this.duplicate = false;
|
31
31
|
this.voicenumber = voicenumber; //number of the voice on a given stave (not staffgroup)
|
32
32
|
this.voicetotal = voicetotal;
|
33
|
+
this.bottom = 7;
|
34
|
+
this.top = 7;
|
35
|
+
this.specialY = {
|
36
|
+
tempoHeightAbove: 0,
|
37
|
+
partHeightAbove: 0,
|
38
|
+
volumeHeightAbove: 0,
|
39
|
+
dynamicHeightAbove: 0,
|
40
|
+
endingHeightAbove: 0,
|
41
|
+
chordHeightAbove: 0,
|
42
|
+
lyricHeightAbove: 0,
|
43
|
+
|
44
|
+
lyricHeightBelow: 0,
|
45
|
+
chordHeightBelow: 0,
|
46
|
+
volumeHeightBelow: 0,
|
47
|
+
dynamicHeightBelow: 0
|
48
|
+
};
|
33
49
|
};
|
34
50
|
|
35
51
|
ABCJS.write.VoiceElement.prototype.addChild = function (child) {
|
@@ -45,6 +61,55 @@ ABCJS.write.VoiceElement.prototype.addChild = function (child) {
|
|
45
61
|
}
|
46
62
|
}
|
47
63
|
this.children[this.children.length] = child;
|
64
|
+
this.setRange(child);
|
65
|
+
};
|
66
|
+
|
67
|
+
ABCJS.write.VoiceElement.prototype.setLimit = function(member, child) {
|
68
|
+
// Sometimes we get an absolute element in here and sometimes we get some type of relative element.
|
69
|
+
// If there is a "specialY" element, then assume it is an absolute element. If that doesn't exist, look for the
|
70
|
+
// same members at the top level, because that's where they are in relative elements.
|
71
|
+
var specialY = child.specialY;
|
72
|
+
if (!specialY) specialY = child;
|
73
|
+
if (!specialY[member]) return;
|
74
|
+
if (!this.specialY[member])
|
75
|
+
this.specialY[member] = specialY[member];
|
76
|
+
else
|
77
|
+
this.specialY[member] = Math.max(this.specialY[member], specialY[member]);
|
78
|
+
};
|
79
|
+
|
80
|
+
ABCJS.write.VoiceElement.prototype.adjustRange = function(child) {
|
81
|
+
if (child.bottom !== undefined)
|
82
|
+
this.bottom = Math.min(this.bottom, child.bottom);
|
83
|
+
if (child.top !== undefined)
|
84
|
+
this.top = Math.max(this.top, child.top);
|
85
|
+
};
|
86
|
+
|
87
|
+
ABCJS.write.VoiceElement.prototype.setRange = function(child) {
|
88
|
+
this.adjustRange(child);
|
89
|
+
this.setLimit('tempoHeightAbove', child);
|
90
|
+
this.setLimit('partHeightAbove', child);
|
91
|
+
this.setLimit('volumeHeightAbove', child);
|
92
|
+
this.setLimit('dynamicHeightAbove', child);
|
93
|
+
this.setLimit('endingHeightAbove', child);
|
94
|
+
this.setLimit('chordHeightAbove', child);
|
95
|
+
this.setLimit('lyricHeightAbove', child);
|
96
|
+
this.setLimit('lyricHeightBelow', child);
|
97
|
+
this.setLimit('chordHeightBelow', child);
|
98
|
+
this.setLimit('volumeHeightBelow', child);
|
99
|
+
this.setLimit('dynamicHeightBelow', child);
|
100
|
+
};
|
101
|
+
|
102
|
+
ABCJS.write.VoiceElement.prototype.setUpperAndLowerElements = function(positionY) {
|
103
|
+
var i;
|
104
|
+
for (i = 0; i < this.children.length; i++) {
|
105
|
+
var abselem = this.children[i];
|
106
|
+
abselem.setUpperAndLowerElements(positionY);
|
107
|
+
}
|
108
|
+
for (i = 0; i < this.otherchildren.length; i++) {
|
109
|
+
var abselem = this.otherchildren[i];
|
110
|
+
if (typeof abselem !== 'string')
|
111
|
+
abselem.setUpperAndLowerElements(positionY);
|
112
|
+
}
|
48
113
|
};
|
49
114
|
|
50
115
|
ABCJS.write.VoiceElement.prototype.addOther = function (child) {
|
@@ -52,6 +117,7 @@ ABCJS.write.VoiceElement.prototype.addOther = function (child) {
|
|
52
117
|
this.beams.push(child);
|
53
118
|
} else {
|
54
119
|
this.otherchildren.push(child);
|
120
|
+
this.setRange(child);
|
55
121
|
}
|
56
122
|
};
|
57
123
|
|
@@ -73,7 +139,9 @@ ABCJS.write.VoiceElement.prototype.getDurationIndex = function () {
|
|
73
139
|
|
74
140
|
// number of spacing units expected for next positioning
|
75
141
|
ABCJS.write.VoiceElement.prototype.getSpacingUnits = function () {
|
76
|
-
return
|
142
|
+
return Math.sqrt(this.spacingduration*8);
|
143
|
+
// TODO-PER: On short lines, this would never trigger, so the spacing was wrong. I just changed this line empirically, though, so I don't know if there are other ramifications.
|
144
|
+
//return (this.minx<this.nextx) ? Math.sqrt(this.spacingduration*8) : 0; // we haven't used any spacing units if we end up using minx
|
77
145
|
};
|
78
146
|
|
79
147
|
//
|
@@ -84,7 +152,7 @@ ABCJS.write.VoiceElement.prototype.getNextX = function () {
|
|
84
152
|
ABCJS.write.VoiceElement.prototype.beginLayout = function (startx) {
|
85
153
|
this.i=0;
|
86
154
|
this.durationindex=0;
|
87
|
-
this.ii=this.children.length;
|
155
|
+
//this.ii=this.children.length;
|
88
156
|
this.startx=startx;
|
89
157
|
this.minx=startx; // furthest left to where negatively positioned elements are allowed to go
|
90
158
|
this.nextx=startx; // x position where the next element of this voice should be placed assuming no other voices and no fixed width constraints
|
@@ -102,18 +170,18 @@ ABCJS.write.VoiceElement.prototype.layoutOneItem = function (x, spacing) {
|
|
102
170
|
if (er<child.getExtraWidth()) { // shift right by needed amount
|
103
171
|
x+=child.getExtraWidth()-er;
|
104
172
|
}
|
105
|
-
child.x
|
173
|
+
child.setX(x);
|
106
174
|
|
107
175
|
this.spacingduration = child.duration;
|
108
176
|
//update minx
|
109
177
|
this.minx = x+child.getMinWidth(); // add necessary layout space
|
110
|
-
if (this.i!==this.
|
178
|
+
if (this.i!==this.children.length-1) this.minx+=child.minspacing; // add minimumspacing except on last elem
|
111
179
|
|
112
180
|
this.updateNextX(x, spacing);
|
113
181
|
|
114
182
|
// contribute to staff y position
|
115
|
-
this.staff.
|
116
|
-
this.staff.
|
183
|
+
//this.staff.top = Math.max(child.top,this.staff.top);
|
184
|
+
//this.staff.bottom = Math.min(child.bottom,this.staff.bottom);
|
117
185
|
|
118
186
|
return x; // where we end up having placed the child
|
119
187
|
};
|
@@ -126,13 +194,22 @@ ABCJS.write.VoiceElement.prototype.updateNextX = function (x, spacing) {
|
|
126
194
|
ABCJS.write.VoiceElement.prototype.shiftRight = function (dx) {
|
127
195
|
var child = this.children[this.i];
|
128
196
|
if (!child) return;
|
129
|
-
child.x
|
197
|
+
child.setX(child.x+dx);
|
130
198
|
this.minx+=dx;
|
131
199
|
this.nextx+=dx;
|
132
200
|
};
|
133
201
|
|
134
202
|
ABCJS.write.VoiceElement.prototype.draw = function (renderer, bartop) {
|
135
203
|
var width = this.w-1;
|
204
|
+
<<<<<<< HEAD
|
205
|
+
renderer.staffbottom = this.staff.bottom;
|
206
|
+
//this.barbottom = renderer.calcY(2);
|
207
|
+
|
208
|
+
renderer.measureNumber = null;
|
209
|
+
if (this.header) { // print voice name
|
210
|
+
var textpitch = 14 - (this.voicenumber+1)*(12/(this.voicetotal+1));
|
211
|
+
renderer.renderText(renderer.padding.left, renderer.calcY(textpitch), this.header, 'voicefont', 'staff-extra voice-name', 'start');
|
212
|
+
=======
|
136
213
|
renderer.y = this.staff.y;
|
137
214
|
renderer.staffbottom = this.staff.bottom;
|
138
215
|
this.barbottom = renderer.calcY(2);
|
@@ -142,7 +219,8 @@ ABCJS.write.VoiceElement.prototype.draw = function (renderer, bartop) {
|
|
142
219
|
var textpitch = 12 - (this.voicenumber+1)*(12/(this.voicetotal+1));
|
143
220
|
var headerX = (this.startx-renderer.paddingleft)/2+renderer.paddingleft;
|
144
221
|
headerX = headerX*renderer.scale;
|
145
|
-
renderer.
|
222
|
+
renderer.renderText(headerX, renderer.calcY(textpitch), this.header, 'voicefont', 'staff-extra voice-name');
|
223
|
+
>>>>>>> origin/master
|
146
224
|
}
|
147
225
|
|
148
226
|
for (var i=0, ii=this.children.length; i<ii; i++) {
|
@@ -175,3 +253,17 @@ ABCJS.write.VoiceElement.prototype.draw = function (renderer, bartop) {
|
|
175
253
|
});
|
176
254
|
|
177
255
|
};
|
256
|
+
|
257
|
+
ABCJS.write.VoiceElement.prototype.layoutBeams = function() {
|
258
|
+
for (var i = 0; i < this.beams.length; i++) {
|
259
|
+
if (this.beams[i].layout) {
|
260
|
+
this.beams[i].layout();
|
261
|
+
// The above will change the top and bottom of the abselem children, so see if we need to expand our range.
|
262
|
+
for (var j = 0; j < this.beams[i].elems.length; j++) {
|
263
|
+
this.adjustRange(this.beams[i].elems[j]);
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
this.staff.top = Math.max(this.staff.top, this.top);
|
268
|
+
this.staff.bottom = Math.min(this.staff.bottom, this.bottom);
|
269
|
+
};
|
@@ -54,6 +54,7 @@ ABCJS.write.Printer = function(paper, params) {
|
|
54
54
|
this.usingSvg = (window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? true : false); // Same test Raphael uses
|
55
55
|
if (this.usingSvg && params.add_classes)
|
56
56
|
Raphael._availableAttrs['class'] = "";
|
57
|
+
Raphael._availableAttrs['text-decoration'] = "";
|
57
58
|
};
|
58
59
|
|
59
60
|
ABCJS.write.Printer.prototype.addClasses = function (c) {
|
@@ -190,15 +191,6 @@ ABCJS.write.Printer.prototype.printStem = function (x, dx, y1, y2) {
|
|
190
191
|
}
|
191
192
|
};
|
192
193
|
|
193
|
-
ABCJS.write.Printer.prototype.printText = function (x, offset, text, anchor, extraClass) {
|
194
|
-
anchor = anchor || "start";
|
195
|
-
var ret = this.paper.text(x*this.scale, this.calcY(offset)*this.scale, text).attr({"text-anchor":anchor, "font-size":12*this.scale, 'class': this.addClasses(extraClass)});
|
196
|
-
// if (this.scale!==1) {
|
197
|
-
// ret.scale(this.scale, this.scale, 0, 0);
|
198
|
-
// }
|
199
|
-
return ret;
|
200
|
-
};
|
201
|
-
|
202
194
|
// assumes this.y is set appropriately
|
203
195
|
// if symbol is a multichar string without a . (as in scripts.staccato) 1 symbol per char is assumed
|
204
196
|
// not scaled if not in printgroup
|
@@ -215,7 +207,7 @@ ABCJS.write.Printer.prototype.printSymbol = function(x, offset, symbol, scalex,
|
|
215
207
|
elemset.push(el);
|
216
208
|
dx+=this.glyphs.getSymbolWidth(symbol.charAt(i));
|
217
209
|
} else {
|
218
|
-
this.
|
210
|
+
this.renderText(x, this.y, "no symbol:" +symbol, "debugfont", 'debug-msg', 'start');
|
219
211
|
}
|
220
212
|
}
|
221
213
|
if (this.scale!==1) {
|
@@ -234,7 +226,7 @@ ABCJS.write.Printer.prototype.printSymbol = function(x, offset, symbol, scalex,
|
|
234
226
|
}
|
235
227
|
return el;
|
236
228
|
} else
|
237
|
-
this.
|
229
|
+
this.renderText(x, this.y, "no symbol:" +symbol, "debugfont", 'debug-msg', 'start');
|
238
230
|
}
|
239
231
|
return null;
|
240
232
|
}
|
@@ -281,18 +273,16 @@ ABCJS.write.Printer.prototype.drawArc = function(x1, x2, pitch1, pitch2, above)
|
|
281
273
|
return ret;
|
282
274
|
};
|
283
275
|
|
284
|
-
ABCJS.write.Printer.prototype.
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
};
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
el[0].setAttribute("class", "abc-lyric");
|
295
|
-
return el;
|
276
|
+
ABCJS.write.Printer.prototype.renderText = function(x, y, text, type, klass, anchor) {
|
277
|
+
var font = this.abctune.formatting[type];
|
278
|
+
if (!font)
|
279
|
+
font = { face: "Arial", size: 12, decoration: "underline", style: "normal", weight: "normal" };
|
280
|
+
var attr = {"font-size": font.size*this.scale,
|
281
|
+
"font-family": font.face, 'font-weight': font.weight, 'text-decoration': font.decoration,
|
282
|
+
'class': this.addClasses(klass) };
|
283
|
+
if (anchor)
|
284
|
+
attr["text-anchor"] = anchor;
|
285
|
+
return this.paper.text(x, y*this.scale, text).attr(attr);
|
296
286
|
};
|
297
287
|
|
298
288
|
ABCJS.write.Printer.prototype.calcY = function(ofs) {
|
@@ -328,9 +318,8 @@ ABCJS.write.Printer.prototype.printABC = function(abctunes) {
|
|
328
318
|
};
|
329
319
|
|
330
320
|
ABCJS.write.Printer.prototype.printTempo = function (tempo, paper, layouter, y, printer, x) {
|
331
|
-
var fontStyle = {"text-anchor":"start", 'font-size':12*printer.scale, 'font-weight':'bold', 'class': this.addClasses('tempo')};
|
332
321
|
if (tempo.preString) {
|
333
|
-
var text =
|
322
|
+
var text = this.renderText(x, this.y+20, tempo.preString, 'tempofont', 'tempo',"start");
|
334
323
|
x += (text.getBBox().width + 20*printer.scale);
|
335
324
|
}
|
336
325
|
if (tempo.duration) {
|
@@ -365,11 +354,11 @@ ABCJS.write.Printer.prototype.printTempo = function (tempo, paper, layouter, y,
|
|
365
354
|
abselem.x = x*(1/printer.scale); // TODO-PER: For some reason it scales this element twice, so just compensate.
|
366
355
|
abselem.draw(printer, null);
|
367
356
|
x += (abselem.w + 5*printer.scale);
|
368
|
-
text =
|
357
|
+
text = this.renderText(x, this.y+20, "= " + tempo.bpm, 'tempofont', 'tempo',"start");
|
369
358
|
x += text.getBBox().width + 10*printer.scale;
|
370
359
|
}
|
371
360
|
if (tempo.postString) {
|
372
|
-
|
361
|
+
this.renderText(x, this.y+20, tempo.postString, 'tempofont', 'tempo',"start");
|
373
362
|
}
|
374
363
|
y += 15*printer.scale;
|
375
364
|
return y;
|
@@ -377,6 +366,7 @@ ABCJS.write.Printer.prototype.printTempo = function (tempo, paper, layouter, y,
|
|
377
366
|
|
378
367
|
ABCJS.write.Printer.prototype.printTune = function (abctune) {
|
379
368
|
this.lineNumber = null;
|
369
|
+
this.abctune = abctune;
|
380
370
|
this.measureNumber = null;
|
381
371
|
this.layouter = new ABCJS.write.Layout(this.glyphs, abctune.formatting.bagpipes);
|
382
372
|
this.layouter.printer = this; // TODO-PER: this is a hack to get access, but it tightens the coupling.
|
@@ -395,8 +385,7 @@ ABCJS.write.Printer.prototype.printTune = function (abctune) {
|
|
395
385
|
}
|
396
386
|
else
|
397
387
|
this.y+=this.paddingtop;
|
398
|
-
|
399
|
-
if (abctune.formatting.staffwidth) {
|
388
|
+
if (abctune.formatting.staffwidth) {
|
400
389
|
this.width=abctune.formatting.staffwidth;
|
401
390
|
} else {
|
402
391
|
this.width=this.staffwidth;
|
@@ -404,26 +393,34 @@ ABCJS.write.Printer.prototype.printTune = function (abctune) {
|
|
404
393
|
this.width+=this.paddingleft;
|
405
394
|
if (abctune.formatting.scale) { this.scale=abctune.formatting.scale; }
|
406
395
|
if (abctune.metaText.title)
|
407
|
-
|
396
|
+
this.renderText(this.width/2, this.y, abctune.metaText.title, 'titlefont', 'title meta-top');
|
408
397
|
this.y+=20*this.scale;
|
409
398
|
if (abctune.lines[0] && abctune.lines[0].subtitle) {
|
410
399
|
this.printSubtitleLine(abctune.lines[0]);
|
411
400
|
this.y+=20*this.scale;
|
412
401
|
}
|
413
402
|
if (abctune.metaText.rhythm) {
|
414
|
-
this.
|
415
|
-
!
|
403
|
+
this.renderText(this.paddingleft, this.y, abctune.metaText.rhythm, 'infofont', 'meta-top', "start");
|
404
|
+
if (!abctune.metaText.author && !abctune.metaText.origin && !abctune.metaText.composer)
|
405
|
+
this.y+=15*this.scale;
|
416
406
|
}
|
417
407
|
var composerLine = "";
|
418
408
|
if (abctune.metaText.composer) composerLine += abctune.metaText.composer;
|
419
409
|
if (abctune.metaText.origin) composerLine += ' (' + abctune.metaText.origin + ')';
|
420
|
-
if (composerLine.length > 0) {
|
421
|
-
|
410
|
+
if (composerLine.length > 0) {
|
411
|
+
this.renderText(this.width, this.y, composerLine, 'composerfont', 'meta-top', "end");
|
412
|
+
this.y+=15;
|
413
|
+
}
|
414
|
+
if (abctune.metaText.author) {
|
415
|
+
this.renderText(this.width, this.y, abctune.metaText.author, 'composerfont', 'meta-top', "end");
|
416
|
+
this.y+=15;
|
417
|
+
}
|
422
418
|
if (abctune.metaText.tempo && !abctune.metaText.tempo.suppress) {
|
423
419
|
this.y = this.printTempo(abctune.metaText.tempo, this.paper, this.layouter, this.y, this, 50, -1);
|
424
420
|
this.y += 20*this.scale;
|
425
421
|
}
|
426
422
|
this.staffgroups = [];
|
423
|
+
var text2;
|
427
424
|
var maxwidth = this.width;
|
428
425
|
for(var line=0; line<abctune.lines.length; line++) {
|
429
426
|
this.lineNumber = line;
|
@@ -436,51 +433,50 @@ ABCJS.write.Printer.prototype.printTune = function (abctune) {
|
|
436
433
|
this.y+=20*this.scale; //hardcoded
|
437
434
|
} else if (abcline.text) {
|
438
435
|
if (typeof abcline.text === 'string')
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
436
|
+
text2 = this.renderText(this.paddingleft, this.y, abcline.text, "textfont", 'defined-text', "start");
|
437
|
+
else {
|
438
|
+
var str = "";
|
439
|
+
for (var i = 0; i < abcline.text.length; i++) {
|
440
|
+
str += " FONT " + abcline.text[i].text;
|
441
|
+
}
|
442
|
+
text2 = this.renderText(this.paddingleft, this.y, str, "textfont", 'defined-text', "start");
|
443
|
+
}
|
444
|
+
this.y += text2.getBBox().height + 10 * this.scale;
|
445
|
+
}
|
449
446
|
}
|
450
447
|
this.lineNumber = null;
|
451
448
|
this.measureNumber = null;
|
449
|
+
if (abctune.metaText.partOrder) {
|
450
|
+
text2 = this.renderText(this.paddingleft, this.y, "Part Order: " + abctune.metaText.partOrder, 'partsfont', 'meta-bottom');
|
451
|
+
this.y += text2.getBBox().height + 10 * this.scale;
|
452
|
+
}
|
452
453
|
var extraText = "";
|
453
|
-
var text2;
|
454
|
-
var height;
|
455
|
-
if (abctune.metaText.partOrder) extraText += "Part Order: " + abctune.metaText.partOrder + "\n";
|
456
454
|
if (abctune.metaText.unalignedWords) {
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
}
|
467
|
-
|
468
|
-
|
469
|
-
text2.translate(0,height/2);
|
470
|
-
this.y+=height;
|
455
|
+
for (var j = 0; j < abctune.metaText.unalignedWords.length; j++) {
|
456
|
+
if (typeof abctune.metaText.unalignedWords[j] === 'string')
|
457
|
+
extraText += abctune.metaText.unalignedWords[j] + "\n";
|
458
|
+
else {
|
459
|
+
for (var k = 0; k < abctune.metaText.unalignedWords[j].length; k++) {
|
460
|
+
extraText += " FONT " + abctune.metaText.unalignedWords[j][k].text;
|
461
|
+
}
|
462
|
+
extraText += "\n";
|
463
|
+
}
|
464
|
+
}
|
465
|
+
text2 = this.renderText(this.paddingleft + 50, this.y, extraText, 'wordsfont', 'meta-bottom', "start");
|
466
|
+
this.y += text2.getBBox().height + 10 * this.scale;
|
471
467
|
extraText = "";
|
472
|
-
|
468
|
+
}
|
473
469
|
if (abctune.metaText.book) extraText += "Book: " + abctune.metaText.book + "\n";
|
474
470
|
if (abctune.metaText.source) extraText += "Source: " + abctune.metaText.source + "\n";
|
475
471
|
if (abctune.metaText.discography) extraText += "Discography: " + abctune.metaText.discography + "\n";
|
476
472
|
if (abctune.metaText.notes) extraText += "Notes: " + abctune.metaText.notes + "\n";
|
477
473
|
if (abctune.metaText.transcription) extraText += "Transcription: " + abctune.metaText.transcription + "\n";
|
478
474
|
if (abctune.metaText.history) extraText += "History: " + abctune.metaText.history + "\n";
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
475
|
+
if (abctune.metaText['abc-copyright']) extraText += "Copyright: " + abctune.metaText['abc-copyright'] + "\n";
|
476
|
+
if (abctune.metaText['abc-creator']) extraText += "Creator: " + abctune.metaText['abc-creator'] + "\n";
|
477
|
+
if (abctune.metaText['abc-edited-by']) extraText += "Edited By: " + abctune.metaText['abc-edited-by'] + "\n";
|
478
|
+
text2 = this.renderText(this.paddingleft, this.y, extraText, 'historyfont', 'meta-bottom', "start");
|
479
|
+
this.y += text2.getBBox().height + 10 * this.scale;
|
484
480
|
var sizetoset = {w: (maxwidth+this.paddingright)*this.scale,h: (this.y+this.paddingbottom)*this.scale};
|
485
481
|
this.paper.setSize(sizetoset.w,sizetoset.h);
|
486
482
|
// Correct for IE problem in calculating height
|
@@ -493,7 +489,7 @@ ABCJS.write.Printer.prototype.printTune = function (abctune) {
|
|
493
489
|
};
|
494
490
|
|
495
491
|
ABCJS.write.Printer.prototype.printSubtitleLine = function(abcline) {
|
496
|
-
|
492
|
+
this.renderText(this.width/2, this.y, abcline.subtitle, "subtitlefont", 'text meta-top');
|
497
493
|
};
|
498
494
|
|
499
495
|
function centerWholeRests(voices) {
|