VexFlow - Copyright (c) Mohit Muthanna 2010. @author Mohit Cheppudira
This file implements a generic base class for VexFlow, with implementations of general functions and properties that can be inherited by all VexFlow elements.
import { Vex } from './vex';
import { Registry } from './registry';
import { Flow } from './tables';
export class Element {
static newID() { return 'auto' + (Element.ID++); }
constructor({ type } = {}) {
this.attrs = {
id: Element.newID(),
el: null,
type: type || 'Base',
classes: {},
};
this.boundingBox = null;
this.context = null;
this.rendered = false;
this.fontStack = Flow.DEFAULT_FONT_STACK;
this.musicFont = Flow.DEFAULT_FONT_STACK[0];
If a default registry exist, then register with it right away.
if (Registry.getDefaultRegistry()) {
Registry.getDefaultRegistry().register(this);
}
}
set music font
setFontStack(fontStack) {
this.fontStack = fontStack;
this.musicFont = fontStack[0];
return this;
}
getFontStack() {
return this.fontStack;
}
set the draw style of a stemmable note:
setStyle(style) { this.style = style; return this; }
getStyle() { return this.style; }
Apply current style to Canvas context
applyStyle(context = this.context, style = this.getStyle()) {
if (!style) return this;
context.save();
if (style.shadowColor) context.setShadowColor(style.shadowColor);
if (style.shadowBlur) context.setShadowBlur(style.shadowBlur);
if (style.fillStyle) context.setFillStyle(style.fillStyle);
if (style.strokeStyle) context.setStrokeStyle(style.strokeStyle);
if (style.lineWidth) context.setLineWidth(style.lineWidth);
return this;
}
restoreStyle(context = this.context, style = this.getStyle()) {
if (!style) return this;
context.restore();
return this;
}
draw with style of an element.
drawWithStyle() {
this.checkContext();
this.applyStyle();
this.draw();
this.restoreStyle();
}
An element can have multiple class labels.
hasClass(className) { return (this.attrs.classes[className] === true); }
addClass(className) {
this.attrs.classes[className] = true;
if (this.registry) {
this.registry.onUpdate({
id: this.getAttribute('id'),
name: 'class',
value: className,
oldValue: null,
});
}
return this;
}
removeClass(className) {
delete this.attrs.classes[className];
if (this.registry) {
this.registry.onUpdate({
id: this.getAttribute('id'),
name: 'class',
value: null,
oldValue: className,
});
}
return this;
}
This is called by the registry after the element is registered.
onRegister(registry) { this.registry = registry; return this; }
isRendered() { return this.rendered; }
setRendered(rendered = true) { this.rendered = rendered; return this; }
getAttributes() { return this.attrs; }
getAttribute(name) { return this.attrs[name]; }
setAttribute(name, value) {
const id = this.attrs.id;
const oldValue = this.attrs[name];
this.attrs[name] = value;
if (this.registry) {
Register with old id to support id changes.
this.registry.onUpdate({ id, name, value, oldValue });
}
return this;
}
getContext() { return this.context; }
setContext(context) { this.context = context; return this; }
getBoundingBox() { return this.boundingBox; }
Validators
checkContext() {
if (!this.context) {
throw new Vex.RERR('NoContext', 'No rendering context attached to instance');
}
return this.context;
}
}
Element.ID = 1000;