UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature

1,096 lines (713 loc) 37.2 kB
<!DOCTYPE html> <html> <head> <title>staveline.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="public/stylesheets/normalize.css" /> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div class="container"> <div class="page"> <div class="header"> <h1>staveline.js</h1> <div class="toc"> <h3>Table of Contents</h3> <ol> <li> <a class="source" href="accidental.html"> accidental.js </a> </li> <li> <a class="source" href="annotation.html"> annotation.js </a> </li> <li> <a class="source" href="articulation.html"> articulation.js </a> </li> <li> <a class="source" href="barnote.html"> barnote.js </a> </li> <li> <a class="source" href="beam.html"> beam.js </a> </li> <li> <a class="source" href="bend.html"> bend.js </a> </li> <li> <a class="source" href="boundingbox.html"> boundingbox.js </a> </li> <li> <a class="source" href="boundingboxcomputation.html"> boundingboxcomputation.js </a> </li> <li> <a class="source" href="canvascontext.html"> canvascontext.js </a> </li> <li> <a class="source" href="clef.html"> clef.js </a> </li> <li> <a class="source" href="clefnote.html"> clefnote.js </a> </li> <li> <a class="source" href="crescendo.html"> crescendo.js </a> </li> <li> <a class="source" href="curve.html"> curve.js </a> </li> <li> <a class="source" href="dot.html"> dot.js </a> </li> <li> <a class="source" href="easyscore.html"> easyscore.js </a> </li> <li> <a class="source" href="element.html"> element.js </a> </li> <li> <a class="source" href="factory.html"> factory.js </a> </li> <li> <a class="source" href="formatter.html"> formatter.js </a> </li> <li> <a class="source" href="fraction.html"> fraction.js </a> </li> <li> <a class="source" href="frethandfinger.html"> frethandfinger.js </a> </li> <li> <a class="source" href="ghostnote.html"> ghostnote.js </a> </li> <li> <a class="source" href="glyph.html"> glyph.js </a> </li> <li> <a class="source" href="glyphnote.html"> glyphnote.js </a> </li> <li> <a class="source" href="gracenote.html"> gracenote.js </a> </li> <li> <a class="source" href="gracenotegroup.html"> gracenotegroup.js </a> </li> <li> <a class="source" href="gracetabnote.html"> gracetabnote.js </a> </li> <li> <a class="source" href="index.html"> index.js </a> </li> <li> <a class="source" href="keymanager.html"> keymanager.js </a> </li> <li> <a class="source" href="keysignature.html"> keysignature.js </a> </li> <li> <a class="source" href="keysignote.html"> keysignote.js </a> </li> <li> <a class="source" href="modifier.html"> modifier.js </a> </li> <li> <a class="source" href="modifiercontext.html"> modifiercontext.js </a> </li> <li> <a class="source" href="multimeasurerest.html"> multimeasurerest.js </a> </li> <li> <a class="source" href="music.html"> music.js </a> </li> <li> <a class="source" href="note.html"> note.js </a> </li> <li> <a class="source" href="notehead.html"> notehead.js </a> </li> <li> <a class="source" href="notesubgroup.html"> notesubgroup.js </a> </li> <li> <a class="source" href="ornament.html"> ornament.js </a> </li> <li> <a class="source" href="parser.html"> parser.js </a> </li> <li> <a class="source" href="pedalmarking.html"> pedalmarking.js </a> </li> <li> <a class="source" href="raphaelcontext.html"> raphaelcontext.js </a> </li> <li> <a class="source" href="registry.html"> registry.js </a> </li> <li> <a class="source" href="renderer.html"> renderer.js </a> </li> <li> <a class="source" href="repeatnote.html"> repeatnote.js </a> </li> <li> <a class="source" href="smufl.html"> smufl.js </a> </li> <li> <a class="source" href="stave.html"> stave.js </a> </li> <li> <a class="source" href="stavebarline.html"> stavebarline.js </a> </li> <li> <a class="source" href="staveconnector.html"> staveconnector.js </a> </li> <li> <a class="source" href="stavehairpin.html"> stavehairpin.js </a> </li> <li> <a class="source" href="staveline.html"> staveline.js </a> </li> <li> <a class="source" href="stavemodifier.html"> stavemodifier.js </a> </li> <li> <a class="source" href="stavenote.html"> stavenote.js </a> </li> <li> <a class="source" href="staverepetition.html"> staverepetition.js </a> </li> <li> <a class="source" href="stavesection.html"> stavesection.js </a> </li> <li> <a class="source" href="stavetempo.html"> stavetempo.js </a> </li> <li> <a class="source" href="stavetext.html"> stavetext.js </a> </li> <li> <a class="source" href="stavetie.html"> stavetie.js </a> </li> <li> <a class="source" href="stavevolta.html"> stavevolta.js </a> </li> <li> <a class="source" href="stem.html"> stem.js </a> </li> <li> <a class="source" href="stemmablenote.html"> stemmablenote.js </a> </li> <li> <a class="source" href="stringnumber.html"> stringnumber.js </a> </li> <li> <a class="source" href="strokes.html"> strokes.js </a> </li> <li> <a class="source" href="svgcontext.html"> svgcontext.js </a> </li> <li> <a class="source" href="system.html"> system.js </a> </li> <li> <a class="source" href="tables.html"> tables.js </a> </li> <li> <a class="source" href="tabnote.html"> tabnote.js </a> </li> <li> <a class="source" href="tabslide.html"> tabslide.js </a> </li> <li> <a class="source" href="tabstave.html"> tabstave.js </a> </li> <li> <a class="source" href="tabtie.html"> tabtie.js </a> </li> <li> <a class="source" href="textbracket.html"> textbracket.js </a> </li> <li> <a class="source" href="textdynamics.html"> textdynamics.js </a> </li> <li> <a class="source" href="textnote.html"> textnote.js </a> </li> <li> <a class="source" href="tickable.html"> tickable.js </a> </li> <li> <a class="source" href="tickcontext.html"> tickcontext.js </a> </li> <li> <a class="source" href="timesignature.html"> timesignature.js </a> </li> <li> <a class="source" href="timesignote.html"> timesignote.js </a> </li> <li> <a class="source" href="tremolo.html"> tremolo.js </a> </li> <li> <a class="source" href="tuning.html"> tuning.js </a> </li> <li> <a class="source" href="tuplet.html"> tuplet.js </a> </li> <li> <a class="source" href="vex.html"> vex.js </a> </li> <li> <a class="source" href="vibrato.html"> vibrato.js </a> </li> <li> <a class="source" href="vibratobracket.html"> vibratobracket.js </a> </li> <li> <a class="source" href="voice.html"> voice.js </a> </li> <li> <a class="source" href="voicegroup.html"> voicegroup.js </a> </li> </ol> </div> </div> <p><a href="http://vexflow.com">VexFlow</a> - Copyright (c) Mohit Muthanna 2010.</p> <h2 id="description">Description</h2> <p>This file implements <code>StaveLine</code> which are simply lines that connect two notes. This object is highly configurable, see the <code>render_options</code>. A simple line is often used for notating glissando articulations, but you can format a <code>StaveLine</code> with arrows or colors for more pedagogical purposes, such as diagrams.</p> <div class='highlight'><pre><span class="hljs-keyword">import</span> { Vex } <span class="hljs-keyword">from</span> <span class="hljs-string">'./vex'</span>; <span class="hljs-keyword">import</span> { Element } <span class="hljs-keyword">from</span> <span class="hljs-string">'./element'</span>; <span class="hljs-keyword">import</span> { Flow } <span class="hljs-keyword">from</span> <span class="hljs-string">'./tables'</span>;</pre></div> <p>Attribution: Arrow rendering implementations based off of Patrick Horgan’s article, “Drawing lines and arcs with arrow heads on HTML5 Canvas”</p> <p>Draw an arrow head that connects between 3 coordinates</p> <div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawArrowHead</span>(<span class="hljs-params">ctx, x0, y0, x1, y1, x2, y2</span>) </span>{</pre></div> <p>all cases do this.</p> <div class='highlight'><pre> ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x0, y0); ctx.closePath(); ctx.fill(); }</pre></div> <p>Helper function to draw a line with arrow heads</p> <div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawArrowLine</span>(<span class="hljs-params">ctx, point1, point2, config</span>) </span>{ <span class="hljs-keyword">const</span> both_arrows = config.draw_start_arrow &amp;&amp; config.draw_end_arrow; <span class="hljs-keyword">const</span> x1 = point1.x; <span class="hljs-keyword">const</span> y1 = point1.y; <span class="hljs-keyword">const</span> x2 = point2.x; <span class="hljs-keyword">const</span> y2 = point2.y;</pre></div> <p>For ends with arrow we actually want to stop before we get to the arrow so that wide lines won’t put a flat end on the arrow.</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> distance = <span class="hljs-built_in">Math</span>.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); <span class="hljs-keyword">const</span> ratio = (distance - config.arrowhead_length / <span class="hljs-number">3</span>) / distance; <span class="hljs-keyword">let</span> end_x; <span class="hljs-keyword">let</span> end_y; <span class="hljs-keyword">let</span> start_x; <span class="hljs-keyword">let</span> start_y; <span class="hljs-keyword">if</span> (config.draw_end_arrow || both_arrows) { end_x = <span class="hljs-built_in">Math</span>.round(x1 + (x2 - x1) * ratio); end_y = <span class="hljs-built_in">Math</span>.round(y1 + (y2 - y1) * ratio); } <span class="hljs-keyword">else</span> { end_x = x2; end_y = y2; } <span class="hljs-keyword">if</span> (config.draw_start_arrow || both_arrows) { start_x = x1 + (x2 - x1) * (<span class="hljs-number">1</span> - ratio); start_y = y1 + (y2 - y1) * (<span class="hljs-number">1</span> - ratio); } <span class="hljs-keyword">else</span> { start_x = x1; start_y = y1; } <span class="hljs-keyword">if</span> (config.color) { ctx.setStrokeStyle(config.color); ctx.setFillStyle(config.color); }</pre></div> <p>Draw the shaft of the arrow</p> <div class='highlight'><pre> ctx.beginPath(); ctx.moveTo(start_x, start_y); ctx.lineTo(end_x, end_y); ctx.stroke(); ctx.closePath();</pre></div> <p>calculate the angle of the line</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> line_angle = <span class="hljs-built_in">Math</span>.atan2(y2 - y1, x2 - x1);</pre></div> <p>h is the line length of a side of the arrow head</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> h = <span class="hljs-built_in">Math</span>.abs(config.arrowhead_length / <span class="hljs-built_in">Math</span>.cos(config.arrowhead_angle)); <span class="hljs-keyword">let</span> angle1; <span class="hljs-keyword">let</span> angle2; <span class="hljs-keyword">let</span> top_x; <span class="hljs-keyword">let</span> top_y; <span class="hljs-keyword">let</span> bottom_x; <span class="hljs-keyword">let</span> bottom_y; <span class="hljs-keyword">if</span> (config.draw_end_arrow || both_arrows) { angle1 = line_angle + <span class="hljs-built_in">Math</span>.PI + config.arrowhead_angle; top_x = x2 + <span class="hljs-built_in">Math</span>.cos(angle1) * h; top_y = y2 + <span class="hljs-built_in">Math</span>.sin(angle1) * h; angle2 = line_angle + <span class="hljs-built_in">Math</span>.PI - config.arrowhead_angle; bottom_x = x2 + <span class="hljs-built_in">Math</span>.cos(angle2) * h; bottom_y = y2 + <span class="hljs-built_in">Math</span>.sin(angle2) * h; drawArrowHead(ctx, top_x, top_y, x2, y2, bottom_x, bottom_y); } <span class="hljs-keyword">if</span> (config.draw_start_arrow || both_arrows) { angle1 = line_angle + config.arrowhead_angle; top_x = x1 + <span class="hljs-built_in">Math</span>.cos(angle1) * h; top_y = y1 + <span class="hljs-built_in">Math</span>.sin(angle1) * h; angle2 = line_angle - config.arrowhead_angle; bottom_x = x1 + <span class="hljs-built_in">Math</span>.cos(angle2) * h; bottom_y = y1 + <span class="hljs-built_in">Math</span>.sin(angle2) * h; drawArrowHead(ctx, top_x, top_y, x1, y1, bottom_x, bottom_y); } } <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StaveLine</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Element</span> </span>{</pre></div> <p>Text Positioning</p> <div class='highlight'><pre> <span class="hljs-keyword">static</span> get TextVerticalPosition() { <span class="hljs-keyword">return</span> { <span class="hljs-attr">TOP</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">BOTTOM</span>: <span class="hljs-number">2</span>, }; } <span class="hljs-keyword">static</span> get TextJustification() { <span class="hljs-keyword">return</span> { <span class="hljs-attr">LEFT</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">CENTER</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">RIGHT</span>: <span class="hljs-number">3</span>, }; }</pre></div> <p>Initialize the StaveLine with the given <code>notes</code>.</p> <p><code>notes</code> is a struct that has:</p> <pre><code> { <span class="hljs-attr">first_note</span>: Note, <span class="hljs-attr">last_note</span>: Note, <span class="hljs-attr">first_indices</span>: [n1, n2, n3], <span class="hljs-attr">last_indices</span>: [n1, n2, n3] }</code></pre> <div class='highlight'><pre> <span class="hljs-keyword">constructor</span>(notes) { <span class="hljs-keyword">super</span>(); <span class="hljs-keyword">this</span>.setAttribute(<span class="hljs-string">'type'</span>, <span class="hljs-string">'StaveLine'</span>); <span class="hljs-keyword">this</span>.notes = notes; <span class="hljs-keyword">this</span>.text = <span class="hljs-string">''</span>; <span class="hljs-keyword">this</span>.font = { <span class="hljs-attr">family</span>: <span class="hljs-string">'Arial'</span>, <span class="hljs-attr">size</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">weight</span>: <span class="hljs-string">''</span>, }; <span class="hljs-keyword">this</span>.render_options = {</pre></div> <p>Space to add to the left or the right</p> <div class='highlight'><pre> padding_left: <span class="hljs-number">4</span>, <span class="hljs-attr">padding_right</span>: <span class="hljs-number">3</span>,</pre></div> <p>The width of the line in pixels</p> <div class='highlight'><pre> line_width: <span class="hljs-number">1</span>,</pre></div> <p>An array of line/space lengths. Unsupported with Raphael (SVG)</p> <div class='highlight'><pre> line_dash: <span class="hljs-literal">null</span>,</pre></div> <p>Can draw rounded line end, instead of a square. Unsupported with Raphael (SVG)</p> <div class='highlight'><pre> rounded_end: <span class="hljs-literal">true</span>,</pre></div> <p>The color of the line and arrowheads</p> <div class='highlight'><pre> color: <span class="hljs-literal">null</span>,</pre></div> <p>Flags to draw arrows on each end of the line</p> <div class='highlight'><pre> draw_start_arrow: <span class="hljs-literal">false</span>, <span class="hljs-attr">draw_end_arrow</span>: <span class="hljs-literal">false</span>,</pre></div> <p>The length of the arrowhead sides</p> <div class='highlight'><pre> arrowhead_length: <span class="hljs-number">10</span>,</pre></div> <p>The angle of the arrowhead</p> <div class='highlight'><pre> arrowhead_angle: <span class="hljs-built_in">Math</span>.PI / <span class="hljs-number">8</span>,</pre></div> <p>The position of the text</p> <div class='highlight'><pre> text_position_vertical: StaveLine.TextVerticalPosition.TOP, <span class="hljs-attr">text_justification</span>: StaveLine.TextJustification.CENTER, }; <span class="hljs-keyword">this</span>.setNotes(notes); }</pre></div> <p>Set the font for the <code>StaveLine</code> text</p> <div class='highlight'><pre> setFont(font) { <span class="hljs-keyword">this</span>.font = font; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div> <p>The the annotation for the <code>StaveLine</code></p> <div class='highlight'><pre> setText(text) { <span class="hljs-keyword">this</span>.text = text; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div> <p>Set the notes for the <code>StaveLine</code></p> <div class='highlight'><pre> setNotes(notes) { <span class="hljs-keyword">if</span> (!notes.first_note &amp;&amp; !notes.last_note) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RuntimeError( <span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Notes needs to have either first_note or last_note set.'</span> ); } <span class="hljs-keyword">if</span> (!notes.first_indices) notes.first_indices = [<span class="hljs-number">0</span>]; <span class="hljs-keyword">if</span> (!notes.last_indices) notes.last_indices = [<span class="hljs-number">0</span>]; <span class="hljs-keyword">if</span> (notes.first_indices.length !== notes.last_indices.length) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RuntimeError( <span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Connected notes must have similar index sizes'</span> ); }</pre></div> <p>Success. Lets grab ‘em notes.</p> <div class='highlight'><pre> <span class="hljs-keyword">this</span>.first_note = notes.first_note; <span class="hljs-keyword">this</span>.first_indices = notes.first_indices; <span class="hljs-keyword">this</span>.last_note = notes.last_note; <span class="hljs-keyword">this</span>.last_indices = notes.last_indices; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div> <p>Apply the style of the <code>StaveLine</code> to the context</p> <div class='highlight'><pre> applyLineStyle() { <span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.checkContext(); <span class="hljs-keyword">const</span> render_options = <span class="hljs-keyword">this</span>.render_options; <span class="hljs-keyword">if</span> (render_options.line_dash) { ctx.setLineDash(render_options.line_dash); } <span class="hljs-keyword">if</span> (render_options.line_width) { ctx.setLineWidth(render_options.line_width); } <span class="hljs-keyword">if</span> (render_options.rounded_end) { ctx.setLineCap(<span class="hljs-string">'round'</span>); } <span class="hljs-keyword">else</span> { ctx.setLineCap(<span class="hljs-string">'square'</span>); } }</pre></div> <p>Apply the text styling to the context</p> <div class='highlight'><pre> applyFontStyle() { <span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.checkContext(); <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.font) { ctx.setFont(<span class="hljs-keyword">this</span>.font.family, <span class="hljs-keyword">this</span>.font.size, <span class="hljs-keyword">this</span>.font.weight); } <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.render_options.color) { ctx.setStrokeStyle(<span class="hljs-keyword">this</span>.render_options.color); ctx.setFillStyle(<span class="hljs-keyword">this</span>.render_options.color); } }</pre></div> <p>Renders the <code>StaveLine</code> on the context</p> <div class='highlight'><pre> draw() { <span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.checkContext(); <span class="hljs-keyword">this</span>.setRendered(); <span class="hljs-keyword">const</span> first_note = <span class="hljs-keyword">this</span>.first_note; <span class="hljs-keyword">const</span> last_note = <span class="hljs-keyword">this</span>.last_note; <span class="hljs-keyword">const</span> render_options = <span class="hljs-keyword">this</span>.render_options; ctx.save(); <span class="hljs-keyword">this</span>.applyLineStyle();</pre></div> <p>Cycle through each set of indices and draw lines</p> <div class='highlight'><pre> <span class="hljs-keyword">let</span> start_position; <span class="hljs-keyword">let</span> end_position; <span class="hljs-keyword">this</span>.first_indices.forEach(<span class="hljs-function">(<span class="hljs-params">first_index, i</span>) =&gt;</span> { <span class="hljs-keyword">const</span> last_index = <span class="hljs-keyword">this</span>.last_indices[i];</pre></div> <p>Get initial coordinates for the start/end of the line</p> <div class='highlight'><pre> start_position = first_note.getModifierStartXY(<span class="hljs-number">2</span>, first_index); end_position = last_note.getModifierStartXY(<span class="hljs-number">1</span>, last_index); <span class="hljs-keyword">const</span> upwards_slope = start_position.y &gt; end_position.y;</pre></div> <p>Adjust <code>x</code> coordinates for modifiers</p> <div class='highlight'><pre> start_position.x += first_note.getMetrics().modRightPx + render_options.padding_left; end_position.x -= last_note.getMetrics().modLeftPx + render_options.padding_right;</pre></div> <p>Adjust first <code>x</code> coordinates for displacements</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> notehead_width = first_note.getGlyph().getWidth(); <span class="hljs-keyword">const</span> first_displaced = first_note.getKeyProps()[first_index].displaced; <span class="hljs-keyword">if</span> (first_displaced &amp;&amp; first_note.getStemDirection() === <span class="hljs-number">1</span>) { start_position.x += notehead_width + render_options.padding_left; }</pre></div> <p>Adjust last <code>x</code> coordinates for displacements</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> last_displaced = last_note.getKeyProps()[last_index].displaced; <span class="hljs-keyword">if</span> (last_displaced &amp;&amp; last_note.getStemDirection() === <span class="hljs-number">-1</span>) { end_position.x -= notehead_width + render_options.padding_right; }</pre></div> <p>Adjust y position better if it’s not coming from the center of the note</p> <div class='highlight'><pre> start_position.y += upwards_slope ? <span class="hljs-number">-3</span> : <span class="hljs-number">1</span>; end_position.y += upwards_slope ? <span class="hljs-number">2</span> : <span class="hljs-number">0</span>; drawArrowLine(ctx, start_position, end_position, <span class="hljs-keyword">this</span>.render_options); }); ctx.restore();</pre></div> <p>Determine the x coordinate where to start the text</p> <div class='highlight'><pre> <span class="hljs-keyword">const</span> text_width = ctx.measureText(<span class="hljs-keyword">this</span>.text).width; <span class="hljs-keyword">const</span> justification = render_options.text_justification; <span class="hljs-keyword">let</span> x = <span class="hljs-number">0</span>; <span class="hljs-keyword">if</span> (justification === StaveLine.TextJustification.LEFT) { x = start_position.x; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (justification === StaveLine.TextJustification.CENTER) { <span class="hljs-keyword">const</span> delta_x = (end_position.x - start_position.x); <span class="hljs-keyword">const</span> center_x = (delta_x / <span class="hljs-number">2</span>) + start_position.x; x = center_x - (text_width / <span class="hljs-number">2</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (justification === StaveLine.TextJustification.RIGHT) { x = end_position.x - text_width; }</pre></div> <p>Determine the y value to start the text</p> <div class='highlight'><pre> <span class="hljs-keyword">let</span> y; <span class="hljs-keyword">const</span> vertical_position = render_options.text_position_vertical; <span class="hljs-keyword">if</span> (vertical_position === StaveLine.TextVerticalPosition.TOP) { y = first_note.getStave().getYForTopText(); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (vertical_position === StaveLine.TextVerticalPosition.BOTTOM) { y = first_note.getStave().getYForBottomText(Flow.TEXT_HEIGHT_OFFSET_HACK); }</pre></div> <p>Draw the text</p> <div class='highlight'><pre> ctx.save(); <span class="hljs-keyword">this</span>.applyFontStyle(); ctx.fillText(<span class="hljs-keyword">this</span>.text, x, y); ctx.restore(); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; } }</pre></div> <div class="fleur">h</div> </div> </div> </body> </html>