Files
goldenChart/frontend_golden/src/components/FibonacciFan.tsx
T
2026-05-23 15:11:48 +09:00

148 lines
3.9 KiB
TypeScript

import React, { useRef, useEffect } from 'react';
import { Box } from '@mui/material';
export interface FibonacciFanObject {
id: string;
type: 'fibonacciFan';
startPrice: number;
endPrice: number;
startTime: number;
endTime: number;
settings: {
color: string;
lineWidth: number;
lineStyle: 'solid' | 'dashed' | 'dotted';
levels: number[];
showLabels: boolean;
};
}
interface FibonacciFanProps {
objects: FibonacciFanObject[];
chartWidth: number;
chartHeight: number;
totalChartHeight?: number;
priceScale: {
from: number;
to: number;
};
timeScale: {
from: number;
to: number;
};
candleData: Array<{ time: string | number; open: number; high: number; low: number; close: number }>;
timeToX: (time: number) => number | null;
priceToY: (price: number) => number | null;
onClick?: (objectId: string, event: React.MouseEvent) => void;
onDoubleClick?: (objectId: string) => void;
onDragStart?: (objectId: string, startX: number, startTime: number) => void;
}
const FibonacciFan: React.FC<FibonacciFanProps> = ({
objects,
chartWidth,
chartHeight,
totalChartHeight,
priceScale,
timeScale,
candleData,
timeToX,
priceToY,
onClick,
onDoubleClick,
onDragStart,
}) => {
const svgRef = useRef<SVGSVGElement>(null);
const calculateFanLines = (startPrice: number, endPrice: number) => {
const priceRange = endPrice - startPrice;
const levels = [0.382, 0.5, 0.618]; // 기본 피보나치 팬 레벨
return levels.map(level => ({
level,
price: startPrice + (priceRange * level)
}));
};
const renderFan = (fanObject: FibonacciFanObject) => {
const startX = timeToX(fanObject.startTime);
const endX = timeToX(fanObject.endTime);
const startY = priceToY(fanObject.startPrice);
if (startX === null || endX === null || startY === null) return null;
const fanLines = calculateFanLines(fanObject.startPrice, fanObject.endPrice);
return (
<g key={fanObject.id}>
{fanLines.map((fanLine, index) => {
const endY = priceToY(fanLine.price);
if (endY === null) return null;
const strokeDasharray = fanObject.settings.lineStyle === 'dashed'
? '5,5'
: fanObject.settings.lineStyle === 'dotted'
? '2,2'
: undefined;
return (
<g key={index}>
<line
x1={startX}
y1={startY}
x2={endX}
y2={endY}
stroke={fanObject.settings.color}
strokeWidth={fanObject.settings.lineWidth}
strokeDasharray={strokeDasharray}
opacity={0.8}
style={{ cursor: 'pointer' }}
onClick={(e) => onClick?.(fanObject.id, e)}
onDoubleClick={() => onDoubleClick?.(fanObject.id)}
/>
{fanObject.settings.showLabels && (
<text
x={endX + 5}
y={endY}
fill={fanObject.settings.color}
fontSize={10}
fontFamily="Arial, sans-serif"
>
{`${(fanLine.level * 100).toFixed(1)}%`}
</text>
)}
</g>
);
})}
</g>
);
};
return (
<Box
sx={{
position: 'absolute',
top: 0,
left: 0,
width: chartWidth,
height: totalChartHeight || chartHeight,
pointerEvents: 'none',
zIndex: 100,
}}
>
<svg
ref={svgRef}
width={chartWidth}
height={totalChartHeight || chartHeight}
style={{ position: 'absolute', top: 0, left: 0 }}
>
<g style={{ pointerEvents: 'all' }}>
{objects.map(renderFan)}
</g>
</svg>
</Box>
);
};
export default FibonacciFan;