Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronDavidNewman committed Sep 6, 2021
2 parents fbafe0d + acfb120 commit 57463a6
Show file tree
Hide file tree
Showing 23 changed files with 411 additions and 156 deletions.
25 changes: 8 additions & 17 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,31 @@
"parserOptions": {
"project": "tsconfig.json"
},
"plugins": [
"@typescript-eslint",
"prettier"
],
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"no-console": 1, // Means warning
"prettier/prettier": 2 // Means error
},
"overrides": [
{
"files": [ "**/*.ts" ],
"files": ["**/*.ts"],
"extends": [
"eslint:recommended",
"prettier",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-inferrable-types": "off"
}
},
{
"files": [ "src/**/*.js" ],
"extends": [
"eslint:recommended",
"prettier"
]
"files": ["src/**/*.js"],
"extends": ["eslint:recommended", "prettier"]
},
{
"files": [ "tests/**/*.js" ],
"extends": [
"eslint:recommended",
"prettier"
],
"files": ["tests/**/*.js"],
"extends": ["eslint:recommended", "prettier"],
"rules": {
"no-restricted-globals": 0,
"no-undef": 0,
Expand Down
9 changes: 8 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ module.exports = (grunt) => {
library: libraryName,
libraryTarget: 'umd',
libraryExport: 'default',
globalObject: `typeof window !== 'undefined' ? window : this`,
// Support different ways of loading VexFlow.
// The `globalObject` string is assigned to `root` in line 15 of vexflow-debug.js.
// VexFlow is exported as root["Vex"], and can be accessed via:
// - `window.Vex` in browsers
// - `globalThis.Vex` in node JS >= 12
// - `this.Vex` in all other environments
// See: https://webpack.js.org/configuration/output/#outputglobalobject
globalObject: `typeof window !== 'undefined' ? window : typeof globalThis !== 'undefined' ? globalThis : this`,
publicPath: 'auto',
},
resolve: {
Expand Down
22 changes: 22 additions & 0 deletions demos/modules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Using VexFlow with ES Modules

Use `test.sh`to build and copy `vexflow-debug.js` into this folder. Or do this manually:

```
grunt
cp ../../build/vexflow-debug.js vexflow-debug.js
```

Start a web server in this folder.

```
npx http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
Hit CTRL-C to stop the server
```

Then load the `index.html` in a browser by visiting http://127.0.0.1:8080.
31 changes: 31 additions & 0 deletions demos/modules/index.classic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<body>
<div id="output"></div>
<p>VexFlow Build: <span id="info"></span></p>
<p>See also: <a href="index.html">index.html</a></p>
<script src="vexflow-debug.js"></script>
<script>
document.querySelector('#info').innerText = Vex.Flow.BUILD;

const vf = new Vex.Flow.Factory({
renderer: { elementId: 'output', width: 500, height: 200 },
});

const score = vf.EasyScore();
const system = vf.System();

system
.addStave({
voices: [
score.voice(score.notes('C#5/q, B4, A4, G#4', { stem: 'up' })),
score.voice(score.notes('C#4/h, C#4', { stem: 'down' })),
],
})
.addClef('treble')
.addTimeSignature('4/4');

vf.draw();
</script>
</body>
</html>
31 changes: 31 additions & 0 deletions demos/modules/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<body>
<div id="output"></div>
<p>VexFlow Build: <span id="info"></span></p>
<p>See also: <a href="index.classic.html">index.classic.html</a></p>
<script type="module" src="vexflow-debug.js"></script>
<script type="module">
document.querySelector('#info').innerText = Vex.Flow.BUILD;

const vf = new Vex.Flow.Factory({
renderer: { elementId: 'output', width: 500, height: 200 },
});

const score = vf.EasyScore();
const system = vf.System();

system
.addStave({
voices: [
score.voice(score.notes('C#5/q, B4, A4, G#4', { stem: 'up' })),
score.voice(score.notes('C#4/h, C#4', { stem: 'down' })),
],
})
.addClef('treble')
.addTimeSignature('4/4');

vf.draw();
</script>
</body>
</html>
19 changes: 19 additions & 0 deletions demos/modules/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Build vexflow-debug.js if it does not exist.
BUILD_FILE=../../build/vexflow-debug.js
LOCAL_FILE=vexflow-debug.js

if [ ! -f "$LOCAL_FILE" ]; then
printf "\n$LOCAL_FILE not found. Copy it from the build folder.\n"

if [ ! -f "$BUILD_FILE" ]; then
printf "\n$BUILD_FILE not found. Running grunt.\n\n"
grunt
fi

# Copy vexflow-debug.js into this folder.
cp $BUILD_FILE $LOCAL_FILE
fi

# Launch a web server to test index.html and index.classic.html
npx http-server
2 changes: 2 additions & 0 deletions demos/node/canvas.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// node canvas.js > output.html

/* eslint-disable no-console */

const { createCanvas } = require('canvas');
const Vex = require('../../build/vexflow-debug');
const VF = Vex.Flow;
Expand Down
23 changes: 23 additions & 0 deletions demos/node/import/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// node index.js

/* eslint-disable no-console */

import Vex from '../../../build/vexflow-debug.js';

// If you copy vexflow-debug.js to this folder and then update the import as follows:
// import Vex from './vexflow-debug.js';
// It will fail with error:
// SyntaxError: The requested module './vexflow-debug.js' does not provide an export named 'default'
// This is because this folder includes a package.json which indicates that all JS files should be treated as ES6 modules.
// To fix this, append the following to the end of vexflow-debug.js:
// export default Vex;
// However, doing so will make vexflow-debug.js incompatible with classic <script src="..."></script> tags.

// console.log(this); // this === undefined
// console.log(window); // ReferenceError: window is not defined
// console.log(self); // ReferenceError: self is not defined
// console.log(global); // success! global is the Node JS global object.
// console.log(globalThis); // success! globalThis is the Node JS global object.
// console.log(globalThis === global); // true

console.log('VexFlow BUILD: ' + Vex.Flow.BUILD);
5 changes: 5 additions & 0 deletions demos/node/import/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "modules-demo",
"version": "1.0.0",
"type": "module"
}
9 changes: 9 additions & 0 deletions demos/node/legacy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// node legacy.js
//
// Older versions of Node JS (e.g. v11.15.0) do not support globalThis.
// This demonstrates that VexFlow can be imported even if globalThis is not available.

/* eslint-disable no-console */

const Vex = require('../../build/vexflow-debug');
console.log(Vex);
2 changes: 2 additions & 0 deletions demos/node/svg.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// node svg.js > output.svg

/* eslint-disable no-console */

const Vex = require('../../build/vexflow-debug');
const { JSDOM } = require('jsdom');
const fs = require('fs');
Expand Down
26 changes: 14 additions & 12 deletions src/canvascontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,24 @@ export class CanvasContext implements RenderContext {
static get WIDTH(): number {
return 600;
}

static get HEIGHT(): number {
return 400;
}

static get CANVAS_BROWSER_SIZE_LIMIT(): number {
return 32767; // Chrome/Firefox. Could be determined more precisely by npm module canvas-size.
}

static SanitizeCanvasDims(width: number, height: number): [number, number] {
if (Math.max(width, height) > this.CANVAS_BROWSER_SIZE_LIMIT) {
warn('Canvas dimensions exceed browser limit. Cropping to ' + this.CANVAS_BROWSER_SIZE_LIMIT);
if (width > this.CANVAS_BROWSER_SIZE_LIMIT) {
width = this.CANVAS_BROWSER_SIZE_LIMIT;
// note: Math.min return 0 for undefined, NaN for null. Would change inputs.
const limit = this.CANVAS_BROWSER_SIZE_LIMIT;
if (Math.max(width, height) > limit) {
warn('Canvas dimensions exceed browser limit. Cropping to ' + limit);
if (width > limit) {
width = limit;
}
if (height > this.CANVAS_BROWSER_SIZE_LIMIT) {
height = this.CANVAS_BROWSER_SIZE_LIMIT;
if (height > limit) {
height = limit;
}
}
return [width, height];
Expand Down Expand Up @@ -145,11 +147,11 @@ export class CanvasContext implements RenderContext {
return this;
}

// renderer.js calls ctx.scale() instead, so this method is never used.
// CanvasRenderingContext2D does not have a resize function.
// renderer.ts calls ctx.scale() instead, so this method is never used.
// eslint-disable-next-line
resize(width: number, height: number): this {
// Do nothing for now.
// CanvasRenderingContext2D does not have a resize function.
// DO NOTHING.
return this;
}

Expand Down Expand Up @@ -199,9 +201,9 @@ export class CanvasContext implements RenderContext {
return this;
}

// CanvasRenderingContext2D does not have a glow function.
glow(): this {
// Do nothing for now.
// CanvasRenderingContext2D does not have a glow function.
// DO NOTHING.
return this;
}

Expand Down
2 changes: 1 addition & 1 deletion src/modifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class Modifier extends Element {

/** Called when position changes. */
protected reset(): void {
// do nothing
// DO NOTHING.
}

/**
Expand Down
47 changes: 29 additions & 18 deletions src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export type ContextBuilder = typeof Renderer.getSVGContext | typeof Renderer.get
* Support Canvas & SVG rendering contexts.
*/
export class Renderer {
protected elementId?: string | HTMLCanvasElement;
protected element: HTMLCanvasElement;
protected elementId?: string;
protected element: HTMLCanvasElement | HTMLDivElement;
protected backend: number;

protected ctx: RenderContext;
Expand Down Expand Up @@ -43,7 +43,7 @@ export class Renderer {
static lastContext?: RenderContext = undefined;

static buildContext(
elementId: string | HTMLCanvasElement,
elementId: string,
backend: number,
width: number,
height: number,
Expand Down Expand Up @@ -145,23 +145,34 @@ export class Renderer {
context.stroke();
}

constructor(elementId: string | HTMLCanvasElement, backend: number) {
if (!elementId) {
/**
* @param canvasId can be:
* - a string element ID (of a canvas or div element)
* - a canvas element
* - a div element, which will contain the SVG output
* @param backend Renderer.Backends.CANVAS or Renderer.Backends.SVG
*/
constructor(canvasId: string | HTMLCanvasElement | HTMLDivElement, backend: number) {
if (!canvasId) {
throw new RuntimeError('BadArgument', 'Invalid id for renderer.');
} else if (typeof canvasId === 'string') {
this.elementId = canvasId;
this.element = document.getElementById(canvasId as string) as HTMLCanvasElement | HTMLDivElement;
} else if ('getContext' in canvasId /* HTMLCanvasElement */) {
this.element = canvasId as HTMLCanvasElement;
} else {
// Assume it's a HTMLDivElement.
this.element = canvasId as HTMLDivElement;
}

this.element =
typeof elementId === 'string' && typeof document !== 'undefined'
? (document.getElementById(elementId as string) as HTMLCanvasElement)
: (elementId as HTMLCanvasElement);

// Verify backend and create context
this.backend = backend;
if (this.backend === Renderer.Backends.CANVAS) {
if (!this.element?.getContext) {
throw new RuntimeError('BadElement', `Can't get canvas context from element: ${elementId}`);
const canvasElement = this.element as HTMLCanvasElement;
if (!canvasElement.getContext) {
throw new RuntimeError('BadElement', `Can't get canvas context from element: ${canvasId}`);
}
this.ctx = Renderer.bolsterCanvasContext(this.element.getContext('2d'));
this.ctx = Renderer.bolsterCanvasContext(canvasElement.getContext('2d'));
} else if (this.backend === Renderer.Backends.SVG) {
this.ctx = new SVGContext(this.element);
} else {
Expand All @@ -171,16 +182,16 @@ export class Renderer {

resize(width: number, height: number): this {
if (this.backend === Renderer.Backends.CANVAS) {
const canvasElement = this.element as HTMLCanvasElement;
[width, height] = CanvasContext.SanitizeCanvasDims(width, height);

const devicePixelRatio = window.devicePixelRatio || 1;

this.element.width = width * devicePixelRatio;
this.element.height = height * devicePixelRatio;
this.element.style.width = width + 'px';
this.element.style.height = height + 'px';
canvasElement.width = width * devicePixelRatio;
canvasElement.height = height * devicePixelRatio;
canvasElement.style.width = width + 'px';
canvasElement.style.height = height + 'px';

this.ctx = Renderer.bolsterCanvasContext(this.element.getContext('2d'));
this.ctx.scale(devicePixelRatio, devicePixelRatio);
} else {
this.ctx.resize(width, height);
Expand Down
2 changes: 1 addition & 1 deletion src/stavemodifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@ export class StaveModifier extends Element {

// eslint-disable-next-line
draw(element?: Element, x_shift?: number): void {
// do nothing
// DO NOTHING.
}
}
Loading

0 comments on commit 57463a6

Please sign in to comment.