UNPKG

satie

Version:

A sheet music renderer for the web

202 lines (183 loc) 7.65 kB
/** * This file is part of Satie music engraver <https://github.com/jnetterf/satie>. * Copyright (C) Joshua Netterfield <joshua.ca> 2015 - present. * * Satie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Satie is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Satie. If not, see <http://www.gnu.org/licenses/>. */ import {Time, TimeSymbolType} from "musicxml-interfaces"; import {createFactory, Component, DOM, PropTypes} from "react"; import {map} from "lodash"; import Glyph from "./private_views_glyph"; import {NUMBER_SPACING, PLUS_SPACING} from "./implAttributes_attributesData"; const $Glyph = createFactory(Glyph); /* private */ class TimeSignatureNumber extends Component<ITSNumProps, void> { render() { return DOM.g(null, map((String(this.props.children)).split(""), (numberString, i) => $Glyph({ fill: this.props.stroke, glyphName: "timeSig" + numberString, key: "ts-" + i, x: this.props.x + i * 12 + (numberString === "1" ? (!i && parseInt(this.props.children, 10) >= 10 ? -1 : 1) : 0), y: this.props.y /* Glyph */})) /* DOM.g */); } } const $TimeSignatureNumber = createFactory(TimeSignatureNumber); /** * Renders a simple, compound, or common time signature. */ export default class TimeSignatureView extends Component<{spec: Time, key?: string | number}, void> { static contextTypes = { originY: PropTypes.number, } as any; context: { originY: number; }; render(): any { const spec = this.props.spec; if (spec.senzaMisura != null) { return null; } let ts = this._displayTimeSignature(); if (ts.singleNumber && ts.beats.length === 1 && ts.beats[0].length === 1) { return $TimeSignatureNumber({ stroke: spec.color, x: spec.defaultX + (spec.relativeX || 0), y: (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0)) }, ts.beats[0] ); } if (ts.commonRepresentation) { let beats = ts.beats; let beatType = ts.beatType; let hasSingleBeat = beats.length === 1 && beats[0].length === 1; let isCommon = hasSingleBeat && beats[0][0] === 4 && beatType[0] === 4; let isCut = hasSingleBeat && beats[0][0] === 2 && beatType[0] === 2; if (isCommon) { return $Glyph({ fill: spec.color, glyphName: "timeSigCommon", x: spec.defaultX + (spec.relativeX || 0), y: (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0)) }); } else if (isCut) { return $Glyph({ fill: spec.color, glyphName: "timeSigCutCommon", x: spec.defaultX + (spec.relativeX || 0), y: (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0)) }); } // Cannot be represented in common representation. Pass through. } let numOffsets = this.numOffsets(); let denOffsets = this.denOffsets(); let pos = 0; return DOM.g(null, map(ts.beats, (beatsOuter, idx) => { let array = [ map(beatsOuter, (beats, jdx) => [ $TimeSignatureNumber({ key: `num_${idx}_${jdx}`, stroke: spec.color, x: spec.defaultX + (spec.relativeX || 0) + numOffsets[idx] + pos + jdx * NUMBER_SPACING, y: (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0) + 10) }, beats ), (jdx + 1 !== beatsOuter.length) && $Glyph({ fill: "black", glyphName: "timeSigPlusSmall", key: `num_plus_numerator_${idx}_${jdx}`, x: spec.defaultX + (spec.relativeX || 0) + numOffsets[idx] + pos + jdx * NUMBER_SPACING + 17, y: (this.context.originY || 0) - (spec.defaultY) + (spec.relativeY || 0) - 10 }) ]), $TimeSignatureNumber({ key: "den", stroke: spec.color, x: spec.defaultX + (spec.relativeX || 0) + denOffsets[idx] + pos, y: (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0) - 10) }, ts.beatType[idx] ), (idx + 1 !== ts.beats.length) && $Glyph({ fill: "black", glyphName: "timeSigPlus", key: `num_plus_${idx}`, x: spec.defaultX + (spec.relativeX || 0) + numOffsets[idx] + pos + beatsOuter.length * NUMBER_SPACING - 10, y: (this.context.originY || 0) - (spec.defaultY) + (spec.relativeY || 0) }) ]; pos += beatsOuter.length * NUMBER_SPACING + PLUS_SPACING; return array; }) /* DOM.g */); } numOffsets() { // This is sketchy. let ts = this._displayTimeSignature(); return map(ts.beats, (beats, idx) => { if (beats.length > 1) { return 0; } let culm = 0; if (beats[0] < 10 && ts.beatType[idx] >= 10) { culm += 5; } return culm; }); } denOffsets() { // This is sketchy. let ts = this._displayTimeSignature(); return map(ts.beatType, (beatType, idx) => { let culm = 0; let numToDenOffset = (ts.beats[idx].length - 1) * NUMBER_SPACING / 2; culm += numToDenOffset; if (ts.beats[idx][0] >= 10 && beatType < 10) { culm += 7; } return culm; }); } _displayTimeSignature() { const spec = this.props.spec; return { beatType: spec.beatTypes, beats: map(spec.beats, beats => beats.split("+").map(n => parseInt(n, 10))), commonRepresentation: spec.symbol === TimeSymbolType.Common || spec.symbol === TimeSymbolType.Cut, singleNumber: spec.symbol === TimeSymbolType.SingleNumber }; } }; /* private */ interface ITSNumProps { key?: string | number; x: number; y: number; stroke: string; children?: string; };