added various performance improvements
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import {IPublisher, Publisher} from "./Publisher";
|
import {IPublisher, ISubscription, Publisher} from "./Publisher";
|
||||||
import ISubscriber from "./Subscriber";
|
import ISubscriber from "./Subscriber";
|
||||||
|
|
||||||
export enum BeatUnitType {
|
export enum BeatUnitType {
|
||||||
@@ -24,7 +24,7 @@ export default class BeatUnit implements IPublisher<BeatUnitEvents> {
|
|||||||
this.on = on;
|
this.on = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatUnitEvents | BeatUnitEvents[]): { unbind: () => void } {
|
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatUnitEvents | BeatUnitEvents[]): ISubscription {
|
||||||
return this.publisher.addSubscriber(subscriber, eventType);
|
return this.publisher.addSubscriber(subscriber, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,29 @@
|
|||||||
import ISubscriber from "./Subscriber";
|
import ISubscriber from "./Subscriber";
|
||||||
|
|
||||||
|
class Subscription<T extends (string | number), P> implements ISubscription {
|
||||||
|
private subscriber: ISubscriber;
|
||||||
|
private readonly eventTypes: T[];
|
||||||
|
private publisher: Publisher<T, P>;
|
||||||
|
constructor(publisher: Publisher<T, P>, subscriber: ISubscriber, eventTypes: T[]) {
|
||||||
|
this.subscriber = subscriber;
|
||||||
|
this.publisher = publisher;
|
||||||
|
this.eventTypes = eventTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(): void {
|
||||||
|
this.publisher.unbind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getEventTypes(): T[] {
|
||||||
|
return this.eventTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubscriber(): ISubscriber {
|
||||||
|
return this.subscriber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Publisher<T extends (string | number), P> implements IPublisher<T> {
|
export class Publisher<T extends (string | number), P> implements IPublisher<T> {
|
||||||
private subscribers: Map<T | "all", ISubscriber[]>;
|
private subscribers: Map<T | "all", ISubscriber[]>;
|
||||||
private parent: P;
|
private parent: P;
|
||||||
@@ -10,7 +34,7 @@ export class Publisher<T extends (string | number), P> implements IPublisher<T>
|
|||||||
this.subscribers.set("all", []);
|
this.subscribers.set("all", []);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: (T | "all") | T[]): {unbind: () => void} {
|
addSubscriber(subscriber: ISubscriber, eventType: (T | "all") | T[]): ISubscription {
|
||||||
let eventTypes: (T | "all")[] = [];
|
let eventTypes: (T | "all")[] = [];
|
||||||
if (!Array.isArray(eventType)) {
|
if (!Array.isArray(eventType)) {
|
||||||
eventTypes.push(eventType);
|
eventTypes.push(eventType);
|
||||||
@@ -20,14 +44,14 @@ export class Publisher<T extends (string | number), P> implements IPublisher<T>
|
|||||||
for (const key of eventTypes) {
|
for (const key of eventTypes) {
|
||||||
this.getSubscribers(key).push(subscriber);
|
this.getSubscribers(key).push(subscriber);
|
||||||
}
|
}
|
||||||
return {
|
return new Subscription(this, subscriber, eventTypes);
|
||||||
unbind: () => {
|
}
|
||||||
for (const key of eventTypes) {
|
|
||||||
const subs = this.getSubscribers(key);
|
unbind(subscription: Subscription<T, P>): void {
|
||||||
subs.splice(subs.indexOf(subscriber), 1);
|
for (const key of subscription.getEventTypes()) {
|
||||||
}
|
const subs = this.getSubscribers(key);
|
||||||
}
|
subs.splice(subs.indexOf(subscription.getSubscriber()), 1);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSubscribers(key: T | "all"): ISubscriber[] {
|
private getSubscribers(key: T | "all"): ISubscriber[] {
|
||||||
@@ -41,7 +65,7 @@ export class Publisher<T extends (string | number), P> implements IPublisher<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notifySubs(eventType: T) {
|
notifySubs(eventType: T): void {
|
||||||
for (const sub of this.getSubscribers(eventType)) {
|
for (const sub of this.getSubscribers(eventType)) {
|
||||||
sub.notify(this.parent, eventType);
|
sub.notify(this.parent, eventType);
|
||||||
}
|
}
|
||||||
@@ -54,3 +78,7 @@ export class Publisher<T extends (string | number), P> implements IPublisher<T>
|
|||||||
export interface IPublisher<T extends string | number> {
|
export interface IPublisher<T extends string | number> {
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: (T | "all") | T[]): {unbind: () => void};
|
addSubscriber(subscriber: ISubscriber, eventType: (T | "all") | T[]): {unbind: () => void};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISubscription {
|
||||||
|
unbind(): void;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import BeatUnit, {BeatUnitEvents, BeatUnitType} from "../../../../BeatUnit";
|
import BeatUnit, {BeatUnitEvents, BeatUnitType} from "../../../../BeatUnit";
|
||||||
import ISubscriber from "../../../../Subscriber";
|
import ISubscriber from "../../../../Subscriber";
|
||||||
import UINode, {UINodeOptions} from "../../../UINode";
|
import UINode, {UINodeOptions} from "../../../UINode";
|
||||||
import {IPublisher} from "../../../../Publisher";
|
import {IPublisher, ISubscription, Publisher} from "../../../../Publisher";
|
||||||
import "./BeatUnit.css";
|
import "./BeatUnit.css";
|
||||||
|
|
||||||
export type BeatUnitUINodeOptions = UINodeOptions & {
|
export type BeatUnitUINodeOptions = UINodeOptions & {
|
||||||
@@ -10,7 +10,8 @@ export type BeatUnitUINodeOptions = UINodeOptions & {
|
|||||||
|
|
||||||
export default class BeatUnitView extends UINode implements ISubscriber {
|
export default class BeatUnitView extends UINode implements ISubscriber {
|
||||||
private beatUnit: BeatUnit;
|
private beatUnit: BeatUnit;
|
||||||
private subscription!: {unbind: () => void};
|
private subscription: ISubscription | null = null;
|
||||||
|
private publisher: IPublisher<BeatUnitEvents> = new Publisher<BeatUnitEvents, BeatUnitView>(this);
|
||||||
|
|
||||||
constructor(options: BeatUnitUINodeOptions) {
|
constructor(options: BeatUnitUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -19,13 +20,14 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setUnit(beatUnit: BeatUnit): void {
|
setUnit(beatUnit: BeatUnit): void {
|
||||||
this.subscription.unbind();
|
|
||||||
this.beatUnit = beatUnit;
|
this.beatUnit = beatUnit;
|
||||||
this.setupBindings();
|
this.setupBindings();
|
||||||
this.redraw();
|
this.notify(this.publisher, beatUnit.isOn() ? BeatUnitEvents.On : BeatUnitEvents.Off);
|
||||||
|
this.notify(this.publisher, BeatUnitEvents.TypeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupBindings() {
|
private setupBindings() {
|
||||||
|
this.subscription?.unbind();
|
||||||
this.subscription = this.beatUnit.addSubscriber(this, "all");
|
this.subscription = this.beatUnit.addSubscriber(this, "all");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,14 +45,16 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
||||||
if (event === BeatUnitEvents.On) {
|
if (event === BeatUnitEvents.On) {
|
||||||
this.node?.classList.add("beat-unit-on");
|
this.getNode().classList.add("beat-unit-on");
|
||||||
} else if (event === BeatUnitEvents.Off) {
|
} else if (event === BeatUnitEvents.Off) {
|
||||||
this.node?.classList.remove("beat-unit-on");
|
this.getNode().classList.remove("beat-unit-on");
|
||||||
} else if (event === BeatUnitEvents.TypeChange) {
|
} else if (event === BeatUnitEvents.TypeChange) {
|
||||||
if (this.beatUnit.getType() === BeatUnitType.GhostNote) {
|
const showingAsGhost = this.getNode().classList.contains("beat-unit-ghost");
|
||||||
this.node?.classList.add("beat-unit-ghost");
|
const isGhost = this.beatUnit.getType() === BeatUnitType.GhostNote;
|
||||||
} else {
|
if (isGhost && !showingAsGhost) {
|
||||||
this.node?.classList.remove("beat-unit-ghost");
|
this.getNode().classList.add("beat-unit-ghost");
|
||||||
|
} else if (!isGhost && showingAsGhost) {
|
||||||
|
this.getNode().classList.remove("beat-unit-ghost");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
this.setupBindings();
|
this.setupBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onBeatViewHover(beatView: BeatUnitView) {
|
||||||
|
this.lastHoveredBeatUnitView = beatView;
|
||||||
|
if (BeatView.selectingUnits) {
|
||||||
|
this.lastHoveredBeatUnitView.turnOn();
|
||||||
|
} else if (BeatView.deselectingUnits) {
|
||||||
|
this.lastHoveredBeatUnitView.turnOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setupBindings() {
|
private setupBindings() {
|
||||||
this.beat.addSubscriber(this, "all");
|
this.beat.addSubscriber(this, "all");
|
||||||
}
|
}
|
||||||
@@ -56,14 +65,7 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
view = new BeatUnitView({beatUnit});
|
view = new BeatUnitView({beatUnit});
|
||||||
this.beatUnitViews.push(view);
|
this.beatUnitViews.push(view);
|
||||||
}
|
}
|
||||||
view.onHover(() => {
|
view.onHover(() => this.onBeatViewHover(view));
|
||||||
this.lastHoveredBeatUnitView = view;
|
|
||||||
if (BeatView.selectingUnits) {
|
|
||||||
this.lastHoveredBeatUnitView.turnOn();
|
|
||||||
} else if (BeatView.deselectingUnits) {
|
|
||||||
this.lastHoveredBeatUnitView.turnOff();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
view.onMouseDown((event: MouseEvent) => this.onBeatUnitClick(event.button, i));
|
view.onMouseDown((event: MouseEvent) => this.onBeatUnitClick(event.button, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,11 +114,11 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
|
|||||||
this.autoBeatLengthCheckbox.render(),
|
this.autoBeatLengthCheckbox.render(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
this.beatSettingsContainer,
|
|
||||||
new ActionButtonView({
|
new ActionButtonView({
|
||||||
label: "New Track",
|
label: "New Track",
|
||||||
onClick: () => this.beatGroup.addBeat(),
|
onClick: () => this.beatGroup.addBeat(),
|
||||||
}).render(),
|
}).render(),
|
||||||
|
this.beatSettingsContainer,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import "./BeatSettings.css";
|
|||||||
import Beat, {BeatEvents} from "../../Beat";
|
import Beat, {BeatEvents} from "../../Beat";
|
||||||
import UINode, {UINodeOptions} from "../UINode";
|
import UINode, {UINodeOptions} from "../UINode";
|
||||||
import ISubscriber from "../../Subscriber";
|
import ISubscriber from "../../Subscriber";
|
||||||
import {IPublisher} from "../../Publisher";
|
import {IPublisher, ISubscription} from "../../Publisher";
|
||||||
import NumberInputView from "../Widgets/NumberInput/NumberInputView";
|
import NumberInputView from "../Widgets/NumberInput/NumberInputView";
|
||||||
import BoolBoxView from "../Widgets/BoolBox/BoolBoxView";
|
import BoolBoxView from "../Widgets/BoolBox/BoolBoxView";
|
||||||
import ActionButtonView from "../Widgets/ActionButton/ActionButtonView";
|
import ActionButtonView from "../Widgets/ActionButton/ActionButtonView";
|
||||||
@@ -18,7 +18,7 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
|
|||||||
private loopLengthInput!: NumberInputView;
|
private loopLengthInput!: NumberInputView;
|
||||||
private loopCheckbox!: BoolBoxView;
|
private loopCheckbox!: BoolBoxView;
|
||||||
private loopLengthSection!: HTMLDivElement;
|
private loopLengthSection!: HTMLDivElement;
|
||||||
private sub!: { unbind: () => void };
|
private sub!: ISubscription;
|
||||||
|
|
||||||
constructor(options: BeatSettingsViewUINodeOptions) {
|
constructor(options: BeatSettingsViewUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ export default class RootView extends UINode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleSidebar(): void {
|
toggleSidebar(): void {
|
||||||
this.node!.classList.toggle("sidebar-visible");
|
this.node?.classList.toggle("sidebar-visible");
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleOrientation(): void {
|
toggleOrientation(): void {
|
||||||
this.node!.classList.toggle("vertical-mode");
|
this.node?.classList.toggle("vertical-mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild(): HTMLElement {
|
rebuild(): HTMLElement {
|
||||||
|
|||||||
Reference in New Issue
Block a user