보조지표 전체보기 후 복귀버튼 추가
This commit is contained in:
@@ -6,6 +6,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import type { IndicatorConfig } from '../types';
|
||||
import { ChartManager } from '../utils/ChartManager';
|
||||
import { getPaneHostId } from '../utils/indicatorPaneMerge';
|
||||
import { isIndicatorPaneFocused, resolveFocusedPaneLayoutId } from '../utils/indicatorPaneFocus';
|
||||
import { buildPaneItems, resolvePaneItemLayout } from './paneLegendLayout';
|
||||
import { PAPER_OVERLAY_MENU_TITLE } from '../utils/paperChartOverlayVisibility';
|
||||
|
||||
@@ -154,8 +155,8 @@ function buildMenuItems(
|
||||
const itemHostId = getPaneHostId(item.id, indicators);
|
||||
const isMergedPane = samePaneItems.length > 1;
|
||||
const showSplit = isMergedPane && item.id === itemHostId && !!opts.onSplit;
|
||||
const isFocused = opts.focusedId === item.id;
|
||||
const showExpand = !!(opts.onExpand || (isFocused && opts.onRestore));
|
||||
const isFocused = isIndicatorPaneFocused(item.id, opts.focusedId, indicators);
|
||||
const showExpand = !!(opts.onExpand || (opts.focusedId && opts.onRestore));
|
||||
const done = opts.onDone ?? (() => {});
|
||||
const cfg = indicators.find(ind => ind.id === item.id);
|
||||
const isHidden = cfg?.hidden === true;
|
||||
@@ -302,6 +303,17 @@ const ChartRightToolbar: React.FC<ChartRightToolbarProps> = ({
|
||||
const showOverlayMenu = !!(candleOverlayToggles?.length && candlePane && onToggleCandleOverlay);
|
||||
const overlayMenuOpen = openMenuId === CANDLE_OVERLAY_MENU_ID;
|
||||
|
||||
const focusedLayoutId = focusedId
|
||||
? resolveFocusedPaneLayoutId(focusedId, indicators)
|
||||
: null;
|
||||
const focusedPaneLayout = focusedLayoutId
|
||||
? (() => {
|
||||
const item = paneItems.find(p => isIndicatorPaneFocused(p.id, focusedId, indicators));
|
||||
if (item) return resolvePaneItemLayout(manager, item);
|
||||
return manager.getIndicatorPaneScreenLayout(focusedLayoutId);
|
||||
})()
|
||||
: null;
|
||||
|
||||
const overlayMenuItems: MenuItemDef[] = showOverlayMenu
|
||||
? candleOverlayToggles!.map(item => ({
|
||||
key: item.key,
|
||||
@@ -320,6 +332,22 @@ const ChartRightToolbar: React.FC<ChartRightToolbarProps> = ({
|
||||
className="chart-right-toolbar-inner"
|
||||
style={{ height: Math.max(innerHeight, chartHeight) }}
|
||||
>
|
||||
{focusedId && onRestore && focusedPaneLayout && (
|
||||
<div
|
||||
className="chart-right-toolbar-cluster chart-right-toolbar-cluster--focus-restore"
|
||||
style={{ top: focusedPaneLayout.topY + 4 }}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="tv-side-btn chart-right-toolbar-btn chart-right-toolbar-btn--restore active"
|
||||
title="기본 보기로 복원 (모든 보조지표 표시)"
|
||||
onClick={e => { e.stopPropagation(); onRestore(); }}
|
||||
>
|
||||
<IconRestore />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showOverlayMenu && (
|
||||
<div
|
||||
className="chart-right-toolbar-cluster chart-right-toolbar-cluster--overlay"
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 보조지표 단독 전체보기 모드 — 해당 pane 우측 상단 «기본 보기로 복원» 버튼
|
||||
*/
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import type { IndicatorConfig } from '../types';
|
||||
import { ChartManager } from '../utils/ChartManager';
|
||||
import { resolveFocusedPaneLayoutId } from '../utils/indicatorPaneFocus';
|
||||
|
||||
const IconRestore = () => (
|
||||
<svg width="13" height="13" viewBox="0 0 14 14" fill="none"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="5,13 1,13 1,9"/>
|
||||
<line x1="1" y1="13" x2="5.5" y2="8.5"/>
|
||||
<polyline points="9,1 13,1 13,5"/>
|
||||
<line x1="13" y1="1" x2="8.5" y2="5.5"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export interface IndicatorPaneControlsProps {
|
||||
manager: ChartManager;
|
||||
containerEl: HTMLElement;
|
||||
indicators: IndicatorConfig[];
|
||||
focusedId: string | null;
|
||||
onRestore: () => void;
|
||||
}
|
||||
|
||||
const IndicatorPaneControls: React.FC<IndicatorPaneControlsProps> = ({
|
||||
manager,
|
||||
containerEl,
|
||||
indicators,
|
||||
focusedId,
|
||||
onRestore,
|
||||
}) => {
|
||||
const [pos, setPos] = useState<{ left: number; top: number } | null>(null);
|
||||
|
||||
const updatePos = useCallback(() => {
|
||||
if (!focusedId) {
|
||||
setPos(null);
|
||||
return;
|
||||
}
|
||||
const layoutId = resolveFocusedPaneLayoutId(focusedId, indicators);
|
||||
const lay = manager.getIndicatorPaneScreenLayout(layoutId);
|
||||
if (!lay) {
|
||||
setPos(null);
|
||||
return;
|
||||
}
|
||||
const rect = containerEl.getBoundingClientRect();
|
||||
setPos({
|
||||
left: rect.left + rect.width - 40,
|
||||
top: rect.top + lay.topY + 4,
|
||||
});
|
||||
}, [manager, containerEl, focusedId, indicators]);
|
||||
|
||||
useEffect(() => {
|
||||
updatePos();
|
||||
const ro = new ResizeObserver(() => updatePos());
|
||||
ro.observe(containerEl);
|
||||
const unsub = manager.subscribePaneLayout(() => updatePos());
|
||||
const id = setInterval(updatePos, 400);
|
||||
return () => {
|
||||
ro.disconnect();
|
||||
unsub();
|
||||
clearInterval(id);
|
||||
};
|
||||
}, [containerEl, manager, updatePos, focusedId]);
|
||||
|
||||
if (!focusedId || !pos) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="indicator-pane-controls"
|
||||
style={{ position: 'fixed', left: pos.left, top: pos.top, zIndex: 505 }}
|
||||
onMouseDown={e => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="pane-btn pane-btn-expand active"
|
||||
onClick={e => { e.stopPropagation(); onRestore(); }}
|
||||
title="기본 보기로 복원 (모든 보조지표 표시)"
|
||||
>
|
||||
<IconRestore />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default IndicatorPaneControls;
|
||||
@@ -56,6 +56,7 @@ import ChartHoverToolbar from './ChartHoverToolbar';
|
||||
import ChartMagnifier from './ChartMagnifier';
|
||||
import ChartContextMenu from './ChartContextMenu';
|
||||
import CandlePaneControls from './CandlePaneControls';
|
||||
import IndicatorPaneControls from './IndicatorPaneControls';
|
||||
import { getKoreanName } from '../utils/marketNameCache';
|
||||
import { DEFAULT_DISPLAY_TIMEZONE } from '../utils/timezone';
|
||||
import { chartHasStaleIndicators, classifyIndicatorChartChange, singleIndParamKey } from '../utils/indicatorChartSync';
|
||||
@@ -1667,6 +1668,15 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
onRestore={() => setCandleOnlyMode(false)}
|
||||
/>
|
||||
)}
|
||||
{chartMgr && focusedIndicatorId && onRestoreIndicators && chartPaintReady && (
|
||||
<IndicatorPaneControlsPortal
|
||||
manager={chartMgr}
|
||||
indicators={indicators}
|
||||
getContainer={() => containerRef.current}
|
||||
focusedId={focusedIndicatorId}
|
||||
onRestore={onRestoreIndicators}
|
||||
/>
|
||||
)}
|
||||
{chartMgr && !candleOnlyMode && showPaneLegend && chartPaintReady && (
|
||||
<PaneLegendPortal
|
||||
key={indKey(indicators)}
|
||||
@@ -1723,6 +1733,33 @@ const CandlePaneTimeAxisPortal: React.FC<{
|
||||
return <CandlePaneTimeAxis manager={manager} containerEl={el} />;
|
||||
};
|
||||
|
||||
const IndicatorPaneControlsPortal: React.FC<{
|
||||
manager: ChartManager;
|
||||
indicators: IndicatorConfig[];
|
||||
getContainer: () => HTMLElement | null;
|
||||
focusedId: string;
|
||||
onRestore: () => void;
|
||||
}> = ({ manager, indicators, getContainer, focusedId, onRestore }) => {
|
||||
const [el, setEl] = useState<HTMLElement | null>(null);
|
||||
useEffect(() => {
|
||||
const c = getContainer();
|
||||
if (c) { setEl(c); return; }
|
||||
const tid = setTimeout(() => setEl(getContainer()), 100);
|
||||
return () => clearTimeout(tid);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
if (!el) return null;
|
||||
return (
|
||||
<IndicatorPaneControls
|
||||
manager={manager}
|
||||
containerEl={el}
|
||||
indicators={indicators}
|
||||
focusedId={focusedId}
|
||||
onRestore={onRestore}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const CandlePaneControlsPortal: React.FC<{
|
||||
manager: ChartManager;
|
||||
getContainer: () => HTMLElement | null;
|
||||
|
||||
Reference in New Issue
Block a user