OpenSheetMusicDisplay
    Preparing search index...

    Class GeometricSkyBottomLineContext

    A virtual VexFlow rendering context that computes the vertical extents (min and max y) of everything drawn into it, per (pixel) column, instead of rasterizing to a canvas.

    This is used by SkyBottomLineCalculator to calculate the skyline and bottom-line of a measure geometrically from the same VexFlowMeasure.draw() call that was previously made on a hidden canvas, without the very expensive CanvasRenderingContext2D.getImageData() call (GPU->CPU transfer) and without rasterizing/allocating a canvas at all. (see #937)

    It implements the subset of the CanvasRenderingContext2D interface that VexFlow 1.2.93 uses, plus the extra methods VexFlow adds in Renderer.bolsterCanvasContext() (setFont, setFillStyle, openGroup, etc., see VexFlow's canvascontext.js).

    Accuracy notes compared to the pixel-based (raster) method:

    • Values are exact geometry instead of pixel indices, i.e. not quantized to integers and without the up-to-1px anti-aliasing halo of the raster method. Differences are well below 1px (0.1 units).
    • Where a shape's edge lies (almost) exactly on a pixel column boundary (e.g. the tangent of a notehead ellipse, or a stem edge), the rasterizer can round the sliver of coverage down to nothing, while this context includes the column. Conservative, at most one extra pixel column per edge.
    • Text is merged from per-character ink extents (probed once per font + character from a tiny canvas, see probeCharacterInk()). Font hinting can shift rasterized glyph edges by up to a pixel depending on the fractional pen position, which is not predictable; the unrounded extents used here are conservative.
    • Completely transparent fills/strokes (e.g. "#00000000" used for invisible elements) are skipped, like in the raster method, where the alpha > 0 pixel test ignored them.
    • clearRect() (only used by VexFlow's TabNote to erase stave lines behind fret numbers) is a no-op, so this context keeps the bottom stave line of tablatures solid, while the raster method saw holes in it, which even shifted its relative anchoring of the whole bottom line by ~0.2 units on tab staves. The geometric (solid) result is the more correct one.
    • The raster method clipped contents above/below its 300px canvas (~10 units above the stave). This context has no such limit, which is more correct for extreme cases.
    • Drawing is clipped horizontally to [0, width) like on the per-measure canvas of the raster method.
    • Dashed/dotted strokes are treated as solid lines (conservative). Miter join spikes of stroked multi-segment paths are not modeled (only relevant for sharp angles, which VexFlow doesn't stroke).
    Index

    Constructors

    Properties

    canvas: { height: number; width: number } = ...

    Mimics CanvasRenderingContext2D.canvas (width/height only). Some code checks for its existence.

    vexFlowCanvasContext: GeometricSkyBottomLineContext = ...

    Set by VexFlow's Renderer.bolsterCanvasContext() pattern, some code accesses ctx.vexFlowCanvasContext.

    Accessors

    Methods

    • Parameters

      • x: number
      • y: number
      • radius: number
      • startAngle: number
      • endAngle: number
      • antiClockwise: boolean = false

      Returns void

    • Parameters

      • cp1x: number
      • cp1y: number
      • cp2x: number
      • cp2y: number
      • x: number
      • y: number

      Returns void

    • Only used by VexFlow's TabNote to erase the stave lines behind fret numbers, which never affects the extents (skyline/bottom-line). Erasing is not supported by this context.

      Parameters

      • x: number
      • y: number
      • width: number
      • height: number

      Returns void

    • Writes the computed extents into the given skyline/bottomline arrays (in device pixels, indexed by pixel column), in the same format the raster method produced them: columns where nothing was drawn are left undefined.

      Parameters

      • skyLine: number[]
      • bottomLine: number[]

      Returns void

    • Fast path for glyphs, called by VexFlow's (patched) Glyph.renderOutline() instead of issuing the outline's dozens of path commands: merges the glyph outline's flattened line segments, cached once per outline + scale (the curve flattening and command parsing are the expensive part of glyph drawing, and the same glyphs repeat constantly: noteheads, accidentals, ...). The merged segments are identical to the ones the normal path commands would produce, so the result is exactly the same. Returns true if handled (VexFlow then skips the normal path commands).

      Parameters

      • outline: object
      • scale: number
      • xPos: number
      • yPos: number

      Returns boolean

    • For min/max per column, the fill of a closed path has the same extents as its outline: the topmost/bottommost filled point of a column always lies on the path boundary (holes like in half note noteheads never contain a column's extremes).

      Returns void

    • Merges the ink extents of the text, character by character (a single box for the whole string would e.g. claim ascender height above lowercase letters, unlike the rasterized text the raster method saw, which has per-character contours).

      Parameters

      • text: string
      • x: number
      • y: number

      Returns void