UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature

2,211 lines 95.6 kB
<!DOCTYPE html>

<html>
<head>
  <title>stavenote.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>stavenote.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="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="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 notes for standard notation. This consists of one or
more <code>NoteHeads</code>, an optional stem, and an optional flag.</p>
<p><em>Throughout these comments, a “note” refers to the entire <code>StaveNote</code>,
and a “key” refers to a specific pitch/notehead within a note.</em></p>
<p>See <code>tests/stavenote_tests.js</code> for usage examples.</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> { Flow } <span class="hljs-keyword">from</span> <span class="hljs-string">'./tables'</span>;
<span class="hljs-keyword">import</span> { BoundingBox } <span class="hljs-keyword">from</span> <span class="hljs-string">'./boundingbox'</span>;
<span class="hljs-keyword">import</span> { Stem } <span class="hljs-keyword">from</span> <span class="hljs-string">'./stem'</span>;
<span class="hljs-keyword">import</span> { NoteHead } <span class="hljs-keyword">from</span> <span class="hljs-string">'./notehead'</span>;
<span class="hljs-keyword">import</span> { StemmableNote } <span class="hljs-keyword">from</span> <span class="hljs-string">'./stemmablenote'</span>;
<span class="hljs-keyword">import</span> { Modifier } <span class="hljs-keyword">from</span> <span class="hljs-string">'./modifier'</span>;
<span class="hljs-keyword">import</span> { Dot } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dot'</span>;</pre></div>
        
      
        
        <p>To enable logging for this class. Set <code>Vex.Flow.StaveNote.DEBUG</code> to <code>true</code>.</p>

        
          <div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">L</span>(<span class="hljs-params">...args</span>) </span>{ <span class="hljs-keyword">if</span> (StaveNote.DEBUG) Vex.L(<span class="hljs-string">'Vex.Flow.StaveNote'</span>, args); }

<span class="hljs-keyword">const</span> getStemAdjustment = <span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> Stem.WIDTH / (<span class="hljs-number">2</span> * -note.getStemDirection());

<span class="hljs-keyword">const</span> isInnerNoteIndex = <span class="hljs-function">(<span class="hljs-params">note, index</span>) =&gt;</span>
  index === (note.getStemDirection() === Stem.UP ? note.keyProps.length - <span class="hljs-number">1</span> : <span class="hljs-number">0</span>);</pre></div>
        
      
        
        <p>Helper methods for rest positioning in ModifierContext.</p>

        
          <div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shiftRestVertical</span>(<span class="hljs-params">rest, note, dir</span>) </span>{
  <span class="hljs-keyword">const</span> delta = (note.isrest ? <span class="hljs-number">0.0</span> : <span class="hljs-number">1.0</span>) * dir;

  rest.line += delta;
  rest.maxLine += delta;
  rest.minLine += delta;
  rest.note.setKeyLine(<span class="hljs-number">0</span>, rest.note.getKeyLine(<span class="hljs-number">0</span>) + (delta));
}</pre></div>
        
      
        
        <p>Called from formatNotes :: center a rest between two notes</p>

        
          <div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">centerRest</span>(<span class="hljs-params">rest, noteU, noteL</span>) </span>{
  <span class="hljs-keyword">const</span> delta = rest.line - Vex.MidLine(noteU.minLine, noteL.maxLine);
  rest.note.setKeyLine(<span class="hljs-number">0</span>, rest.note.getKeyLine(<span class="hljs-number">0</span>) - delta);
  rest.line -= delta;
  rest.maxLine -= delta;
  rest.minLine -= delta;
}

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StaveNote</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StemmableNote</span> </span>{
  <span class="hljs-keyword">static</span> get CATEGORY() { <span class="hljs-keyword">return</span> <span class="hljs-string">'stavenotes'</span>; }
  <span class="hljs-keyword">static</span> get STEM_UP() { <span class="hljs-keyword">return</span> Stem.UP; }
  <span class="hljs-keyword">static</span> get STEM_DOWN() { <span class="hljs-keyword">return</span> Stem.DOWN; }
  <span class="hljs-keyword">static</span> get DEFAULT_LEDGER_LINE_OFFSET() { <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>; }</pre></div>
        
      
        
        <h2 id="static-methods">Static Methods</h2>
<p>Format notes inside a ModifierContext.</p>

        
          <div class='highlight'><pre>  <span class="hljs-keyword">static</span> format(notes, state) {
    <span class="hljs-keyword">if</span> (!notes || notes.length &lt; <span class="hljs-number">2</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;</pre></div>
        
      
        
        <p>FIXME: VexFlow will soon require that a stave be set before formatting.
Which, according to the below condition, means that following branch will
always be taken and the rest of this function is dead code.</p>
<p>Problematically, <code>Formatter#formatByY</code> was not designed to work for more
than 2 voices (although, doesn’t throw on this condition, just tries
to power through).</p>
<p>Based on the above:</p>
<ul>
<li>2 voices can be formatted <em>with or without</em> a stave being set but
the output will be different</li>
<li>3 voices can only be formatted <em>without</em> a stave</li>
</ul>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (notes[<span class="hljs-number">0</span>].getStave()) {
      <span class="hljs-keyword">return</span> StaveNote.formatByY(notes, state);
    }

    <span class="hljs-keyword">const</span> notesList = [];

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; notes.length; i++) {
      <span class="hljs-keyword">const</span> props = notes[i].getKeyProps();
      <span class="hljs-keyword">const</span> line = props[<span class="hljs-number">0</span>].line;
      <span class="hljs-keyword">let</span> minL = props[props.length - <span class="hljs-number">1</span>].line;
      <span class="hljs-keyword">const</span> stemDirection = notes[i].getStemDirection();
      <span class="hljs-keyword">const</span> stemMax = notes[i].getStemLength() / <span class="hljs-number">10</span>;
      <span class="hljs-keyword">const</span> stemMin = notes[i].getStemMinumumLength() / <span class="hljs-number">10</span>;

      <span class="hljs-keyword">let</span> maxL;
      <span class="hljs-keyword">if</span> (notes[i].isRest()) {
        maxL = line + notes[i].glyph.line_above;
        minL = line - notes[i].glyph.line_below;
      } <span class="hljs-keyword">else</span> {
        maxL = stemDirection === <span class="hljs-number">1</span>
          ? props[props.length - <span class="hljs-number">1</span>].line + stemMax
          : props[props.length - <span class="hljs-number">1</span>].line;

        minL = stemDirection === <span class="hljs-number">1</span>
          ? props[<span class="hljs-number">0</span>].line
          : props[<span class="hljs-number">0</span>].line - stemMax;
      }

      notesList.push({
        <span class="hljs-attr">line</span>: props[<span class="hljs-number">0</span>].line, <span class="hljs-comment">// note/rest base line</span>
        maxLine: maxL, <span class="hljs-comment">// note/rest upper bounds line</span>
        minLine: minL, <span class="hljs-comment">// note/rest lower bounds line</span>
        isrest: notes[i].isRest(),
        stemDirection,
        stemMax, <span class="hljs-comment">// Maximum (default) note stem length;</span>
        stemMin, <span class="hljs-comment">// minimum note stem length</span>
        voice_shift: notes[i].getVoiceShiftWidth(),
        <span class="hljs-attr">is_displaced</span>: notes[i].isDisplaced(), <span class="hljs-comment">// note manually displaced</span>
        note: notes[i],
      });
    }

    <span class="hljs-keyword">const</span> voices = notesList.length;

    <span class="hljs-keyword">let</span> noteU = notesList[<span class="hljs-number">0</span>];
    <span class="hljs-keyword">const</span> noteM = voices &gt; <span class="hljs-number">2</span> ? notesList[<span class="hljs-number">1</span>] : <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> noteL = voices &gt; <span class="hljs-number">2</span> ? notesList[<span class="hljs-number">2</span>] : notesList[<span class="hljs-number">1</span>];</pre></div>
        
      
        
        <p>for two voice backward compatibility, ensure upper voice is stems up
for three voices, the voices must be in order (upper, middle, lower)</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (voices === <span class="hljs-number">2</span> &amp;&amp; noteU.stemDirection === <span class="hljs-number">-1</span> &amp;&amp; noteL.stemDirection === <span class="hljs-number">1</span>) {
      noteU = notesList[<span class="hljs-number">1</span>];
      noteL = notesList[<span class="hljs-number">0</span>];
    }

    <span class="hljs-keyword">const</span> voiceXShift = <span class="hljs-built_in">Math</span>.max(noteU.voice_shift, noteL.voice_shift);
    <span class="hljs-keyword">let</span> xShift = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">let</span> stemDelta;</pre></div>
        
      
        
        <p>Test for two voice note intersection</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (voices === <span class="hljs-number">2</span>) {
      <span class="hljs-keyword">const</span> lineSpacing = noteU.stemDirection === noteL.stemDirection ? <span class="hljs-number">0.0</span> : <span class="hljs-number">0.5</span>;</pre></div>
        
      
        
        <p>if top voice is a middle voice, check stem intersection with lower voice</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">if</span> (noteU.stemDirection === noteL.stemDirection &amp;&amp;
        noteU.minLine &lt;= noteL.maxLine) {
        <span class="hljs-keyword">if</span> (!noteU.isrest) {
          stemDelta = <span class="hljs-built_in">Math</span>.abs(noteU.line - (noteL.maxLine + <span class="hljs-number">0.5</span>));
          stemDelta = <span class="hljs-built_in">Math</span>.max(stemDelta, noteU.stemMin);
          noteU.minLine = noteU.line - stemDelta;
          noteU.note.setStemLength(stemDelta * <span class="hljs-number">10</span>);
        }
      }
      <span class="hljs-keyword">if</span> (noteU.minLine &lt;= noteL.maxLine + lineSpacing) {
        <span class="hljs-keyword">if</span> (noteU.isrest) {</pre></div>
        
      
        
        <p>shift rest up</p>

        
          <div class='highlight'><pre>          shiftRestVertical(noteU, noteL, <span class="hljs-number">1</span>);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (noteL.isrest) {</pre></div>
        
      
        
        <p>shift rest down</p>

        
          <div class='highlight'><pre>          shiftRestVertical(noteL, noteU, <span class="hljs-number">-1</span>);
        } <span class="hljs-keyword">else</span> {
          xShift = voiceXShift;
          <span class="hljs-keyword">if</span> (noteU.stemDirection === noteL.stemDirection) {</pre></div>
        
      
        
        <p>upper voice is middle voice, so shift it right</p>

        
          <div class='highlight'><pre>            noteU.note.setXShift(xShift + <span class="hljs-number">3</span>);
          } <span class="hljs-keyword">else</span> {</pre></div>
        
      
        
        <p>shift lower voice right</p>

        
          <div class='highlight'><pre>            noteL.note.setXShift(xShift);
          }
        }
      }</pre></div>
        
      
        
        <p>format complete</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }</pre></div>
        
      
        
        <p>Check middle voice stem intersection with lower voice</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (noteM !== <span class="hljs-literal">null</span> &amp;&amp; noteM.minLine &lt; noteL.maxLine + <span class="hljs-number">0.5</span>) {
      <span class="hljs-keyword">if</span> (!noteM.isrest) {
        stemDelta = <span class="hljs-built_in">Math</span>.abs(noteM.line - (noteL.maxLine + <span class="hljs-number">0.5</span>));
        stemDelta = <span class="hljs-built_in">Math</span>.max(stemDelta, noteM.stemMin);
        noteM.minLine = noteM.line - stemDelta;
        noteM.note.setStemLength(stemDelta * <span class="hljs-number">10</span>);
      }
    }</pre></div>
        
      
        
        <p>For three voices, test if rests can be repositioned</p>
<p>Special case 1 :: middle voice rest between two notes</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (noteM.isrest &amp;&amp; !noteU.isrest &amp;&amp; !noteL.isrest) {
      <span class="hljs-keyword">if</span> (noteU.minLine &lt;= noteM.maxLine || noteM.minLine &lt;= noteL.maxLine) {
        <span class="hljs-keyword">const</span> restHeight = noteM.maxLine - noteM.minLine;
        <span class="hljs-keyword">const</span> space = noteU.minLine - noteL.maxLine;
        <span class="hljs-keyword">if</span> (restHeight &lt; space) {</pre></div>
        
      
        
        <p>center middle voice rest between the upper and lower voices</p>

        
          <div class='highlight'><pre>          centerRest(noteM, noteU, noteL);
        } <span class="hljs-keyword">else</span> {
          xShift = voiceXShift + <span class="hljs-number">3</span>;    <span class="hljs-comment">// shift middle rest right</span>
          noteM.note.setXShift(xShift);
        }</pre></div>
        
      
        
        <p>format complete</p>

        
          <div class='highlight'><pre>        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
      }
    }</pre></div>
        
      
        
        <p>Special case 2 :: all voices are rests</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (noteU.isrest &amp;&amp; noteM.isrest &amp;&amp; noteL.isrest) {</pre></div>
        
      
        
        <p>Shift upper voice rest up</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteU, noteM, <span class="hljs-number">1</span>);</pre></div>
        
      
        
        <p>Shift lower voice rest down</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteL, noteM, <span class="hljs-number">-1</span>);</pre></div>
        
      
        
        <p>format complete</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }</pre></div>
        
      
        
        <p>Test if any other rests can be repositioned</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (noteM.isrest &amp;&amp; noteU.isrest &amp;&amp; noteM.minLine &lt;= noteL.maxLine) {</pre></div>
        
      
        
        <p>Shift middle voice rest up</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteM, noteL, <span class="hljs-number">1</span>);
    }
    <span class="hljs-keyword">if</span> (noteM.isrest &amp;&amp; noteL.isrest &amp;&amp; noteU.minLine &lt;= noteM.maxLine) {</pre></div>
        
      
        
        <p>Shift middle voice rest down</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteM, noteU, <span class="hljs-number">-1</span>);
    }
    <span class="hljs-keyword">if</span> (noteU.isrest &amp;&amp; noteU.minLine &lt;= noteM.maxLine) {</pre></div>
        
      
        
        <p>shift upper voice rest up;</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteU, noteM, <span class="hljs-number">1</span>);
    }
    <span class="hljs-keyword">if</span> (noteL.isrest &amp;&amp; noteM.minLine &lt;= noteL.maxLine) {</pre></div>
        
      
        
        <p>shift lower voice rest down</p>

        
          <div class='highlight'><pre>      shiftRestVertical(noteL, noteM, <span class="hljs-number">-1</span>);
    }</pre></div>
        
      
        
        <p>If middle voice intersects upper or lower voice</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> ((!noteU.isrest &amp;&amp; !noteM.isrest &amp;&amp; noteU.minLine &lt;= noteM.maxLine + <span class="hljs-number">0.5</span>) ||
      (!noteM.isrest &amp;&amp; !noteL.isrest &amp;&amp; noteM.minLine &lt;= noteL.maxLine)) {
      xShift = voiceXShift + <span class="hljs-number">3</span>;      <span class="hljs-comment">// shift middle note right</span>
      noteM.note.setXShift(xShift);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-keyword">static</span> formatByY(notes, state) {</pre></div>
        
      
        
        <p>NOTE: this function does not support more than two voices per stave
use with care.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">let</span> hasStave = <span class="hljs-literal">true</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; notes.length; i++) {
      hasStave = hasStave &amp;&amp; notes[i].getStave() != <span class="hljs-literal">null</span>;
    }

    <span class="hljs-keyword">if</span> (!hasStave) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(
        <span class="hljs-string">'Stave Missing'</span>,
        <span class="hljs-string">'All notes must have a stave - Vex.Flow.ModifierContext.formatMultiVoice!'</span>
      );
    }

    <span class="hljs-keyword">let</span> xShift = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; notes.length - <span class="hljs-number">1</span>; i++) {
      <span class="hljs-keyword">let</span> topNote = notes[i];
      <span class="hljs-keyword">let</span> bottomNote = notes[i + <span class="hljs-number">1</span>];

      <span class="hljs-keyword">if</span> (topNote.getStemDirection() === Stem.DOWN) {
        topNote = notes[i + <span class="hljs-number">1</span>];
        bottomNote = notes[i];
      }

      <span class="hljs-keyword">const</span> topKeys = topNote.getKeyProps();
      <span class="hljs-keyword">const</span> bottomKeys = bottomNote.getKeyProps();

      <span class="hljs-keyword">const</span> HALF_NOTEHEAD_HEIGHT = <span class="hljs-number">0.5</span>;</pre></div>
        
      
        
        <p><code>keyProps</code> and <code>stave.getYForLine</code> have different notions of a <code>line</code>
so we have to convert the keyProps value by subtracting 5.
See <a href="https://github.com/0xfe/vexflow/wiki/Development-Gotchas">https://github.com/0xfe/vexflow/wiki/Development-Gotchas</a></p>
<p>We also extend the y for each note by a half notehead because the
notehead’s origin is centered</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">const</span> topNotBottomY = topNote
        .getStave()
        .getYForLine(<span class="hljs-number">5</span> - topKeys[<span class="hljs-number">0</span>].line + HALF_NOTEHEAD_HEIGHT);

      <span class="hljs-keyword">const</span> bottomNoteTopY = bottomNote
        .getStave()
        .getYForLine(<span class="hljs-number">5</span> - bottomKeys[bottomKeys.length - <span class="hljs-number">1</span>].line - HALF_NOTEHEAD_HEIGHT);

      <span class="hljs-keyword">const</span> areNotesColliding = bottomNoteTopY - topNotBottomY &lt; <span class="hljs-number">0</span>;

      <span class="hljs-keyword">if</span> (areNotesColliding) {
        xShift = topNote.getVoiceShiftWidth() + <span class="hljs-number">2</span>;
        bottomNote.setXShift(xShift);
      }
    }

    state.right_shift += xShift;
  }

  <span class="hljs-keyword">static</span> postFormat(notes) {
    <span class="hljs-keyword">if</span> (!notes) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    notes.forEach(<span class="hljs-function"><span class="hljs-params">note</span> =&gt;</span> note.postFormat());

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-keyword">constructor</span>(noteStruct) {
    <span class="hljs-keyword">super</span>(noteStruct);
    <span class="hljs-keyword">this</span>.setAttribute(<span class="hljs-string">'type'</span>, <span class="hljs-string">'StaveNote'</span>);

    <span class="hljs-keyword">this</span>.keys = noteStruct.keys;
    <span class="hljs-keyword">this</span>.clef = noteStruct.clef;
    <span class="hljs-keyword">this</span>.octave_shift = noteStruct.octave_shift;
    <span class="hljs-keyword">this</span>.beam = <span class="hljs-literal">null</span>;</pre></div>
        
      
        
        <p>Pull note rendering properties</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.glyph = Flow.durationToGlyph(<span class="hljs-keyword">this</span>.duration, <span class="hljs-keyword">this</span>.noteType);

    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.glyph) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RuntimeError(
        <span class="hljs-string">'BadArguments'</span>,
        <span class="hljs-string">`Invalid note initialization data (No glyph found): <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(noteStruct)}</span>`</span>
      );
    }</pre></div>
        
      
        
        <p>if true, displace note to right</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.displaced = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">this</span>.dot_shiftY = <span class="hljs-number">0</span>;</pre></div>
        
      
        
        <p>per-pitch properties</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.keyProps = [];</pre></div>
        
      
        
        <p>for displaced ledger lines</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.use_default_head_x = <span class="hljs-literal">false</span>;</pre></div>
        
      
        
        <p>Drawing</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.note_heads = [];
    <span class="hljs-keyword">this</span>.modifiers = [];

    Vex.Merge(<span class="hljs-keyword">this</span>.render_options, {</pre></div>
        
      
        
        <p>font size for note heads and rests</p>

        
          <div class='highlight'><pre>      glyph_font_scale: noteStruct.glyph_font_scale || Flow.DEFAULT_NOTATION_FONT_SCALE,</pre></div>
        
      
        
        <p>number of stroke px to the left and right of head</p>

        
          <div class='highlight'><pre>      stroke_px: noteStruct.stroke_px || StaveNote.DEFAULT_LEDGER_LINE_OFFSET,
    });

    <span class="hljs-keyword">this</span>.calculateKeyProps();
    <span class="hljs-keyword">this</span>.buildStem();</pre></div>
        
      
        
        <p>Set the stem direction</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (noteStruct.auto_stem) {
      <span class="hljs-keyword">this</span>.autoStem();
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">this</span>.setStemDirection(noteStruct.stem_direction);
    }
    <span class="hljs-keyword">this</span>.reset();
    <span class="hljs-keyword">this</span>.buildFlag();
  }

  reset() {
    <span class="hljs-keyword">super</span>.reset();</pre></div>
        
      
        
        <p>Save prior noteHead styles &amp; reapply them after making new noteheads.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">const</span> noteHeadStyles = <span class="hljs-keyword">this</span>.note_heads.map(<span class="hljs-function"><span class="hljs-params">noteHead</span> =&gt;</span> noteHead.getStyle());
    <span class="hljs-keyword">this</span>.buildNoteHeads();
    <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function">(<span class="hljs-params">noteHead, index</span>) =&gt;</span> noteHead.setStyle(noteHeadStyles[index]));

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.stave) {
      <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function"><span class="hljs-params">head</span> =&gt;</span> head.setStave(<span class="hljs-keyword">this</span>.stave));
    }
    <span class="hljs-keyword">this</span>.calcExtraPx();
  }

  setBeam(beam) {
    <span class="hljs-keyword">this</span>.beam = beam;
    <span class="hljs-keyword">this</span>.calcExtraPx();
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }

  getCategory() { <span class="hljs-keyword">return</span> StaveNote.CATEGORY; }</pre></div>
        
      
        
        <p>Builds a <code>Stem</code> for the note</p>

        
          <div class='highlight'><pre>  buildStem() {
    <span class="hljs-keyword">const</span> glyph = <span class="hljs-keyword">this</span>.getGlyph();

    <span class="hljs-keyword">this</span>.setStem(<span class="hljs-keyword">new</span> Stem({
      <span class="hljs-attr">stem_up_y_offset</span>: glyph.stem_up_y_offset,
      <span class="hljs-attr">stem_down_y_offset</span>: glyph.stem_down_y_offset,
      <span class="hljs-attr">hide</span>: !!<span class="hljs-keyword">this</span>.isRest(),
    }));
  }</pre></div>
        
      
        
        <p>Builds a <code>NoteHead</code> for each key in the note</p>

        
          <div class='highlight'><pre>  buildNoteHeads() {
    <span class="hljs-keyword">this</span>.note_heads = [];
    <span class="hljs-keyword">const</span> stemDirection = <span class="hljs-keyword">this</span>.getStemDirection();
    <span class="hljs-keyword">const</span> keys = <span class="hljs-keyword">this</span>.getKeys();

    <span class="hljs-keyword">let</span> lastLine = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> lineDiff = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> displaced = <span class="hljs-literal">false</span>;</pre></div>
        
      
        
        <p>Draw notes from bottom to top.</p>

        
      
        
        <p>For down-stem notes, we draw from top to bottom.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">let</span> start;
    <span class="hljs-keyword">let</span> end;
    <span class="hljs-keyword">let</span> step;
    <span class="hljs-keyword">if</span> (stemDirection === Stem.UP) {
      start = <span class="hljs-number">0</span>;
      end = keys.length;
      step = <span class="hljs-number">1</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (stemDirection === Stem.DOWN) {
      start = keys.length - <span class="hljs-number">1</span>;
      end = <span class="hljs-number">-1</span>;
      step = <span class="hljs-number">-1</span>;
    }

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = start; i !== end; i += step) {
      <span class="hljs-keyword">const</span> noteProps = <span class="hljs-keyword">this</span>.keyProps[i];
      <span class="hljs-keyword">const</span> line = noteProps.line;</pre></div>
        
      
        
        <p>Keep track of last line with a note head, so that consecutive heads
are correctly displaced.</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">if</span> (lastLine === <span class="hljs-literal">null</span>) {
        lastLine = line;
      } <span class="hljs-keyword">else</span> {
        lineDiff = <span class="hljs-built_in">Math</span>.abs(lastLine - line);
        <span class="hljs-keyword">if</span> (lineDiff === <span class="hljs-number">0</span> || lineDiff === <span class="hljs-number">0.5</span>) {
          displaced = !displaced;
        } <span class="hljs-keyword">else</span> {
          displaced = <span class="hljs-literal">false</span>;
          <span class="hljs-keyword">this</span>.use_default_head_x = <span class="hljs-literal">true</span>;
        }
      }
      lastLine = line;

      <span class="hljs-keyword">const</span> notehead = <span class="hljs-keyword">new</span> NoteHead({
        <span class="hljs-attr">duration</span>: <span class="hljs-keyword">this</span>.duration,
        <span class="hljs-attr">note_type</span>: <span class="hljs-keyword">this</span>.noteType,
        displaced,
        <span class="hljs-attr">stem_direction</span>: stemDirection,
        <span class="hljs-attr">custom_glyph_code</span>: noteProps.code,
        <span class="hljs-attr">glyph_font_scale</span>: <span class="hljs-keyword">this</span>.render_options.glyph_font_scale,
        <span class="hljs-attr">x_shift</span>: noteProps.shift_right,
        <span class="hljs-attr">line</span>: noteProps.line,
      });

      <span class="hljs-keyword">this</span>.note_heads[i] = notehead;
    }
  }</pre></div>
        
      
        
        <p>Automatically sets the stem direction based on the keys in the note</p>

        
          <div class='highlight'><pre>  autoStem() {</pre></div>
        
      
        
        <p>Figure out optimal stem direction based on given notes</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.minLine = <span class="hljs-keyword">this</span>.keyProps[<span class="hljs-number">0</span>].line;
    <span class="hljs-keyword">this</span>.maxLine = <span class="hljs-keyword">this</span>.keyProps[<span class="hljs-keyword">this</span>.keyProps.length - <span class="hljs-number">1</span>].line;

    <span class="hljs-keyword">const</span> MIDDLE_LINE = <span class="hljs-number">3</span>;
    <span class="hljs-keyword">const</span> decider = (<span class="hljs-keyword">this</span>.minLine + <span class="hljs-keyword">this</span>.maxLine) / <span class="hljs-number">2</span>;
    <span class="hljs-keyword">const</span> stemDirection = decider &lt; MIDDLE_LINE ? Stem.UP : Stem.DOWN;

    <span class="hljs-keyword">this</span>.setStemDirection(stemDirection);
  }</pre></div>
        
      
        
        <p>Calculates and stores the properties for each key in the note</p>

        
          <div class='highlight'><pre>  calculateKeyProps() {
    <span class="hljs-keyword">let</span> lastLine = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.keys.length; ++i) {
      <span class="hljs-keyword">const</span> key = <span class="hljs-keyword">this</span>.keys[i];</pre></div>
        
      
        
        <p>All rests use the same position on the line.
if (this.glyph.rest) key = this.glyph.position;</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.glyph.rest) <span class="hljs-keyword">this</span>.glyph.position = key;

      <span class="hljs-keyword">const</span> options = { <span class="hljs-attr">octave_shift</span>: <span class="hljs-keyword">this</span>.octave_shift || <span class="hljs-number">0</span> };
      <span class="hljs-keyword">const</span> props = Flow.keyProperties(key, <span class="hljs-keyword">this</span>.clef, options);

      <span class="hljs-keyword">if</span> (!props) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RuntimeError(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid key for note properties: <span class="hljs-subst">${key}</span>`</span>);
      }</pre></div>
        
      
        
        <p>Override line placement for default rests</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">if</span> (props.key === <span class="hljs-string">'R'</span>) {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.duration === <span class="hljs-string">'1'</span> || <span class="hljs-keyword">this</span>.duration === <span class="hljs-string">'w'</span>) {
          props.line = <span class="hljs-number">4</span>;
        } <span class="hljs-keyword">else</span> {
          props.line = <span class="hljs-number">3</span>;
        }
      }</pre></div>
        
      
        
        <p>Calculate displacement of this note</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">const</span> line = props.line;
      <span class="hljs-keyword">if</span> (lastLine === <span class="hljs-literal">null</span>) {
        lastLine = line;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(lastLine - line) === <span class="hljs-number">0.5</span>) {
          <span class="hljs-keyword">this</span>.displaced = <span class="hljs-literal">true</span>;
          props.displaced = <span class="hljs-literal">true</span>;</pre></div>
        
      
        
        <p>Have to mark the previous note as
displaced as well, for modifier placement</p>

        
          <div class='highlight'><pre>          <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.keyProps.length &gt; <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">this</span>.keyProps[i - <span class="hljs-number">1</span>].displaced = <span class="hljs-literal">true</span>;
          }
        }
      }

      lastLine = line;
      <span class="hljs-keyword">this</span>.keyProps.push(props);
    }</pre></div>
        
      
        
        <p>Sort the notes from lowest line to highest line</p>

        
          <div class='highlight'><pre>    lastLine = -<span class="hljs-literal">Infinity</span>;
    <span class="hljs-keyword">this</span>.keyProps.forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (key.line &lt; lastLine) {
        Vex.W(
          <span class="hljs-string">'Unsorted keys in note will be sorted. '</span> +
          <span class="hljs-string">'See https://github.com/0xfe/vexflow/issues/104 for details.'</span>
        );
      }
      lastLine = key.line;
    });
    <span class="hljs-keyword">this</span>.keyProps.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a.line - b.line);
  }</pre></div>
        
      
        
        <p>Get the <code>BoundingBox</code> for the entire note</p>

        
          <div class='highlight'><pre>  getBoundingBox() {
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.preFormatted) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'UnformattedNote'</span>, <span class="hljs-string">"Can't call getBoundingBox on an unformatted note."</span>);
    }

    <span class="hljs-keyword">const</span> { <span class="hljs-attr">width</span>: w, modLeftPx, extraLeftPx } = <span class="hljs-keyword">this</span>.getMetrics();
    <span class="hljs-keyword">const</span> x = <span class="hljs-keyword">this</span>.getAbsoluteX() - modLeftPx - extraLeftPx;

    <span class="hljs-keyword">let</span> minY = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">let</span> maxY = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">const</span> halfLineSpacing = <span class="hljs-keyword">this</span>.getStave().getSpacingBetweenLines() / <span class="hljs-number">2</span>;
    <span class="hljs-keyword">const</span> lineSpacing = halfLineSpacing * <span class="hljs-number">2</span>;

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isRest()) {
      <span class="hljs-keyword">const</span> y = <span class="hljs-keyword">this</span>.ys[<span class="hljs-number">0</span>];
      <span class="hljs-keyword">const</span> frac = Flow.durationToFraction(<span class="hljs-keyword">this</span>.duration);
      <span class="hljs-keyword">if</span> (frac.equals(<span class="hljs-number">1</span>) || frac.equals(<span class="hljs-number">2</span>)) {
        minY = y - halfLineSpacing;
        maxY = y + halfLineSpacing;
      } <span class="hljs-keyword">else</span> {
        minY = y - (<span class="hljs-keyword">this</span>.glyph.line_above * lineSpacing);
        maxY = y + (<span class="hljs-keyword">this</span>.glyph.line_below * lineSpacing);
      }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.glyph.stem) {
      <span class="hljs-keyword">const</span> ys = <span class="hljs-keyword">this</span>.getStemExtents();
      ys.baseY += halfLineSpacing * <span class="hljs-keyword">this</span>.stem_direction;
      minY = <span class="hljs-built_in">Math</span>.min(ys.topY, ys.baseY);
      maxY = <span class="hljs-built_in">Math</span>.max(ys.topY, ys.baseY);
    } <span class="hljs-keyword">else</span> {
      minY = <span class="hljs-literal">null</span>;
      maxY = <span class="hljs-literal">null</span>;

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.ys.length; ++i) {
        <span class="hljs-keyword">const</span> yy = <span class="hljs-keyword">this</span>.ys[i];
        <span class="hljs-keyword">if</span> (i === <span class="hljs-number">0</span>) {
          minY = yy;
          maxY = yy;
        } <span class="hljs-keyword">else</span> {
          minY = <span class="hljs-built_in">Math</span>.min(yy, minY);
          maxY = <span class="hljs-built_in">Math</span>.max(yy, maxY);
        }
      }
      minY -= halfLineSpacing;
      maxY += halfLineSpacing;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BoundingBox(x, minY, w, maxY - minY);
  }</pre></div>
        
      
        
        <p>Gets the line number of the top or bottom note in the chord.
If <code>isTopNote</code> is <code>true</code> then get the top note</p>

        
          <div class='highlight'><pre>  getLineNumber(isTopNote) {
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.keyProps.length) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(
        <span class="hljs-string">'NoKeyProps'</span>, <span class="hljs-string">"Can't get bottom note line, because note is not initialized properly."</span>
      );
    }

    <span class="hljs-keyword">let</span> resultLine = <span class="hljs-keyword">this</span>.keyProps[<span class="hljs-number">0</span>].line;</pre></div>
        
      
        
        <p>No precondition assumed for sortedness of keyProps array</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.keyProps.length; i++) {
      <span class="hljs-keyword">const</span> thisLine = <span class="hljs-keyword">this</span>.keyProps[i].line;
      <span class="hljs-keyword">if</span> (isTopNote) {
        <span class="hljs-keyword">if</span> (thisLine &gt; resultLine) resultLine = thisLine;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (thisLine &lt; resultLine) resultLine = thisLine;
      }
    }

    <span class="hljs-keyword">return</span> resultLine;
  }</pre></div>
        
      
        
        <p>Determine if current note is a rest</p>

        
          <div class='highlight'><pre>  isRest() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.glyph.rest; }</pre></div>
        
      
        
        <p>Determine if the current note is a chord</p>

        
          <div class='highlight'><pre>  isChord() { <span class="hljs-keyword">return</span> !<span class="hljs-keyword">this</span>.isRest() &amp;&amp; <span class="hljs-keyword">this</span>.keys.length &gt; <span class="hljs-number">1</span>; }</pre></div>
        
      
        
        <p>Determine if the <code>StaveNote</code> has a stem</p>

        
          <div class='highlight'><pre>  hasStem() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.glyph.stem; }

  hasFlag() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.hasFlag() &amp;&amp; !<span class="hljs-keyword">this</span>.isRest();
  }

  getStemX() {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.noteType === <span class="hljs-string">'r'</span>) {
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getCenterGlyphX();
    } <span class="hljs-keyword">else</span> {</pre></div>
        
      
        
        <p>We adjust the origin of the stem because we want the stem left-aligned
with the notehead if stemmed-down, and right-aligned if stemmed-up</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.getStemX() + getStemAdjustment(<span class="hljs-keyword">this</span>);
    }
  }</pre></div>
        
      
        
        <p>Get the <code>y</code> coordinate for text placed on the top/bottom of a
note at a desired <code>text_line</code></p>

        
          <div class='highlight'><pre>  getYForTopText(textLine) {
    <span class="hljs-keyword">const</span> extents = <span class="hljs-keyword">this</span>.getStemExtents();
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.min(
      <span class="hljs-keyword">this</span>.stave.getYForTopText(textLine),
      extents.topY - (<span class="hljs-keyword">this</span>.render_options.annotation_spacing * (textLine + <span class="hljs-number">1</span>))
    );
  }
  getYForBottomText(textLine) {
    <span class="hljs-keyword">const</span> extents = <span class="hljs-keyword">this</span>.getStemExtents();
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.max(
      <span class="hljs-keyword">this</span>.stave.getYForTopText(textLine),
      extents.baseY + (<span class="hljs-keyword">this</span>.render_options.annotation_spacing * (textLine))
    );
  }</pre></div>
        
      
        
        <p>Sets the current note to the provided <code>stave</code>. This applies
<code>y</code> values to the <code>NoteHeads</code>.</p>

        
          <div class='highlight'><pre>  setStave(stave) {
    <span class="hljs-keyword">super</span>.setStave(stave);

    <span class="hljs-keyword">const</span> ys = <span class="hljs-keyword">this</span>.note_heads.map(<span class="hljs-function"><span class="hljs-params">notehead</span> =&gt;</span> {
      notehead.setStave(stave);
      <span class="hljs-keyword">return</span> notehead.getY();
    });

    <span class="hljs-keyword">this</span>.setYs(ys);

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.stem) {
      <span class="hljs-keyword">const</span> { y_top, y_bottom } = <span class="hljs-keyword">this</span>.getNoteHeadBounds();
      <span class="hljs-keyword">this</span>.stem.setYBounds(y_top, y_bottom);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }</pre></div>
        
      
        
        <p>Get the pitches in the note</p>

        
          <div class='highlight'><pre>  getKeys() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.keys; }</pre></div>
        
      
        
        <p>Get the properties for all the keys in the note</p>

        
          <div class='highlight'><pre>  getKeyProps() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.keyProps;
  }</pre></div>
        
      
        
        <p>Check if note is shifted to the right</p>

        
          <div class='highlight'><pre>  isDisplaced() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.displaced;
  }</pre></div>
        
      
        
        <p>Sets whether shift note to the right. <code>displaced</code> is a <code>boolean</code></p>

        
          <div class='highlight'><pre>  setNoteDisplaced(displaced) {
    <span class="hljs-keyword">this</span>.displaced = displaced;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }</pre></div>
        
      
        
        <p>Get the starting <code>x</code> coordinate for a <code>StaveTie</code></p>

        
          <div class='highlight'><pre>  getTieRightX() {
    <span class="hljs-keyword">let</span> tieStartX = <span class="hljs-keyword">this</span>.getAbsoluteX();
    tieStartX += <span class="hljs-keyword">this</span>.getGlyphWidth() + <span class="hljs-keyword">this</span>.x_shift + <span class="hljs-keyword">this</span>.extraRightPx;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.modifierContext) tieStartX += <span class="hljs-keyword">this</span>.modifierContext.getExtraRightPx();
    <span class="hljs-keyword">return</span> tieStartX;
  }</pre></div>
        
      
        
        <p>Get the ending <code>x</code> coordinate for a <code>StaveTie</code></p>

        
          <div class='highlight'><pre>  getTieLeftX() {
    <span class="hljs-keyword">let</span> tieEndX = <span class="hljs-keyword">this</span>.getAbsoluteX();
    tieEndX += <span class="hljs-keyword">this</span>.x_shift - <span class="hljs-keyword">this</span>.extraLeftPx;
    <span class="hljs-keyword">return</span> tieEndX;
  }</pre></div>
        
      
        
        <p>Get the stave line on which to place a rest</p>

        
          <div class='highlight'><pre>  getLineForRest() {
    <span class="hljs-keyword">let</span> restLine = <span class="hljs-keyword">this</span>.keyProps[<span class="hljs-number">0</span>].line;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.keyProps.length &gt; <span class="hljs-number">1</span>) {
      <span class="hljs-keyword">const</span> lastLine = <span class="hljs-keyword">this</span>.keyProps[<span class="hljs-keyword">this</span>.keyProps.length - <span class="hljs-number">1</span>].line;
      <span class="hljs-keyword">const</span> top = <span class="hljs-built_in">Math</span>.max(restLine, lastLine);
      <span class="hljs-keyword">const</span> bot = <span class="hljs-built_in">Math</span>.min(restLine, lastLine);
      restLine = Vex.MidLine(top, bot);
    }

    <span class="hljs-keyword">return</span> restLine;
  }</pre></div>
        
      
        
        <p>Get the default <code>x</code> and <code>y</code> coordinates for the provided <code>position</code>
and key <code>index</code></p>

        
          <div class='highlight'><pre>  getModifierStartXY(position, index, options) {
    options = options || {};
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.preFormatted) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'UnformattedNote'</span>, <span class="hljs-string">"Can't call GetModifierStartXY on an unformatted note"</span>);
    }

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.ys.length === <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoYValues'</span>, <span class="hljs-string">'No Y-Values calculated for this note.'</span>);
    }

    <span class="hljs-keyword">const</span> { ABOVE, BELOW, LEFT, RIGHT } = Modifier.Position;
    <span class="hljs-keyword">let</span> x = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">if</span> (position === LEFT) {</pre></div>
        
      
        
        <p>extra_left_px
FIXME: What are these magic numbers?</p>

        
          <div class='highlight'><pre>      x = <span class="hljs-number">-1</span> * <span class="hljs-number">2</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (position === RIGHT) {</pre></div>
        
      
        
        <p>extra_right_px
FIXME: What is this magical +2?</p>

        
          <div class='highlight'><pre>      x = <span class="hljs-keyword">this</span>.getGlyphWidth() + <span class="hljs-keyword">this</span>.x_shift + <span class="hljs-number">2</span>;

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.stem_direction === Stem.UP &amp;&amp; <span class="hljs-keyword">this</span>.hasFlag() &amp;&amp;
        (options.forceFlagRight || isInnerNoteIndex(<span class="hljs-keyword">this</span>, index))) {
        x += <span class="hljs-keyword">this</span>.flag.getMetrics().width;
      }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (position === BELOW || position === ABOVE) {
      x = <span class="hljs-keyword">this</span>.getGlyphWidth() / <span class="hljs-number">2</span>;
    }

    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">x</span>: <span class="hljs-keyword">this</span>.getAbsoluteX() + x,
      <span class="hljs-attr">y</span>: <span class="hljs-keyword">this</span>.ys[index],
    };
  }</pre></div>
        
      
        
        <p>Sets the style of the complete StaveNote, including all keys
and the stem.</p>

        
          <div class='highlight'><pre>  setStyle(style) {
    <span class="hljs-keyword">super</span>.setStyle(style);
    <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function"><span class="hljs-params">notehead</span> =&gt;</span> notehead.setStyle(style));
    <span class="hljs-keyword">this</span>.stem.setStyle(style);
  }

  setStemStyle(style) {
    <span class="hljs-keyword">const</span> stem = <span class="hljs-keyword">this</span>.getStem();
    stem.setStyle(style);
  }
  getStemStyle() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.stem.getStyle(); }

  setLedgerLineStyle(style) { <span class="hljs-keyword">this</span>.ledgerLineStyle = style; }
  getLedgerLineStyle() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.ledgerLineStyle; }

  setFlagStyle(style) { <span class="hljs-keyword">this</span>.flagStyle = style; }
  getFlagStyle() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.flagStyle; }</pre></div>
        
      
        
        <p>Sets the notehead at <code>index</code> to the provided coloring <code>style</code>.</p>
<p><code>style</code> is an <code>object</code> with the following properties: <code>shadowColor</code>,
<code>shadowBlur</code>, <code>fillStyle</code>, <code>strokeStyle</code></p>

        
          <div class='highlight'><pre>  setKeyStyle(index, style) {
    <span class="hljs-keyword">this</span>.note_heads[index].setStyle(style);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }

  setKeyLine(index, line) {
    <span class="hljs-keyword">this</span>.keyProps[index].line = line;
    <span class="hljs-keyword">this</span>.reset();
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }

  getKeyLine(index) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.keyProps[index].line;
  }</pre></div>
        
      
        
        <p>Add self to modifier context. <code>mContext</code> is the <code>ModifierContext</code>
to be added to.</p>

        
          <div class='highlight'><pre>  addToModifierContext(mContext) {
    <span class="hljs-keyword">this</span>.setModifierContext(mContext);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.modifiers.length; ++i) {
      <span class="hljs-keyword">this</span>.modifierContext.addModifier(<span class="hljs-keyword">this</span>.modifiers[i]);
    }
    <span class="hljs-keyword">this</span>.modifierContext.addModifier(<span class="hljs-keyword">this</span>);
    <span class="hljs-keyword">this</span>.setPreFormatted(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }</pre></div>
        
      
        
        <p>Generic function to add modifiers to a note</p>
<p>Parameters:</p>
<ul>
<li><code>index</code>: The index of the key that we’re modifying</li>
<li><code>modifier</code>: The modifier to add</li>
</ul>

        
          <div class='highlight'><pre>  addModifier(index, modifier) {
    modifier.setNote(<span class="hljs-keyword">this</span>);
    modifier.setIndex(index);
    <span class="hljs-keyword">this</span>.modifiers.push(modifier);
    <span class="hljs-keyword">this</span>.setPreFormatted(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }</pre></div>
        
      
        
        <p>Helper function to add an accidental to a key</p>

        
          <div class='highlight'><pre>  addAccidental(index, accidental) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.addModifier(index, accidental);
  }</pre></div>
        
      
        
        <p>Helper function to add an articulation to a key</p>

        
          <div class='highlight'><pre>  addArticulation(index, articulation) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.addModifier(index, articulation);
  }</pre></div>
        
      
        
        <p>Helper function to add an annotation to a key</p>

        
          <div class='highlight'><pre>  addAnnotation(index, annotation) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.addModifier(index, annotation);
  }</pre></div>
        
      
        
        <p>Helper function to add a dot on a specific key</p>

        
          <div class='highlight'><pre>  addDot(index) {
    <span class="hljs-keyword">const</span> dot = <span class="hljs-keyword">new</span> Dot();
    dot.setDotShiftY(<span class="hljs-keyword">this</span>.glyph.dot_shiftY);
    <span class="hljs-keyword">this</span>.dots++;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.addModifier(index, dot);
  }</pre></div>
        
      
        
        <p>Convenience method to add dot to all keys in note</p>

        
          <div class='highlight'><pre>  addDotToAll() {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.keys.length; ++i) {
      <span class="hljs-keyword">this</span>.addDot(i);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
  }</pre></div>
        
      
        
        <p>Get all accidentals in the <code>ModifierContext</code></p>

        
          <div class='highlight'><pre>  getAccidentals() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.modifierContext.getModifiers(<span class="hljs-string">'accidentals'</span>);
  }</pre></div>
        
      
        
        <p>Get all dots in the <code>ModifierContext</code></p>

        
          <div class='highlight'><pre>  getDots() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.modifierContext.getModifiers(<span class="hljs-string">'dots'</span>);
  }</pre></div>
        
      
        
        <p>Get the width of the note if it is displaced. Used for <code>Voice</code>
formatting</p>

        
          <div class='highlight'><pre>  getVoiceShiftWidth() {</pre></div>
        
      
        
        <p>TODO: may need to accomodate for dot here.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getGlyphWidth() * (<span class="hljs-keyword">this</span>.displaced ? <span class="hljs-number">2</span> : <span class="hljs-number">1</span>);
  }</pre></div>
        
      
        
        <p>Calculates and sets the extra pixels to the left or right
if the note is displaced.</p>

        
          <div class='highlight'><pre>  calcExtraPx() {
    <span class="hljs-keyword">this</span>.setExtraLeftPx(
      <span class="hljs-keyword">this</span>.displaced &amp;&amp; <span class="hljs-keyword">this</span>.stem_direction === Stem.DOWN
        ? <span class="hljs-keyword">this</span>.getGlyphWidth()
        : <span class="hljs-number">0</span>
    );</pre></div>
        
      
        
        <p>For upstems with flags, the extra space is unnecessary, since it’s taken
up by the flag.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.setExtraRightPx(
      !<span class="hljs-keyword">this</span>.hasFlag() &amp;&amp; <span class="hljs-keyword">this</span>.displaced &amp;&amp; <span class="hljs-keyword">this</span>.stem_direction === Stem.UP
        ? <span class="hljs-keyword">this</span>.getGlyphWidth()
        : <span class="hljs-number">0</span>
    );
  }</pre></div>
        
      
        
        <p>Pre-render formatting</p>

        
          <div class='highlight'><pre>  preFormat() {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.preFormatted) <span class="hljs-keyword">return</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.modifierContext) <span class="hljs-keyword">this</span>.modifierContext.preFormat();

    <span class="hljs-keyword">let</span> width = <span class="hljs-keyword">this</span>.getGlyphWidth() + <span class="hljs-keyword">this</span>.extraLeftPx + <span class="hljs-keyword">this</span>.extraRightPx;</pre></div>
        
      
        
        <p>For upward flagged notes, the width of the flag needs to be added</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.glyph.flag &amp;&amp; <span class="hljs-keyword">this</span>.beam === <span class="hljs-literal">null</span> &amp;&amp; <span class="hljs-keyword">this</span>.stem_direction === Stem.UP) {
      width += <span class="hljs-keyword">this</span>.getGlyphWidth();
    }

    <span class="hljs-keyword">this</span>.setWidth(width);
    <span class="hljs-keyword">this</span>.setPreFormatted(<span class="hljs-literal">true</span>);
  }

  <span class="hljs-comment">/**
   * @typedef {Object} noteHeadBounds
   * @property {number} y_top the highest notehead bound
   * @property {number} y_bottom the lowest notehead bound
   * @property {number|Null} displaced_x the starting x for displaced noteheads
   * @property {number|Null} non_displaced_x the starting x for non-displaced noteheads
   * @property {number} highest_line the highest notehead line in traditional music line
   *  numbering (bottom line = 1, top line = 5)
   * @property {number} lowest_line the lowest notehead line
   * @property {number|false} highest_displaced_line the highest staff line number
   *   for a displaced notehead
   * @property {number|false} lowest_displaced_line
   * @property {number} highest_non_displaced_line
   * @property {number} lowest_non_displaced_line
   */</span>

  <span class="hljs-comment">/**
   * Get the staff line and y value for the highest &amp; lowest noteheads
   * @returns {noteHeadBounds}
   */</span>
  getNoteHeadBounds() {</pre></div>
        
      
        
        <p>Top and bottom Y values for stem.</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">let</span> yTop = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> yBottom = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> nonDisplacedX = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> displacedX = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">let</span> highestLine = <span class="hljs-keyword">this</span>.stave.getNumLines();
    <span class="hljs-keyword">let</span> lowestLine = <span class="hljs-number">1</span>;
    <span class="hljs-keyword">let</span> highestDisplacedLine = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">let</span> lowestDisplacedLine = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">let</span> highestNonDisplacedLine = highestLine;
    <span class="hljs-keyword">let</span> lowestNonDisplacedLine = lowestLine;

    <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function"><span class="hljs-params">notehead</span> =&gt;</span> {
      <span class="hljs-keyword">const</span> line = notehead.getLine();
      <span class="hljs-keyword">const</span> y = notehead.getY();

      <span class="hljs-keyword">if</span> (yTop === <span class="hljs-literal">null</span> || y &lt; yTop) {
        yTop = y;
      }

      <span class="hljs-keyword">if</span> (yBottom === <span class="hljs-literal">null</span> || y &gt; yBottom) {
        yBottom = y;
      }

      <span class="hljs-keyword">if</span> (displacedX === <span class="hljs-literal">null</span> &amp;&amp; notehead.isDisplaced()) {
        displacedX = notehead.getAbsoluteX();
      }

      <span class="hljs-keyword">if</span> (nonDisplacedX === <span class="hljs-literal">null</span> &amp;&amp; !notehead.isDisplaced()) {
        nonDisplacedX = notehead.getAbsoluteX();
      }

      highestLine = line &gt; highestLine ? line : highestLine;
      lowestLine = line &lt; lowestLine ? line : lowestLine;

      <span class="hljs-keyword">if</span> (notehead.isDisplaced()) {
        highestDisplacedLine = (highestDisplacedLine === <span class="hljs-literal">false</span>) ?
          line : <span class="hljs-built_in">Math</span>.max(line, highestDisplacedLine);
        lowestDisplacedLine = (lowestDisplacedLine === <span class="hljs-literal">false</span>) ?
          line : <span class="hljs-built_in">Math</span>.min(line, lowestDisplacedLine);
      } <span class="hljs-keyword">else</span> {
        highestNonDisplacedLine = <span class="hljs-built_in">Math</span>.max(line, highestNonDisplacedLine);
        lowestNonDisplacedLine = <span class="hljs-built_in">Math</span>.min(line, lowestNonDisplacedLine);
      }
    }, <span class="hljs-keyword">this</span>);

    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">y_top</span>: yTop,
      <span class="hljs-attr">y_bottom</span>: yBottom,
      <span class="hljs-attr">displaced_x</span>: displacedX,
      <span class="hljs-attr">non_displaced_x</span>: nonDisplacedX,
      <span class="hljs-attr">highest_line</span>: highestLine,
      <span class="hljs-attr">lowest_line</span>: lowestLine,
      <span class="hljs-attr">highest_displaced_line</span>: highestDisplacedLine,
      <span class="hljs-attr">lowest_displaced_line</span>: lowestDisplacedLine,
      <span class="hljs-attr">highest_non_displaced_line</span>: highestNonDisplacedLine,
      <span class="hljs-attr">lowest_non_displaced_line</span>: lowestNonDisplacedLine,
    };
  }</pre></div>
        
      
        
        <p>Get the starting <code>x</code> coordinate for the noteheads</p>

        
          <div class='highlight'><pre>  getNoteHeadBeginX() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getAbsoluteX() + <span class="hljs-keyword">this</span>.x_shift;
  }</pre></div>
        
      
        
        <p>Get the ending <code>x</code> coordinate for the noteheads</p>

        
          <div class='highlight'><pre>  getNoteHeadEndX() {
    <span class="hljs-keyword">const</span> xBegin = <span class="hljs-keyword">this</span>.getNoteHeadBeginX();
    <span class="hljs-keyword">return</span> xBegin + <span class="hljs-keyword">this</span>.getGlyphWidth();
  }</pre></div>
        
      
        
        <p>Draw the ledger lines between the stave and the highest/lowest keys</p>

        
          <div class='highlight'><pre>  drawLedgerLines() {
    <span class="hljs-keyword">const</span> {
      stave, glyph,
      <span class="hljs-attr">render_options</span>: { stroke_px },
      <span class="hljs-attr">context</span>: ctx,
    } = <span class="hljs-keyword">this</span>;

    <span class="hljs-keyword">const</span> width = glyph.getWidth() + (stroke_px * <span class="hljs-number">2</span>);
    <span class="hljs-keyword">const</span> doubleWidth = <span class="hljs-number">2</span> * (glyph.getWidth() + stroke_px) - (Stem.WIDTH / <span class="hljs-number">2</span>);

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isRest()) <span class="hljs-keyword">return</span>;
    <span class="hljs-keyword">if</span> (!ctx) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoCanvasContext'</span>, <span class="hljs-string">"Can't draw without a canvas context."</span>);
    }

    <span class="hljs-keyword">const</span> {
      highest_line,
      lowest_line,
      highest_displaced_line,
      highest_non_displaced_line,
      lowest_displaced_line,
      lowest_non_displaced_line,
      displaced_x,
      non_displaced_x,
    } = <span class="hljs-keyword">this</span>.getNoteHeadBounds();

    <span class="hljs-keyword">const</span> min_x = <span class="hljs-built_in">Math</span>.min(displaced_x, non_displaced_x);

    <span class="hljs-keyword">const</span> drawLedgerLine = <span class="hljs-function">(<span class="hljs-params">y, normal, displaced</span>) =&gt;</span> {
      <span class="hljs-keyword">let</span> x;
      <span class="hljs-keyword">if</span> (displaced &amp;&amp; normal) x = min_x - stroke_px;
      <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (normal) x = non_displaced_x - stroke_px;
      <span class="hljs-keyword">else</span> x = displaced_x - stroke_px;
      <span class="hljs-keyword">const</span> ledgerWidth = (normal &amp;&amp; displaced) ? doubleWidth : width;

      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(x + ledgerWidth, y);
      ctx.stroke();
    };

    <span class="hljs-keyword">const</span> style = <span class="hljs-built_in">Object</span>.assign({}, stave.getStyle() || {}, <span class="hljs-keyword">this</span>.getLedgerLineStyle() || {});
    <span class="hljs-keyword">this</span>.applyStyle(ctx, style);</pre></div>
        
      
        
        <p>Draw ledger lines below the staff:</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> line = <span class="hljs-number">6</span>; line &lt;= highest_line; ++line) {
      <span class="hljs-keyword">const</span> normal = (non_displaced_x !== <span class="hljs-literal">null</span>) &amp;&amp; (line &lt;= highest_non_displaced_line);
      <span class="hljs-keyword">const</span> displaced = (displaced_x !== <span class="hljs-literal">null</span>) &amp;&amp; (line &lt;= highest_displaced_line);
      drawLedgerLine(stave.getYForNote(line), normal, displaced);
    }</pre></div>
        
      
        
        <p>Draw ledger lines above the staff:</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> line = <span class="hljs-number">0</span>; line &gt;= lowest_line; --line) {
      <span class="hljs-keyword">const</span> normal = (non_displaced_x !== <span class="hljs-literal">null</span>) &amp;&amp; (line &gt;= lowest_non_displaced_line);
      <span class="hljs-keyword">const</span> displaced = (displaced_x !== <span class="hljs-literal">null</span>) &amp;&amp; (line &gt;= lowest_displaced_line);
      drawLedgerLine(stave.getYForNote(line), normal, displaced);
    }

    <span class="hljs-keyword">this</span>.restoreStyle(ctx, style);
  }</pre></div>
        
      
        
        <p>Draw all key modifiers</p>

        
          <div class='highlight'><pre>  drawModifiers() {
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.context) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoCanvasContext'</span>, <span class="hljs-string">"Can't draw without a canvas context."</span>);
    }

    <span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.context;
    ctx.openGroup(<span class="hljs-string">'modifiers'</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">this</span>.modifiers.length; i++) {
      <span class="hljs-keyword">const</span> modifier = <span class="hljs-keyword">this</span>.modifiers[i];
      <span class="hljs-keyword">const</span> notehead = <span class="hljs-keyword">this</span>.note_heads[modifier.getIndex()];
      <span class="hljs-keyword">const</span> noteheadStyle = notehead.getStyle();
      notehead.applyStyle(ctx, noteheadStyle);
      modifier.setContext(ctx);
      modifier.drawWithStyle();
      notehead.restoreStyle(ctx, noteheadStyle);
    }
    ctx.closeGroup();
  }</pre></div>
        
      
        
        <p>Draw the flag for the note</p>

        
          <div class='highlight'><pre>  drawFlag() {
    <span class="hljs-keyword">const</span> { stem, beam, <span class="hljs-attr">context</span>: ctx } = <span class="hljs-keyword">this</span>;

    <span class="hljs-keyword">if</span> (!ctx) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoCanvasContext'</span>, <span class="hljs-string">"Can't draw without a canvas context."</span>);
    }

    <span class="hljs-keyword">const</span> shouldRenderFlag = beam === <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">const</span> glyph = <span class="hljs-keyword">this</span>.getGlyph();

    <span class="hljs-keyword">if</span> (glyph.flag &amp;&amp; shouldRenderFlag) {
      <span class="hljs-keyword">const</span> { y_top, y_bottom } = <span class="hljs-keyword">this</span>.getNoteHeadBounds();
      <span class="hljs-keyword">const</span> noteStemHeight = stem.getHeight();
      <span class="hljs-keyword">const</span> flagX = <span class="hljs-keyword">this</span>.getStemX();</pre></div>
        
      
        
        <p>FIXME: What’s with the magic +/- 2</p>

        
          <div class='highlight'><pre>      <span class="hljs-keyword">const</span> flagY = <span class="hljs-keyword">this</span>.getStemDirection() === Stem.DOWN</pre></div>
        
      
        
        <p>Down stems have flags on the left</p>

        
          <div class='highlight'><pre>        ? y_top - noteStemHeight + <span class="hljs-number">2</span></pre></div>
        
      
        
        <p>Up stems have flags on the eft.</p>

        
          <div class='highlight'><pre>        : y_bottom - noteStemHeight - <span class="hljs-number">2</span>;</pre></div>
        
      
        
        <p>Draw the Flag</p>

        
          <div class='highlight'><pre>      ctx.openGroup(<span class="hljs-string">'flag'</span>, <span class="hljs-literal">null</span>, { <span class="hljs-attr">pointerBBox</span>: <span class="hljs-literal">true</span> });
      <span class="hljs-keyword">this</span>.applyStyle(ctx, <span class="hljs-keyword">this</span>.getFlagStyle() || <span class="hljs-literal">false</span>);
      <span class="hljs-keyword">this</span>.flag.render(ctx, flagX, flagY);
      <span class="hljs-keyword">this</span>.restoreStyle(ctx, <span class="hljs-keyword">this</span>.getFlagStyle() || <span class="hljs-literal">false</span>);
      ctx.closeGroup();
    }
  }</pre></div>
        
      
        
        <p>Draw the NoteHeads</p>

        
          <div class='highlight'><pre>  drawNoteHeads() {
    <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function"><span class="hljs-params">notehead</span> =&gt;</span> {
      <span class="hljs-keyword">this</span>.context.openGroup(<span class="hljs-string">'notehead'</span>, <span class="hljs-literal">null</span>, { <span class="hljs-attr">pointerBBox</span>: <span class="hljs-literal">true</span> });
      notehead.setContext(<span class="hljs-keyword">this</span>.context).draw();
      <span class="hljs-keyword">this</span>.context.closeGroup();
    });
  }</pre></div>
        
      
        
        <p>Render the stem onto the canvas</p>

        
          <div class='highlight'><pre>  drawStem(stemStruct) {</pre></div>
        
      
        
        <p>GCR TODO: I can’t find any context in which this is called with the stemStruct
argument in the codebase or tests. Nor can I find a case where super.drawStem
is called at all. Perhaps these should be removed?</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.context) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoCanvasContext'</span>, <span class="hljs-string">"Can't draw without a canvas context."</span>);
    }

    <span class="hljs-keyword">if</span> (stemStruct) {
      <span class="hljs-keyword">this</span>.setStem(<span class="hljs-keyword">new</span> Stem(stemStruct));
    }

    <span class="hljs-keyword">this</span>.context.openGroup(<span class="hljs-string">'stem'</span>, <span class="hljs-literal">null</span>, { <span class="hljs-attr">pointerBBox</span>: <span class="hljs-literal">true</span> });
    <span class="hljs-keyword">this</span>.stem.setContext(<span class="hljs-keyword">this</span>.context).draw();
    <span class="hljs-keyword">this</span>.context.closeGroup();
  }</pre></div>
        
      
        
        <p>Draws all the <code>StaveNote</code> parts. This is the main drawing method.</p>

        
          <div class='highlight'><pre>  draw() {
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.context) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoCanvasContext'</span>, <span class="hljs-string">"Can't draw without a canvas context."</span>);
    }
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.stave) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoStave'</span>, <span class="hljs-string">"Can't draw without a stave."</span>);
    }
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.ys.length === <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'NoYValues'</span>, <span class="hljs-string">"Can't draw note without Y values."</span>);
    }

    <span class="hljs-keyword">const</span> xBegin = <span class="hljs-keyword">this</span>.getNoteHeadBeginX();
    <span class="hljs-keyword">const</span> shouldRenderStem = <span class="hljs-keyword">this</span>.hasStem() &amp;&amp; !<span class="hljs-keyword">this</span>.beam;</pre></div>
        
      
        
        <p>Format note head x positions</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.note_heads.forEach(<span class="hljs-function"><span class="hljs-params">notehead</span> =&gt;</span> notehead.setX(xBegin));</pre></div>
        
      
        
        <p>Format stem x positions</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">const</span> stemX = <span class="hljs-keyword">this</span>.getStemX();
    <span class="hljs-keyword">this</span>.stem.setNoteHeadXBounds(stemX, stemX);

    L(<span class="hljs-string">'Rendering '</span>, <span class="hljs-keyword">this</span>.isChord() ? <span class="hljs-string">'chord :'</span> : <span class="hljs-string">'note :'</span>, <span class="hljs-keyword">this</span>.keys);</pre></div>
        
      
        
        <p>Draw each part of the note</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.drawLedgerLines();</pre></div>
        
      
        
        <p>Apply the overall style – may be contradicted by local settings:</p>

        
          <div class='highlight'><pre>    <span class="hljs-keyword">this</span>.applyStyle();
    <span class="hljs-keyword">this</span>.setAttribute(<span class="hljs-string">'el'</span>, <span class="hljs-keyword">this</span>.context.openGroup(<span class="hljs-string">'stavenote'</span>, <span class="hljs-keyword">this</span>.getAttribute(<span class="hljs-string">'id'</span>)));
    <span class="hljs-keyword">this</span>.context.openGroup(<span class="hljs-string">'note'</span>, <span class="hljs-literal">null</span>, { <span class="hljs-attr">pointerBBox</span>: <span class="hljs-literal">true</span> });
    <span class="hljs-keyword">if</span> (shouldRenderStem) <span class="hljs-keyword">this</span>.drawStem();
    <span class="hljs-keyword">this</span>.drawNoteHeads();
    <span class="hljs-keyword">this</span>.drawFlag();
    <span class="hljs-keyword">this</span>.context.closeGroup();
    <span class="hljs-keyword">this</span>.drawModifiers();
    <span class="hljs-keyword">this</span>.context.closeGroup();
    <span class="hljs-keyword">this</span>.restoreStyle();
    <span class="hljs-keyword">this</span>.setRendered();
  }
}</pre></div>
        
      
      <div class="fleur">h</div>
    </div>
  </div>
</body>
</html>