Source: music21/layout.js

/**
 *
 * THIS IS CURRENTLY UNUSED
 * Does not work yet, so not documented
 *
 * @namespace music21.layout
 */
// future -- rewrite of Score and Part to Page, System, SystemPart
// not currently used
// import * as $ from 'jquery';
//
// import { base } from './base';
// import { renderOptions } from './renderOptions.js';

import * as stream from './stream.js';

/**
 * Divide a part up into systems and fix the measure
 * widths so that they are all even.
 *
 * Note that this is done on the part level even though
 * the measure widths need to be consistent across parts.
 *
 * This is possible because the system is deterministic and
 * will come to the same result for each part.  Opportunity
 * for making more efficient through this...
 *
 * @param {music21.stream.Score} score
 * @param {number} containerWidth
 * @returns {LayoutScore}
 */
export function makeLayoutFromScore(
    score,
    containerWidth
) {
    // var systemHeight = score.systemHeight; /* part.show() called... */
    // var systemPadding = score.systemPadding;
    const parts = score.parts;
    // console.log(parts);
    const numParts = parts.length;
    const partZero = parts.get(0);
    const numMeasures = partZero.getElementsByClass('Measure').length;

    const measureWidths = partZero.getMeasureWidths();
    const maxSystemWidth
        = containerWidth || score.maxSystemWidth; /* of course fix! */

    const layoutScore = new LayoutScore();
    const currentPage = new Page(); // to-do multiple pages...
    currentPage.measureStart = 1;
    currentPage.measureEnd = numMeasures;

    layoutScore.insert(0, currentPage);

    let currentSystem = new System();
    let currentSystemNumber = 1;
    currentSystem.measureStart = 1;
    let currentStaves = [];

    const staffMaker = (staffHolder, numParts, measureStart) => {
        for (let pNum = 0; pNum < numParts; pNum++) {
            const staff = new Staff();
            staff.measureStart = measureStart;
            staff.staffNumber = pNum + 1;
            staffHolder.push(staff);
        }
    };
    staffMaker(currentStaves, numParts, 1);

    // noinspection JSMismatchedCollectionQueryUpdate
    const systemCurrentWidths = [];
    // noinspection JSMismatchedCollectionQueryUpdate
    const systemBreakIndexes = [];

    let lastSystemBreak = 0; /* needed to ensure each line has at least one measure */
    const startLeft = 20; /* TODO: make it obtained elsewhere */
    let currentLeft = startLeft;
    // let currentSystemTop = 0;
    // var partTopOffsets = [];
    // const ignoreSystemsInCalculatingScoreHeight = true;
    // const systemHeight = score.estimateStreamHeight(ignoreSystemsInCalculatingScoreHeight);

    for (let i = 0; i < measureWidths.length; i++) {
        const currentRight = currentLeft + measureWidths[i];
        /* console.log("left: " + currentLeft + " ; right: " + currentRight + " ; m: " + i); */
        if (currentRight > maxSystemWidth && lastSystemBreak !== i) {
            // new system...
            for (let j = 0; j < currentStaves.length; j++) {
                currentStaves.measureEnd = i;
                currentSystem.insert(0, currentStaves[j]);
            }
            currentStaves = [];
            staffMaker(currentStaves, numParts, i + 1);
            // currentSystemTop += systemHeight;
            currentSystem.measureEnd = i;
            currentPage.insert(0, currentSystem);
            currentSystemNumber += 1;
            currentSystem = new System();
            currentSystem.measureStart = i + 1;
            currentSystem.systemNumber = currentSystemNumber;

            systemBreakIndexes.push(i - 1);
            systemCurrentWidths.push(currentLeft);
            console.log(
                'setting new width at ' + currentLeft + ' measure ' + i
            );
            currentLeft = startLeft + measureWidths[i];
            lastSystemBreak = i;
        } else {
            currentLeft = currentRight;
        }
        for (let pNum = 0; pNum < currentStaves.length; pNum++) {
            currentStaves[pNum].append(parts[pNum].get(i));
        }
    }
    for (let j = 0; j < currentStaves.length; j++) {
        currentStaves.measureEnd = measureWidths.length - 1;
        currentSystem.insert(0, currentStaves[j]);
    }
    currentPage.insert(0, currentSystem);
    return layoutScore;
}

/**
 * @extends music21.stream.Score
 * @property {number|undefined} measureStart
 * @property {number|undefined} measureEnd
 * @property {number|undefined} width
 * @property {number|undefined} height
 */
export class LayoutScore extends stream.Score {
    constructor() {
        super();
        this.scoreLayout = undefined;
        this.measureStart = undefined;
        this.measureEnd = undefined;
        /**
         *
         * @type {number|undefined}
         * @private
         */
        this._width = undefined;
        this.height = undefined;
        this.top = 0;
        this.left = 0;
    }

    get pages() {
        return this.getElementsByClass('Page');
    }

    get width() {
        if (this._width) {
            return this._width;
        } else if (this.activeSite) {
            return this.activeSite.width;
        } else {
            return undefined;
        }
    }
    // /**
    //  * return a tuple of (top, bottom) for a staff, specified by a given pageId,
    //  * systemId, and staffId in PIXELS.
    //
    //  * @param pageId
    //  * @param systemId
    //  * @param staffId
    //  * @param units -- "pixels" or "tenths" (not supported)
    //  */
    //
    // getPositionForStaff(pageId, systemId, staffId, units) {
    //     units = units || 'pixels';
    // }
}

/**
 * All music must currently be on page 1.
 *
 * @extends music21.stream.Score
 * @property {number|undefined} measureStart
 * @property {number|undefined} measureEnd
 * @property {number|undefined} systemStart
 * @property {number|undefined} systemEnd
 */
export class Page extends stream.Score {
    constructor() {
        super();
        this.pageNumber = 1;
        this.measureStart = undefined;
        this.measureEnd = undefined;
        this.systemStart = undefined;
        this.systemEnd = undefined;
        this.pageLayout = undefined;
    }

    get systems() {
        return this.getElementsByClass('System');
    }

    get width() {
        if (this._width) {
            return this._width;
        } else if (this.activeSite) {
            return this.activeSite.width;
        } else {
            return undefined;
        }
    }
}

/**
 * @extends music21.stream.Score
 * @property {number|undefined} measureStart
 * @property {number|undefined} measureEnd
 * @property {number|undefined} width
 * @property {number|undefined} height
 * @property {number|undefined} top
 * @property {number|undefined} left
 */
export class System extends stream.Score {
    constructor() {
        super();
        this.systemNumber = 1;
        this.systemLayout = undefined;
        this.measureStart = undefined;
        this.measureEnd = undefined;
        /**
         *
         * @type {number|undefined}
         * @private
         */
        this._width = undefined;
        this.height = undefined;
        this.top = undefined;
        this.left = undefined;
    }

    get staves() {
        return this.getElementsByClass('Staff');
    }

    get width() {
        if (this._width) {
            return this._width;
        } else if (this.activeSite) {
            return this.activeSite.width;
        } else {
            return undefined;
        }
    }
}

/**
 * @extends music21.stream.Score
 *
 */
export class Staff extends stream.Part {
    constructor() {
        super();
        this.staffNumber = 1;
        this.optimized = 0;
        this.top = undefined;
        this.left = undefined;
        this._width = undefined;
        this.height = undefined;
        this.inheritedHeight = undefined;
        this.staffLayout = undefined;
    }

    get width() {
        if (this._width) {
            return this._width;
        } else if (this.activeSite) {
            return this.activeSite.width;
        } else {
            return undefined;
        }
    }
}
Music21j, Copyright © 2013-2021 Michael Scott Asato Cuthbert.
Documentation generated by JSDoc 3.6.3 on Wed Jul 31st 2019 using the DocStrap template.