UNPKG

abcjs

Version:

Renderer for abc music notation

188 lines (166 loc) 7.29 kB
// abc_renderer.js: API to render to SVG/Raphael/whatever rendering engine /*global Math */ var spacing = require('./helpers/spacing'); var Svg = require('./svg'); /** * Implements the API for rendering ABCJS Abstract Rendering Structure to a canvas/paper (e.g. SVG, Raphael, etc) * @param {Object} paper */ var Renderer = function (paper) { this.paper = new Svg(paper); this.controller = null; this.space = 3 * spacing.SPACE; this.padding = {}; // renderer's padding is managed by the controller this.reset(); }; Renderer.prototype.reset = function () { this.paper.clear(); this.y = 0; this.abctune = null; this.path = null; this.isPrint = false; this.lineThickness = 0; this.initVerticalSpace(); }; Renderer.prototype.newTune = function (abcTune) { this.abctune = abcTune; // TODO-PER: this is just to get the font info. this.setVerticalSpace(abcTune.formatting); //this.measureNumber = null; //this.noteNumber = null; this.isPrint = abcTune.media === 'print'; this.setPadding(abcTune); }; Renderer.prototype.setLineThickness = function (lineThickness) { this.lineThickness = lineThickness }; Renderer.prototype.setPaddingOverride = function (params) { this.paddingOverride = { top: params.paddingtop, bottom: params.paddingbottom, right: params.paddingright, left: params.paddingleft }; }; Renderer.prototype.setPadding = function (abctune) { // If the padding is set in the tune, then use that. // Otherwise, if the padding is set in the override, use that. // Otherwise, use the defaults (there are a different set of defaults for screen and print.) function setPaddingVariable(self, paddingKey, formattingKey, printDefault, screenDefault) { if (abctune.formatting[formattingKey] !== undefined) self.padding[paddingKey] = abctune.formatting[formattingKey]; else if (self.paddingOverride[paddingKey] !== undefined) self.padding[paddingKey] = self.paddingOverride[paddingKey]; else if (self.isPrint) self.padding[paddingKey] = printDefault; else self.padding[paddingKey] = screenDefault; } // 1cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 38px // 1.8cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 68px setPaddingVariable(this, 'top', 'topmargin', 38, 15); setPaddingVariable(this, 'bottom', 'botmargin', 38, 15); setPaddingVariable(this, 'left', 'leftmargin', 68, 15); setPaddingVariable(this, 'right', 'rightmargin', 68, 15); }; /** * Some of the items on the page are not scaled, so adjust them in the opposite direction of scaling to cancel out the scaling. * @param {float} scale */ Renderer.prototype.adjustNonScaledItems = function (scale) { this.padding.top /= scale; this.padding.bottom /= scale; this.padding.left /= scale; this.padding.right /= scale; this.abctune.formatting.headerfont.size /= scale; this.abctune.formatting.footerfont.size /= scale; }; /** * Set the the values for all the configurable vertical space options. */ Renderer.prototype.initVerticalSpace = function () { // conversion: 37.7953 = conversion factor for cm to px. // All of the following values are in px. this.spacing = { composer: 7.56, // Set the vertical space above the composer. graceBefore: 8.67, // Define the space before, inside and after the grace notes. graceInside: 10.67, graceAfter: 16, info: 0, // Set the vertical space above the infoline. lineSkipFactor: 1.1, // Set the factor for spacing between lines of text. (multiply this by the font size) music: 7.56, // Set the vertical space above the first staff. paragraphSkipFactor: 0.4, // Set the factor for spacing between text paragraphs. (multiply this by the font size) parts: 11.33, // Set the vertical space above a new part. slurHeight: 1.0, // Set the slur height factor. staffSeparation: 61.33, // Do not put a staff system closer than <unit> from the previous system. stemHeight: 26.67 + 10, // Set the stem height. subtitle: 3.78, // Set the vertical space above the subtitle. systemStaffSeparation: 48, // Do not place the staves closer than <unit> inside a system. * This values applies to all staves when in the tune header. Otherwise, it applies to the next staff text: 18.9, // Set the vertical space above the history. title: 7.56, // Set the vertical space above the title. top: 30.24, //Set the vertical space above the tunes and on the top of the continuation pages. vocal: 0, // Set the vertical space above the lyrics under the staves. words: 0 // Set the vertical space above the lyrics at the end of the tune. }; /* TODO-PER: Handle the x-coordinate spacing items, too. maxshrink <float>Default: 0.65 Set how much to compress horizontally when music line breaks are automatic. <float> must be between 0 (natural spacing) and 1 (max shrinking). // This next value is used to compute the natural spacing of // the notes. The base spacing of the crotchet is always // 40 pts. When the duration of a note type is twice the // duration of an other note type, its spacing is multiplied // by this factor. // The default value causes the note spacing to be multiplied // by 2 when its duration is multiplied by 4, i.e. the // space of the semibreve is 80 pts and the space of the // semiquaver is 20 pts. // Setting this value to 1 sets all note spacing to 40 pts. noteSpacingFactor: 1.414, // Set the note spacing factor to <float> (range 1..2). scale <float> Default: 0.75 Set the page scale factor. Note that the header and footer are not scaled. stretchlast <float>Default: 0.8 Stretch the last music line of a tune when it exceeds the <float> fraction of the page width. <float> range is 0.0 to 1.0. */ }; Renderer.prototype.setVerticalSpace = function (formatting) { // conversion from pts to px 4/3 if (formatting.staffsep !== undefined) this.spacing.staffSeparation = formatting.staffsep * 4 / 3; if (formatting.composerspace !== undefined) this.spacing.composer = formatting.composerspace * 4 / 3; if (formatting.partsspace !== undefined) this.spacing.parts = formatting.partsspace * 4 / 3; if (formatting.textspace !== undefined) this.spacing.text = formatting.textspace * 4 / 3; if (formatting.musicspace !== undefined) this.spacing.music = formatting.musicspace * 4 / 3; if (formatting.titlespace !== undefined) this.spacing.title = formatting.titlespace * 4 / 3; if (formatting.sysstaffsep !== undefined) this.spacing.systemStaffSeparation = formatting.sysstaffsep * 4 / 3; if (formatting.subtitlespace !== undefined) this.spacing.subtitle = formatting.subtitlespace * 4 / 3; if (formatting.topspace !== undefined) this.spacing.top = formatting.topspace * 4 / 3; if (formatting.vocalspace !== undefined) this.spacing.vocal = formatting.vocalspace * 4 / 3; if (formatting.wordsspace !== undefined) this.spacing.words = formatting.wordsspace * 4 / 3; }; /** * Calculates the y for a given pitch value (relative to the stave the renderer is currently printing) * @param {number} ofs pitch value (bottom C on a G clef = 0, D=1, etc.) */ Renderer.prototype.calcY = function (ofs) { return this.y - ofs * spacing.STEP; }; Renderer.prototype.moveY = function (em, numLines) { if (numLines === undefined) numLines = 1; this.y += em * numLines; }; Renderer.prototype.absolutemoveY = function (y) { this.y = y; }; module.exports = Renderer;