goldenChat base source add
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import type { IndicatorConfig } from '../types';
|
||||
import { enrichIndicatorConfig, getIndicatorDef } from './indicatorRegistry';
|
||||
|
||||
/** 보조지표 인스턴스 복제 (새 id, 별도 pane) */
|
||||
export function cloneIndicatorConfig(src: IndicatorConfig, newId: string): IndicatorConfig {
|
||||
return enrichIndicatorConfig({
|
||||
...src,
|
||||
id: newId,
|
||||
mergedWith: undefined,
|
||||
params: { ...src.params },
|
||||
plots: src.plots?.map(p => ({ ...p })),
|
||||
hlines: src.hlines?.map(h => ({ ...h })),
|
||||
plotVisibility: src.plotVisibility ? { ...src.plotVisibility } : undefined,
|
||||
timeframeVisibility: src.timeframeVisibility
|
||||
? { ...src.timeframeVisibility }
|
||||
: undefined,
|
||||
cloudColors: src.cloudColors ? { ...src.cloudColors } : undefined,
|
||||
hlinesBackground: src.hlinesBackground
|
||||
? { ...src.hlinesBackground }
|
||||
: undefined,
|
||||
bandBackground: src.bandBackground
|
||||
? { ...src.bandBackground }
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
/** sourceId 바로 아래에 동일 설정의 보조지표 복사본 추가 */
|
||||
export function duplicateIndicatorInList(
|
||||
sourceId: string,
|
||||
prev: IndicatorConfig[],
|
||||
newId: () => string,
|
||||
): IndicatorConfig[] | null {
|
||||
const idx = prev.findIndex(i => i.id === sourceId);
|
||||
if (idx === -1) return null;
|
||||
const src = prev[idx];
|
||||
const def = getIndicatorDef(src.type);
|
||||
if (!def || def.overlay || def.returnsMarkers) return null;
|
||||
|
||||
const clone = cloneIndicatorConfig(src, newId());
|
||||
const next = [...prev];
|
||||
next.splice(idx + 1, 0, clone);
|
||||
return next;
|
||||
}
|
||||
|
||||
/** mergedWith 체인의 루트(공유 pane 소유) 지표 id */
|
||||
export function getPaneHostId(id: string, indicators: IndicatorConfig[]): string {
|
||||
const seen = new Set<string>();
|
||||
let cur = id;
|
||||
for (;;) {
|
||||
if (seen.has(cur)) return id;
|
||||
seen.add(cur);
|
||||
const ind = indicators.find(i => i.id === cur);
|
||||
if (!ind?.mergedWith) return cur;
|
||||
cur = ind.mergedWith;
|
||||
}
|
||||
}
|
||||
|
||||
/** 같은 pane 에 묶인 지표 id 목록 (배열 순서 유지) */
|
||||
export function getMergedGroupIds(hostId: string, indicators: IndicatorConfig[]): string[] {
|
||||
const host = getPaneHostId(hostId, indicators);
|
||||
return indicators
|
||||
.filter(i => getPaneHostId(i.id, indicators) === host)
|
||||
.map(i => i.id);
|
||||
}
|
||||
|
||||
/** 드롭 대상 → 실제 pane 호스트 id */
|
||||
export function resolveMergeTargetId(targetId: string, indicators: IndicatorConfig[]): string {
|
||||
return getPaneHostId(targetId, indicators);
|
||||
}
|
||||
|
||||
/** reload 시 호스트 지표를 먼저 addIndicator 하도록 정렬 */
|
||||
export function sortIndicatorsForPaneLoad(inds: IndicatorConfig[]): IndicatorConfig[] {
|
||||
const byId = new Map(inds.map(i => [i.id, i]));
|
||||
const out: IndicatorConfig[] = [];
|
||||
const added = new Set<string>();
|
||||
|
||||
const addOne = (ind: IndicatorConfig) => {
|
||||
if (added.has(ind.id)) return;
|
||||
if (ind.mergedWith) {
|
||||
const host = byId.get(ind.mergedWith);
|
||||
if (host) addOne(host);
|
||||
}
|
||||
out.push(ind);
|
||||
added.add(ind.id);
|
||||
};
|
||||
|
||||
for (const ind of inds) addOne(ind);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 보조지표 그룹(병합 pane) 통째로 순서 변경 */
|
||||
export function reorderIndicatorGroup(
|
||||
fromId: string,
|
||||
insertBeforeId: string | null,
|
||||
prev: IndicatorConfig[],
|
||||
): IndicatorConfig[] {
|
||||
const hostId = getPaneHostId(fromId, prev);
|
||||
const groupSet = new Set(getMergedGroupIds(hostId, prev));
|
||||
const groupItems = prev.filter(i => groupSet.has(i.id));
|
||||
const without = prev.filter(i => !groupSet.has(i.id));
|
||||
|
||||
if (insertBeforeId === null) {
|
||||
return [...without, ...groupItems];
|
||||
}
|
||||
|
||||
const beforeHost = getPaneHostId(insertBeforeId, prev);
|
||||
const toIdx = without.findIndex(i => i.id === beforeHost);
|
||||
without.splice(toIdx === -1 ? without.length : toIdx, 0, ...groupItems);
|
||||
return without;
|
||||
}
|
||||
|
||||
/** fromId 를 intoId pane 에 병합 */
|
||||
export function mergeIndicators(
|
||||
fromId: string,
|
||||
intoId: string,
|
||||
prev: IndicatorConfig[],
|
||||
): IndicatorConfig[] {
|
||||
const host = resolveMergeTargetId(intoId, prev);
|
||||
if (fromId === host) return prev;
|
||||
if (getPaneHostId(fromId, prev) === host) return prev;
|
||||
return prev.map(i => (i.id === fromId ? { ...i, mergedWith: host } : i));
|
||||
}
|
||||
|
||||
/** 병합 pane 분리 — 호스트 그룹의 mergedWith 제거 */
|
||||
export function splitIndicatorPane(
|
||||
hostOrMemberId: string,
|
||||
prev: IndicatorConfig[],
|
||||
): IndicatorConfig[] {
|
||||
const host = getPaneHostId(hostOrMemberId, prev);
|
||||
return prev.map(i => {
|
||||
if (getPaneHostId(i.id, prev) !== host || !i.mergedWith) return i;
|
||||
const { mergedWith: _m, ...rest } = i;
|
||||
return rest;
|
||||
});
|
||||
}
|
||||
|
||||
export function layoutKey(inds: IndicatorConfig[]): string {
|
||||
return inds.map(i => `${i.id}>${i.mergedWith ?? ''}`).join(';');
|
||||
}
|
||||
Reference in New Issue
Block a user