forked from 0xfe/vexflow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtabnote.js
179 lines (149 loc) · 5.28 KB
/
tabnote.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Vex Flow Notation
// Mohit Muthanna <[email protected]>
//
// Copyright Mohit Muthanna 2010
//
// Requires vex.js.
/** @constructor */
Vex.Flow.TabNote = function(tab_struct) {
if (arguments.length > 0) this.init(tab_struct);
}
Vex.Flow.TabNote.prototype = new Vex.Flow.Note();
Vex.Flow.TabNote.superclass = Vex.Flow.Note.prototype;
Vex.Flow.TabNote.constructor = Vex.Flow.TabNote;
Vex.Flow.TabNote.prototype.init = function(tab_struct) {
var superclass = Vex.Flow.TabNote.superclass;
superclass.init.call(this, tab_struct);
// Note properties
this.positions = tab_struct.positions; // [{ str: X, fret: X }]
this.modifiers = [];
this.render_options = {
glyph_font_scale: 30 // font size for note heads and rests
}
this.noteGlyph =
Vex.Flow.durationToGlyph(this.duration, this.noteType);
if (!this.noteGlyph) {
throw new Vex.RuntimeError("BadArguments",
"Invalid note initialization data (No glyph found): " +
JSON.stringify(tab_struct));
}
this.glyphs = [];
this.width = 0;
for (var i = 0; i < this.positions.length; ++i) {
var fret = this.positions[i].fret;
var glyph = Vex.Flow.tabToGlyph(fret);
this.glyphs.push(glyph);
this.width = (glyph.width > this.width) ? glyph.width : this.width;
}
}
Vex.Flow.TabNote.prototype.setStave = function(stave) {
var superclass = Vex.Flow.TabNote.superclass;
superclass.setStave.call(this, stave);
this.context = stave.context;
this.width = 0;
// Calculate the fret number width based on font used
if (this.context) {
for (var i = 0; i < this.glyphs.length; ++i) {
var text = "" + this.glyphs[i].text;
if (text.toUpperCase() != "X")
this.glyphs[i].width = this.context.measureText(text).width;
this.width = (this.glyphs[i].width > this.width) ?
this.glyphs[i].width : this.width;
}
}
var ys = [];
// Setup y coordinates for score.
for (var i = 0; i < this.positions.length; ++i) {
var line = this.positions[i].str;
ys.push(this.stave.getYForLine(line - 1));
}
return this.setYs(ys);
}
// Get the Tab Positions for each note in chord
Vex.Flow.TabNote.prototype.getPositions = function() {
return this.positions;
}
Vex.Flow.TabNote.prototype.addToModifierContext = function(mc) {
this.setModifierContext(mc);
for (var i = 0; i < this.modifiers.length; ++i) {
this.modifierContext.addModifier(this.modifiers[i]);
}
this.preFormatted = false;
return this;
}
Vex.Flow.TabNote.prototype.addModifier = function(modifier, index) {
modifier.setNote(this);
modifier.setIndex(index || 0);
this.modifiers.push(modifier);
this.setPreFormatted(false);
return this;
}
Vex.Flow.TabNote.prototype.getTieRightX = function() {
var tieStartX = this.getAbsoluteX();
var note_glyph_width = this.noteGlyph.head_width;
tieStartX += (note_glyph_width / 2);
tieStartX += ((-this.width / 2) + this.width + 2);
return tieStartX;
}
Vex.Flow.TabNote.prototype.getTieLeftX = function() {
var tieEndX = this.getAbsoluteX();
var note_glyph_width = this.noteGlyph.head_width;
tieEndX += (note_glyph_width / 2);
tieEndX -= ((this.width / 2) + 2);
return tieEndX;
}
Vex.Flow.TabNote.prototype.getModifierStartXY = function(position, index) {
if (!this.preFormatted) throw new Vex.RERR("UnformattedNote",
"Can't call GetModifierStartXY on an unformatted note");
if (this.ys.length == 0) throw new Vex.RERR("NoYValues",
"No Y-Values calculated for this note.");
var x = 0;
if (position == Vex.Flow.Modifier.Position.LEFT) {
x = -1 * 2; // extra_left_px
} else if (position == Vex.Flow.Modifier.Position.RIGHT) {
x = this.width + 2; // extra_right_px
} else if (position == Vex.Flow.Modifier.Position.BELOW ||
position == Vex.Flow.Modifier.Position.ABOVE) {
var note_glyph_width = this.noteGlyph.head_width;
x = note_glyph_width / 2;
}
return {x: this.getAbsoluteX() + x, y: this.ys[index]};
}
// Pre-render formatting
Vex.Flow.TabNote.prototype.preFormat = function() {
if (this.preFormatted) return;
if (this.modifierContext) this.modifierContext.preFormat();
// width is already set during init()
this.setPreFormatted(true);
}
Vex.Flow.TabNote.prototype.draw = function() {
if (!this.context) throw new Vex.RERR("NoCanvasContext",
"Can't draw without a canvas context.");
if (!this.stave) throw new Vex.RERR("NoStave", "Can't draw without a stave.");
if (this.ys.length == 0) throw new Vex.RERR("NoYValues",
"Can't draw note without Y values.");
var ctx = this.context;
var x = this.getAbsoluteX();
var ys = this.ys;
for (var i = 0; i < this.positions.length; ++i) {
var y = ys[i];
var glyph = this.glyphs[i];
// Center the fret text beneath the notation note head
var note_glyph_width = this.noteGlyph.head_width;
var tab_x = x + (note_glyph_width / 2) - (glyph.width / 2);
ctx.clearRect(tab_x - 2, y - 3, glyph.width + 4, 6);
if (glyph.code) {
Vex.Flow.renderGlyph(ctx, tab_x, y + 5 + glyph.shift_y,
this.render_options.glyph_font_scale, glyph.code);
} else {
var text = glyph.text.toString();
ctx.fillText(text, tab_x, y + 5);
}
}
// Draw the modifiers
for (var i = 0; i < this.modifiers.length; ++i) {
var modifier = this.modifiers[i];
modifier.setContext(this.context);
modifier.draw();
}
}