UNPKG

satie

Version:

A sheet music renderer for the web

143 lines (119 loc) 5.36 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 {ScoreHeader, Print} from "musicxml-interfaces"; import {createFactory, Component, DOM, PropTypes} from "react"; import {map, filter, forEach, last} from "lodash"; import * as invariant from "invariant"; import {IModel, generateModelKey} from "./document"; import {tenthsToMM} from "./private_renderUtil"; import {getPageMargins} from "./private_print"; import {IMeasureLayout} from "./private_measureLayout"; import MeasureView from "./implMeasure_measureView"; import CreditView from "./implPage_creditView"; const $MeasureView = createFactory(MeasureView); const $CreditView = createFactory(CreditView); export interface IProps { scoreHeader: ScoreHeader; print: Print; lineLayouts: IMeasureLayout[][]; renderTarget: "svg-web" | "svg-export"; className: string; singleLineMode?: boolean; onPageHeightChanged?: (pageHeight: number) => void; svgRef?: (svg: SVGSVGElement) => void; } export default class Page extends Component<IProps, void> { static childContextTypes = { originY: PropTypes.number.isRequired, renderTarget: PropTypes.oneOf(["svg-web", "svg-export"]).isRequired, scale40: PropTypes.number.isRequired } as any; _pageHeight = NaN; render(): any { /*--- Staves ----------------------------------------------*/ const lineLayouts = this.props.lineLayouts; /*--- General ---------------------------------------------*/ const print = this.props.print; const pageNum = parseInt(print.pageNumber, 10); invariant(pageNum >= 1, "Page %s isn't a valid page number.", print.pageNumber); const defaults = this.props.scoreHeader.defaults; const credits = filter(this.props.scoreHeader.credits, cr => (cr.page === pageNum)); const scale40 = defaults.scaling.millimeters / defaults.scaling.tenths * 40; const pageLayout = print.pageLayout; const widthMM = this.props.renderTarget === "svg-export" ? tenthsToMM(scale40, pageLayout.pageWidth) + "mm" : "100%"; const heightMM = this.props.renderTarget === "svg-export" ? tenthsToMM(scale40, pageLayout.pageHeight) + "mm" : "100%"; const pageWidth = this.props.singleLineMode ? last(lineLayouts[0]).originX + last(lineLayouts[0]).width + getPageMargins(pageLayout.pageMargins, 0).rightMargin : pageLayout.pageWidth; const pageHeight = pageLayout.pageHeight; if (pageHeight !== this._pageHeight && this.props.onPageHeightChanged) { this._pageHeight = pageHeight; setTimeout(() => { this.props.onPageHeightChanged(pageHeight); }); } /*--- Credits ---------------------------------------------*/ // Make sure our credits are keyed. forEach<IModel>(credits as any as IModel[], generateModelKey); /*--- Render ----------------------------------------------*/ return DOM.svg( { className: this.props.className, style: this.props.renderTarget === "svg-export" ? undefined : { width: "auto", }, "data-page": this.props.renderTarget === "svg-export" ? undefined : print.pageNumber, height: heightMM, ref: this._setSVG, viewBox: `0 0 ${pageWidth} ${pageHeight}`, width: widthMM } as any, !this.props.singleLineMode && map(credits, $CreditView), map(lineLayouts, (lineLayout, lineIdx) => map(lineLayout, measureLayout => $MeasureView({ key: measureLayout.uuid, layout: measureLayout, version: measureLayout.getVersion(), }) ) ) ); } private _setSVG: (svg: SVGSVGElement) => void = (svg) => { if (this.props.svgRef) { this.props.svgRef(svg); }; }; getChildContext() { const defaults = this.props.scoreHeader.defaults; const print = this.props.print; const scale40 = defaults.scaling.millimeters / defaults.scaling.tenths * 40; return { originY: print.pageLayout.pageHeight, renderTarget: this.props.renderTarget, scale40: scale40 }; } }