import Vex from "vexflow" ; import { GraphicalNote } from "../GraphicalNote" ; import { GraphicalStaffEntry } from "../GraphicalStaffEntry" ; import { VexFlowMeasure } from "./VexFlowMeasure" ; import { SourceStaffEntry } from "../../VoiceData/SourceStaffEntry" ; import { unitInPixels } from "./VexFlowMusicSheetDrawer" ; import { VexFlowVoiceEntry } from "./VexFlowVoiceEntry" ; import { Note } from "../../VoiceData/Note" ; import { AccidentalEnum } from "../../../Common/DataObjects/Pitch" ; export class VexFlowStaffEntry extends GraphicalStaffEntry { constructor ( measure , sourceStaffEntry , staffEntryParent ) { super ( measure , sourceStaffEntry , staffEntryParent ) ; } public vfClefBefore : Vex . Flow . ClefNote ; /**
     * Calculates the staff entry positions from the VexFlow stave information and the tickabels inside the staff.
     * This is needed in order to set the OSMD staff entries (which are almost the same as tickables) to the correct positions.
     * It is also needed to be done after formatting!
     */ public calculateXPosition ( ) { const stave = ( this . parentMeasure as VexFlowMeasure ) . getVFStave ( ) ; let lastBorderLeft = 0 ; for ( const gve of this . graphicalVoiceEntries as VexFlowVoiceEntry [ ] ) { if ( gve . vfStaveNote ) { gve . vfStaveNote . setStave ( stave ) ; if ( ! gve . vfStaveNote . preFormatted ) { continue ; } gve . applyBordersFromVexflow ( ) ; if ( this . parentMeasure . ParentStaff . isTab ) { this . PositionAndShape . RelativePosition . x = ( gve . vfStaveNote . getAbsoluteX ( ) + ( < any > gve . vfStaveNote ) . glyph . getWidth ( ) ) / unitInPixels ; } else { this . PositionAndShape . RelativePosition . x = gve . vfStaveNote . getBoundingBox ( ) . getX ( ) / unitInPixels ; } const sourceNote = gve . notes [ 0 ] . sourceNote ; if ( sourceNote . isRest ( ) && sourceNote . Length . RealValue === this . parentMeasure . parentSourceMeasure . ActiveTimeSignature . RealValue ) { this . PositionAndShape . RelativePosition . x += this . parentMeasure . parentSourceMeasure . Rules . WholeRestXShiftVexflow - 0.1 ; gve . PositionAndShape . BorderLeft = - 0.7 ; gve . PositionAndShape . BorderRight = 0.7 ; } if ( gve . PositionAndShape . BorderLeft < lastBorderLeft ) { lastBorderLeft = gve . PositionAndShape . BorderLeft ; } } } this . PositionAndShape . RelativePosition . x -= lastBorderLeft ; this . PositionAndShape . calculateBoundingBox ( ) ; } public setMaxAccidentals ( ) { for ( const gve of this . graphicalVoiceEntries ) { for ( const note of gve . notes ) { if ( note . DrawnAccidental !== AccidentalEnum . NONE ) { return this . MaxAccidentals = 1 ; } } } return this . MaxAccidentals = 0 ; } public setModifierXOffsets ( ) { let notes = [ ] ; for ( const gve of this . graphicalVoiceEntries ) { notes = notes . concat ( gve . notes ) ; } const staffLines = notes . map ( n => n . staffLine ) ; const stringNumberOffsets = this . calculateModifierXOffsets ( staffLines , 1 ) ; const fingeringOffsets = this . calculateModifierXOffsets ( staffLines , 0.5 ) ; notes . forEach ( ( note , i ) => { note . baseFingeringXOffset = fingeringOffsets [ i ] ; note . baseStringNumberXOffset = stringNumberOffsets [ i ] ; } ) ; } /**
     * Calculate x offsets for overlapping string and fingering modifiers in a chord.
     */ private calculateModifierXOffsets ( staffLines , collisionDistance ) { const offsets = [ ] ; for ( let i = 0 ; i < staffLines . length ; i ++ ) { let offset = 0 ; let collisionFound = true ; while ( collisionFound ) { for ( let j = i ; j >= 0 ; j -- ) { const lineDiff = Math . abs ( staffLines [ i ] - staffLines [ j ] ) ; if ( lineDiff <= collisionDistance && offset === offsets [ j ] ) { offset ++ ; collisionFound = true ; break ; } collisionFound = false ; } } offsets . push ( offset ) ; } return offsets ; } }