satie
Version:
A sheet music renderer for the web
147 lines (129 loc) • 4.95 kB
text/typescript
/**
* 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 {Clef, SymbolSize} from "musicxml-interfaces";
import {createFactory, Component, DOM, PropTypes} from "react";
import Glyph from "./private_views_glyph";
import {bboxes} from "./private_smufl";
const $Glyph = createFactory(Glyph);
/**
* Responsible for the rendering of a clef.
*/
export default class ClefView extends Component<{spec: Clef, key?: string | number}, void> {
static contextTypes = {
originY: PropTypes.number,
} as any;
context: {
originY: number;
};
render(): any {
const spec = this.props.spec;
if (spec.printObject === false) {
return null;
}
let clefX = spec.defaultX + (spec.relativeX || 0);
let clefY = (this.context.originY || 0) - (spec.defaultY + (spec.relativeY || 0) +
(this.renderedLine() - 3) * 10);
let clefSign = this.sign();
if (!clefSign) {
return null;
}
let clefGlyph = $Glyph({
fill: spec.color,
glyphName: clefSign,
x: clefX,
y: clefY
});
let clefOctaveChange = parseInt(spec.clefOctaveChange, 10);
let clefDecorations: any[] = [];
let clefSignBox = bboxes[clefSign];
let left = clefSignBox[0];
let top = clefSignBox[1];
let right = clefSignBox[2];
let bottom = clefSignBox[3]; // The linter doesn't like destructuring yet :(
// We want it to actually touch, not just be outside the bbox
let bScalingFactor = spec.sign.toUpperCase() === "F" ? 0.7 : 1;
let topLeftOffset = spec.sign.toUpperCase() === "G" ? left * 2 : 0;
top = -top * 10 + clefY;
bottom = -bottom * 10 * bScalingFactor + clefY;
left = left * 10 + clefX;
right = right * 10 + clefX;
let decorativeX = (left + right) / 2;
if (clefOctaveChange === 2) {
clefDecorations.push($Glyph({
fill: spec.color,
glyphName: "clef15",
key: "15ma",
x: decorativeX - (bboxes["clef15"][0] * 10 +
bboxes["clef15"][2] * 10) / 2 + topLeftOffset,
y: top
}));
} else if (clefOctaveChange === 1) {
clefDecorations.push($Glyph({
fill: spec.color,
glyphName: "clef8",
key: "8va",
x: decorativeX - (bboxes["clef8"][0] * 10 +
bboxes["clef8"][2] * 10) / 2 + topLeftOffset,
y: top
}));
} else if (clefOctaveChange === -1) {
clefDecorations.push($Glyph({
fill: spec.color,
glyphName: "clef8",
key: "8vb",
x: decorativeX - (bboxes["clef8"][0] * 10 + bboxes["clef8"][2] * 10) / 2,
y: bottom + bboxes["clef8"][1] * 10
}));
} else if (clefOctaveChange === -2) {
clefDecorations.push($Glyph({
fill: spec.color,
glyphName: "clef15",
key: "15mb",
x: decorativeX - (bboxes["clef15"][0] * 10 + bboxes["clef15"][2] * 10) / 2,
y: bottom + bboxes["clef15"][1] * 10
}));
}
if (clefDecorations) {
return DOM.g(null,
clefGlyph,
clefDecorations);
} else {
return clefGlyph;
}
}
sign() {
const clef = this.props.spec.sign.toLowerCase();
if (clef === "percussion") {
return "unpitchedPercussionClef1";
} else if (clef === "tab") {
return "6stringTabClef";
} else if (clef === "none") {
return null;
} else {
return clef + "Clef" + (this.props.spec.size === SymbolSize.Cue ?
"Change" : "");
}
}
renderedLine(): number {
// The TAB glyph is higher than expected.
if (this.props.spec.sign.toLowerCase() === "tab") {
return this.props.spec.line - 2;
}
return this.props.spec.line;
}
};