From d51820b1d470ddb484d072ac9177cdd51b8e9d00 Mon Sep 17 00:00:00 2001 From: Daniel Ledda Date: Sun, 5 Dec 2021 15:47:28 +0100 Subject: [PATCH] added various performance improvements --- src/BeatUnit.ts | 4 +- src/Publisher.ts | 48 +++++++++++++++---- .../BeatGroup/Beat/BeatUnit/BeatUnitView.ts | 24 ++++++---- src/ui/BeatGroup/Beat/BeatView.ts | 18 +++---- .../BeatGroupSettingsView.ts | 2 +- src/ui/BeatSettings/BeatSettingsView.ts | 4 +- src/ui/Root/RootView.ts | 4 +- 7 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/BeatUnit.ts b/src/BeatUnit.ts index c0978c6..895d3ec 100644 --- a/src/BeatUnit.ts +++ b/src/BeatUnit.ts @@ -1,4 +1,4 @@ -import {IPublisher, Publisher} from "./Publisher"; +import {IPublisher, ISubscription, Publisher} from "./Publisher"; import ISubscriber from "./Subscriber"; export enum BeatUnitType { @@ -24,7 +24,7 @@ export default class BeatUnit implements IPublisher { 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); } diff --git a/src/Publisher.ts b/src/Publisher.ts index 4ecda57..1c1d1a6 100644 --- a/src/Publisher.ts +++ b/src/Publisher.ts @@ -1,5 +1,29 @@ import ISubscriber from "./Subscriber"; +class Subscription implements ISubscription { + private subscriber: ISubscriber; + private readonly eventTypes: T[]; + private publisher: Publisher; + constructor(publisher: Publisher, 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 implements IPublisher { private subscribers: Map; private parent: P; @@ -10,7 +34,7 @@ export class Publisher implements IPublisher 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")[] = []; if (!Array.isArray(eventType)) { eventTypes.push(eventType); @@ -20,14 +44,14 @@ export class Publisher implements IPublisher for (const key of eventTypes) { this.getSubscribers(key).push(subscriber); } - return { - unbind: () => { - for (const key of eventTypes) { - const subs = this.getSubscribers(key); - subs.splice(subs.indexOf(subscriber), 1); - } - } - }; + return new Subscription(this, subscriber, eventTypes); + } + + unbind(subscription: Subscription): void { + for (const key of subscription.getEventTypes()) { + const subs = this.getSubscribers(key); + subs.splice(subs.indexOf(subscription.getSubscriber()), 1); + } } private getSubscribers(key: T | "all"): ISubscriber[] { @@ -41,7 +65,7 @@ export class Publisher implements IPublisher } } - notifySubs(eventType: T) { + notifySubs(eventType: T): void { for (const sub of this.getSubscribers(eventType)) { sub.notify(this.parent, eventType); } @@ -53,4 +77,8 @@ export class Publisher implements IPublisher export interface IPublisher { addSubscriber(subscriber: ISubscriber, eventType: (T | "all") | T[]): {unbind: () => void}; +} + +export interface ISubscription { + unbind(): void; } \ No newline at end of file diff --git a/src/ui/BeatGroup/Beat/BeatUnit/BeatUnitView.ts b/src/ui/BeatGroup/Beat/BeatUnit/BeatUnitView.ts index 891b83a..627aa16 100644 --- a/src/ui/BeatGroup/Beat/BeatUnit/BeatUnitView.ts +++ b/src/ui/BeatGroup/Beat/BeatUnit/BeatUnitView.ts @@ -1,7 +1,7 @@ import BeatUnit, {BeatUnitEvents, BeatUnitType} from "../../../../BeatUnit"; import ISubscriber from "../../../../Subscriber"; import UINode, {UINodeOptions} from "../../../UINode"; -import {IPublisher} from "../../../../Publisher"; +import {IPublisher, ISubscription, Publisher} from "../../../../Publisher"; import "./BeatUnit.css"; export type BeatUnitUINodeOptions = UINodeOptions & { @@ -10,7 +10,8 @@ export type BeatUnitUINodeOptions = UINodeOptions & { export default class BeatUnitView extends UINode implements ISubscriber { private beatUnit: BeatUnit; - private subscription!: {unbind: () => void}; + private subscription: ISubscription | null = null; + private publisher: IPublisher = new Publisher(this); constructor(options: BeatUnitUINodeOptions) { super(options); @@ -19,13 +20,14 @@ export default class BeatUnitView extends UINode implements ISubscriber { } setUnit(beatUnit: BeatUnit): void { - this.subscription.unbind(); this.beatUnit = beatUnit; this.setupBindings(); - this.redraw(); + this.notify(this.publisher, beatUnit.isOn() ? BeatUnitEvents.On : BeatUnitEvents.Off); + this.notify(this.publisher, BeatUnitEvents.TypeChange); } private setupBindings() { + this.subscription?.unbind(); this.subscription = this.beatUnit.addSubscriber(this, "all"); } @@ -43,14 +45,16 @@ export default class BeatUnitView extends UINode implements ISubscriber { notify(publisher: IPublisher, event: "all" | T[] | T): void { if (event === BeatUnitEvents.On) { - this.node?.classList.add("beat-unit-on"); + this.getNode().classList.add("beat-unit-on"); } else if (event === BeatUnitEvents.Off) { - this.node?.classList.remove("beat-unit-on"); + this.getNode().classList.remove("beat-unit-on"); } else if (event === BeatUnitEvents.TypeChange) { - if (this.beatUnit.getType() === BeatUnitType.GhostNote) { - this.node?.classList.add("beat-unit-ghost"); - } else { - this.node?.classList.remove("beat-unit-ghost"); + const showingAsGhost = this.getNode().classList.contains("beat-unit-ghost"); + const isGhost = this.beatUnit.getType() === BeatUnitType.GhostNote; + if (isGhost && !showingAsGhost) { + this.getNode().classList.add("beat-unit-ghost"); + } else if (!isGhost && showingAsGhost) { + this.getNode().classList.remove("beat-unit-ghost"); } } } diff --git a/src/ui/BeatGroup/Beat/BeatView.ts b/src/ui/BeatGroup/Beat/BeatView.ts index 5aa9400..8ef384e 100644 --- a/src/ui/BeatGroup/Beat/BeatView.ts +++ b/src/ui/BeatGroup/Beat/BeatView.ts @@ -24,6 +24,15 @@ export default class BeatView extends UINode implements ISubscriber { this.setupBindings(); } + private onBeatViewHover(beatView: BeatUnitView) { + this.lastHoveredBeatUnitView = beatView; + if (BeatView.selectingUnits) { + this.lastHoveredBeatUnitView.turnOn(); + } else if (BeatView.deselectingUnits) { + this.lastHoveredBeatUnitView.turnOff(); + } + } + private setupBindings() { this.beat.addSubscriber(this, "all"); } @@ -56,14 +65,7 @@ export default class BeatView extends UINode implements ISubscriber { view = new BeatUnitView({beatUnit}); this.beatUnitViews.push(view); } - view.onHover(() => { - this.lastHoveredBeatUnitView = view; - if (BeatView.selectingUnits) { - this.lastHoveredBeatUnitView.turnOn(); - } else if (BeatView.deselectingUnits) { - this.lastHoveredBeatUnitView.turnOff(); - } - }); + view.onHover(() => this.onBeatViewHover(view)); view.onMouseDown((event: MouseEvent) => this.onBeatUnitClick(event.button, i)); } } diff --git a/src/ui/BeatGroupSettings/BeatGroupSettingsView.ts b/src/ui/BeatGroupSettings/BeatGroupSettingsView.ts index 7952c2e..de18505 100644 --- a/src/ui/BeatGroupSettings/BeatGroupSettingsView.ts +++ b/src/ui/BeatGroupSettings/BeatGroupSettingsView.ts @@ -114,11 +114,11 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber this.autoBeatLengthCheckbox.render(), ], }), - this.beatSettingsContainer, new ActionButtonView({ label: "New Track", onClick: () => this.beatGroup.addBeat(), }).render(), + this.beatSettingsContainer, ], }), ], diff --git a/src/ui/BeatSettings/BeatSettingsView.ts b/src/ui/BeatSettings/BeatSettingsView.ts index a68912c..f317886 100644 --- a/src/ui/BeatSettings/BeatSettingsView.ts +++ b/src/ui/BeatSettings/BeatSettingsView.ts @@ -2,7 +2,7 @@ import "./BeatSettings.css"; import Beat, {BeatEvents} from "../../Beat"; import UINode, {UINodeOptions} from "../UINode"; import ISubscriber from "../../Subscriber"; -import {IPublisher} from "../../Publisher"; +import {IPublisher, ISubscription} from "../../Publisher"; import NumberInputView from "../Widgets/NumberInput/NumberInputView"; import BoolBoxView from "../Widgets/BoolBox/BoolBoxView"; import ActionButtonView from "../Widgets/ActionButton/ActionButtonView"; @@ -18,7 +18,7 @@ export default class BeatSettingsView extends UINode implements ISubscriber { private loopLengthInput!: NumberInputView; private loopCheckbox!: BoolBoxView; private loopLengthSection!: HTMLDivElement; - private sub!: { unbind: () => void }; + private sub!: ISubscription; constructor(options: BeatSettingsViewUINodeOptions) { super(options); diff --git a/src/ui/Root/RootView.ts b/src/ui/Root/RootView.ts index af56249..69e49a8 100644 --- a/src/ui/Root/RootView.ts +++ b/src/ui/Root/RootView.ts @@ -25,11 +25,11 @@ export default class RootView extends UINode { } toggleSidebar(): void { - this.node!.classList.toggle("sidebar-visible"); + this.node?.classList.toggle("sidebar-visible"); } toggleOrientation(): void { - this.node!.classList.toggle("vertical-mode"); + this.node?.classList.toggle("vertical-mode"); } rebuild(): HTMLElement {