Загрузка данных
import type { PriceScaleMode } from 'lightweight-charts';
export interface PriceScaleTarget {
paneId: number;
priceScaleId: string;
}
export interface PriceScaleSnapshot extends PriceScaleTarget {
mode: PriceScaleMode;
}
import { PriceScaleMode } from 'lightweight-charts';
import { BehaviorSubject, distinctUntilChanged, map, Observable } from 'rxjs';
import type { Pane } from '@core/Pane';
import type { PriceScaleSnapshot, PriceScaleTarget } from './types';
interface PriceScaleControllerParams {
getPaneById: (paneId: number) => Pane | undefined;
initialPriceScales?: PriceScaleSnapshot[];
}
export class PriceScaleController {
private readonly getPaneById: (paneId: number) => Pane | undefined;
private readonly userModes = new Map<number, Map<string, PriceScaleSnapshot>>();
private readonly policyModes = new Map<number, Map<string, PriceScaleMode>>();
private readonly changes$ = new BehaviorSubject(0);
constructor({ getPaneById, initialPriceScales = [] }: PriceScaleControllerParams) {
this.getPaneById = getPaneById;
this.setSnapshot(initialPriceScales);
}
public changes(): Observable<number> {
return this.changes$.asObservable();
}
public mode$(target: PriceScaleTarget): Observable<PriceScaleMode> {
return this.changes$.pipe(
map(() => this.getMode(target)),
distinctUntilChanged(),
);
}
public getMode(target: PriceScaleTarget): PriceScaleMode {
const policyMode = this.getPolicyMode(target);
if (policyMode !== PriceScaleMode.Normal) {
return policyMode;
}
return this.getUserMode(target);
}
public getUserMode(target: PriceScaleTarget): PriceScaleMode {
return this.userModes.get(target.paneId)?.get(target.priceScaleId)?.mode ?? PriceScaleMode.Normal;
}
public setMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (this.getUserMode(target) === mode) {
return;
}
this.setUserMode(target, mode);
this.applyMode(target);
this.emitChange();
}
public toggleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.setMode(
target,
this.getUserMode(target) === mode ? PriceScaleMode.Normal : mode,
);
}
public setPolicyMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (this.getPolicyMode(target) === mode) {
return;
}
this.setPolicyModeState(target, mode);
this.applyMode(target);
this.emitChange();
}
public applyAll(): void {
this.getSnapshot().forEach(({ paneId, priceScaleId }) => {
this.applyMode({ paneId, priceScaleId });
});
this.policyModes.forEach((paneModes, paneId) => {
paneModes.forEach((_, priceScaleId) => {
this.applyMode({ paneId, priceScaleId });
});
});
}
public getSnapshot(): PriceScaleSnapshot[] {
return Array.from(this.userModes.values())
.flatMap((paneModes) => Array.from(paneModes.values()))
.filter(({ paneId }) => Boolean(this.getPaneById(paneId)));
}
public setSnapshot(snapshot: PriceScaleSnapshot[]): void {
this.userModes.clear();
snapshot.forEach(({ paneId, priceScaleId, mode }) => {
this.setUserMode({ paneId, priceScaleId }, mode);
});
this.emitChange();
}
public destroy(): void {
this.userModes.clear();
this.policyModes.clear();
this.changes$.complete();
}
private getPolicyMode(target: PriceScaleTarget): PriceScaleMode {
return this.policyModes.get(target.paneId)?.get(target.priceScaleId) ?? PriceScaleMode.Normal;
}
private setUserMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (mode === PriceScaleMode.Normal) {
this.userModes.get(target.paneId)?.delete(target.priceScaleId);
return;
}
const paneModes = this.userModes.get(target.paneId) ?? new Map<string, PriceScaleSnapshot>();
paneModes.set(target.priceScaleId, {
...target,
mode,
});
this.userModes.set(target.paneId, paneModes);
}
private setPolicyModeState(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (mode === PriceScaleMode.Normal) {
this.policyModes.get(target.paneId)?.delete(target.priceScaleId);
return;
}
const paneModes = this.policyModes.get(target.paneId) ?? new Map<string, PriceScaleMode>();
paneModes.set(target.priceScaleId, mode);
this.policyModes.set(target.paneId, paneModes);
}
private applyMode(target: PriceScaleTarget): void {
const pane = this.getPaneById(target.paneId);
if (!pane) {
return;
}
pane.getPriceScale(target.priceScaleId).applyOptions({
mode: this.getMode(target),
});
}
private emitChange(): void {
this.changes$.next(this.changes$.value + 1);
}
}
export { PriceScaleController } from './controller';
export type {
PriceScaleSnapshot,
PriceScaleTarget,
} from './types';