Загрузка данных
import type { PriceScaleMode } from 'lightweight-charts';
export interface PriceScaleTarget {
paneId: number;
priceScaleId: string;
}
export interface PriceScaleModeSnapshot extends PriceScaleTarget {
mode: PriceScaleMode;
}
import { PriceScaleMode } from 'lightweight-charts';
import type { Pane } from '@core/Pane';
import type { PriceScaleModeSnapshot, PriceScaleTarget } from './types';
type PriceScaleModeMap = Map<number, Map<string, PriceScaleMode>>;
interface PriceScaleModeControllerParams {
getPaneById: (paneId: number) => Pane | undefined;
initialModes?: PriceScaleModeSnapshot[];
onChange?: () => void;
}
export class PriceScaleModeController {
private readonly getPaneById: (paneId: number) => Pane | undefined;
private readonly onChange?: () => void;
private readonly savedModes: PriceScaleModeMap = new Map();
private readonly overrideModes: PriceScaleModeMap = new Map();
constructor({ getPaneById, initialModes = [], onChange }: PriceScaleModeControllerParams) {
this.getPaneById = getPaneById;
this.onChange = onChange;
this.setSnapshot(initialModes);
}
public getActiveMode(target: PriceScaleTarget): PriceScaleMode {
return this.getOverrideMode(target) ?? this.getSavedMode(target);
}
public getSavedMode(target: PriceScaleTarget): PriceScaleMode {
return this.savedModes.get(target.paneId)?.get(target.priceScaleId) ?? PriceScaleMode.Normal;
}
public setSavedMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (this.getSavedMode(target) === mode) {
return;
}
this.setMode(this.savedModes, target, mode);
this.applyMode(target);
this.onChange?.();
}
public toggleSavedMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.setSavedMode(target, this.getSavedMode(target) === mode ? PriceScaleMode.Normal : mode);
}
public setOverrideMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
if (mode === PriceScaleMode.Normal) {
this.clearOverrideMode(target);
return;
}
if (this.getOverrideMode(target) === mode) {
return;
}
this.setMode(this.overrideModes, target, mode);
this.applyMode(target);
this.onChange?.();
}
public clearOverrideMode(target: PriceScaleTarget): void {
if (!this.getOverrideMode(target)) {
return;
}
this.removeMode(this.overrideModes, target);
this.applyMode(target);
this.onChange?.();
}
public applyAll(): void {
this.getTargets(this.savedModes).forEach((target) => this.applyMode(target));
this.getTargets(this.overrideModes).forEach((target) => this.applyMode(target));
}
public getSnapshot(): PriceScaleModeSnapshot[] {
const snapshot: PriceScaleModeSnapshot[] = [];
this.savedModes.forEach((paneModes, paneId) => {
if (!this.getPaneById(paneId)) {
return;
}
paneModes.forEach((mode, priceScaleId) => {
snapshot.push({
paneId,
priceScaleId,
mode,
});
});
});
return snapshot;
}
public setSnapshot(snapshot: PriceScaleModeSnapshot[]): void {
this.savedModes.clear();
snapshot.forEach(({ paneId, priceScaleId, mode }) => {
this.setMode(this.savedModes, { paneId, priceScaleId }, mode);
});
}
public destroy(): void {
this.savedModes.clear();
this.overrideModes.clear();
}
private getOverrideMode(target: PriceScaleTarget): PriceScaleMode | undefined {
return this.overrideModes.get(target.paneId)?.get(target.priceScaleId);
}
private setMode(modes: PriceScaleModeMap, target: PriceScaleTarget, mode: PriceScaleMode): void {
if (mode === PriceScaleMode.Normal) {
this.removeMode(modes, target);
return;
}
const paneModes = modes.get(target.paneId) ?? new Map<string, PriceScaleMode>();
paneModes.set(target.priceScaleId, mode);
modes.set(target.paneId, paneModes);
}
private removeMode(modes: PriceScaleModeMap, target: PriceScaleTarget): void {
const paneModes = modes.get(target.paneId);
paneModes?.delete(target.priceScaleId);
if (paneModes?.size === 0) {
modes.delete(target.paneId);
}
}
private getTargets(modes: PriceScaleModeMap): PriceScaleTarget[] {
const targets: PriceScaleTarget[] = [];
modes.forEach((paneModes, paneId) => {
paneModes.forEach((_, priceScaleId) => {
targets.push({ paneId, priceScaleId });
});
});
return targets;
}
private applyMode(target: PriceScaleTarget): void {
const pane = this.getPaneById(target.paneId);
if (!pane) {
return;
}
pane.getPriceScale(target.priceScaleId).applyOptions({
mode: this.getActiveMode(target),
});
}
}
export { PriceScaleModeController } from './controller';
export type {
PriceScaleModeSnapshot,
PriceScaleTarget,
} from './types';
public paneIndex = (): number => {
return this.lwcPane.paneIndex();
};
public getPriceScale(priceScaleId: string): IPriceScaleApi {
return this.lwcChart.priceScale(priceScaleId, this.paneIndex());
}
public getPriceScaleTarget(priceScaleId: string): PriceScaleTarget {
return {
paneId: this.id,
priceScaleId,
};
}
public getPriceScaleMode(target: PriceScaleTarget): PriceScaleMode {
return this.priceScaleModeController.getActiveMode(target);
}
public setPriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.priceScaleModeController.setSavedMode(target, mode);
}
public togglePriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.priceScaleModeController.toggleSavedMode(target, mode);
}
public getMainPriceScaleTarget(): PriceScaleTarget {
return this.paneManager.getMainPane().getPriceScaleTarget(Direction.Right);
}
private applyPolicy(): void {
const list = Array.from(this.entries.values());
const mainPane = this.paneManager.getMainPane();
let percentEnabled = false;
for (let i = 0; i < list.length; i += 1) {
if (list[i].mode === CompareMode.Percentage) {
percentEnabled = true;
break;
}
}
let hasMainNewScale = false;
for (let i = 0; i < list.length; i += 1) {
const pane = list[i].entity.getPane();
if (pane.isMainPane() && list[i].mode === CompareMode.NewScale) {
hasMainNewScale = true;
break;
}
}
const paneIds = new Set<number>();
for (let i = 0; i < list.length; i += 1) {
const pane = list[i].entity.getPane();
if (!pane.isMainPane()) {
paneIds.add(pane.getId());
}
}
this.chart.applyOptions({
leftPriceScale: { visible: hasMainNewScale, borderVisible: false },
});
this.chart.priceScale(Direction.Right, mainPane.paneIndex()).applyOptions({
visible: true,
});
if (percentEnabled) {
this.priceScaleModeController.setOverrideMode(
mainPane.getPriceScaleTarget(Direction.Right),
PriceScaleMode.Percentage,
);
} else {
this.priceScaleModeController.clearOverrideMode(mainPane.getPriceScaleTarget(Direction.Right));
}
this.chart.priceScale(Direction.Left, mainPane.paneIndex()).applyOptions({
visible: hasMainNewScale,
borderVisible: false,
});
const paneIdsList = Array.from(paneIds.values());
for (let i = 0; i < paneIdsList.length; i += 1) {
const pane = this.paneManager.getPaneById(paneIdsList[i]);
if (!pane) {
continue;
}
this.chart.priceScale(Direction.Right, pane.paneIndex()).applyOptions({
visible: true,
});
if (hasMainNewScale) {
this.chart.priceScale(Direction.Left, pane.paneIndex()).applyOptions({
visible: true,
borderVisible: false,
});
}
}
for (let i = 0; i < list.length; i += 1) {
const entry = list[i];
const pane = entry.entity.getPane();
const serie = Array.from(entry.entity.getSeriesMap())[0][1];
if (!pane.isMainPane()) {
serie.applyOptions({ priceScaleId: Direction.Right });
continue;
}
serie.applyOptions({
priceScaleId: entry.mode === CompareMode.NewScale ? Direction.Left : Direction.Right,
});
}
}
public getPriceScaleMode(target: PriceScaleTarget): PriceScaleMode {
return this.chart.getPriceScaleMode(target);
}
public setPriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.chart.setPriceScaleMode(target, mode);
}
public togglePriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
this.chart.togglePriceScaleMode(target, mode);
}
public getMainPriceScaleTarget(): PriceScaleTarget {
return this.chart.getMainPriceScaleTarget();
}
public toggleMainLogarithmicPriceScale(): void {
this.chart.togglePriceScaleMode(this.chart.getMainPriceScaleTarget(), PriceScaleMode.Logarithmic);
}