Skip to content

Commit

Permalink
Merge pull request #235 from boostcampwm-2024/feature/layout/detail/c…
Browse files Browse the repository at this point in the history
…hart-#192

[FE] 차트 확대 축소 기능 추가 & 이동 평균선 NaN 오류 해결 & Top5 localeScale 적용
  • Loading branch information
dongree authored Dec 2, 2024
2 parents a83a127 + 6b3de6d commit 63f1bd7
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 151 deletions.
63 changes: 56 additions & 7 deletions FE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-helmet": "^6.1.0",
"react-router-dom": "^6.27.0",
"react-toastify": "^10.0.6",
"socket.io-client": "^4.8.1",
Expand Down
124 changes: 97 additions & 27 deletions FE/src/components/StocksDetail/Chart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';
import {
MouseEvent,
useCallback,
useEffect,
useRef,
useState,
WheelEvent,
} from 'react';
import {
ChartSizeConfigType,
Padding,
Expand Down Expand Up @@ -65,6 +72,11 @@ export default function Chart({ code }: StocksDeatailChartProps) {
y: 0,
});
const [mouseIndex, setMouseIndex] = useState<number | null>(null);
const [dataRange, setDataRange] = useState({
start: 0,
end: 0,
});
const minDisplayData = 20;

const { data, isLoading } = useQuery(
['stocksChartData', code, timeCategory],
Expand Down Expand Up @@ -178,7 +190,7 @@ export default function Chart({ code }: StocksDeatailChartProps) {
const UpperYCtx = upperChartYCanvas.getContext('2d');
const LowerYCtx = lowerChartYCanvas.getContext('2d');
const ChartXCtx = chartXCanvas.getContext('2d');

const displayData = chartData.slice(dataRange.start, dataRange.end + 1);
if (
!UpperChartCtx ||
!LowerChartCtx ||
Expand All @@ -197,14 +209,14 @@ export default function Chart({ code }: StocksDeatailChartProps) {
lowerChartCanvas.width - padding.left - padding.right,
lowerChartCanvas.height - padding.top - padding.bottom,
lowerLabelNum,
chartData,
displayData,
padding,
);

if (moveAverageToggle) {
drawLineChart(
UpperChartCtx,
chartData,
displayData,
0,
0,
upperChartCanvas.width - padding.left - padding.right,
Expand All @@ -216,7 +228,7 @@ export default function Chart({ code }: StocksDeatailChartProps) {

drawCandleChart(
UpperChartCtx,
chartData,
displayData,
0,
0,
upperChartCanvas.width - padding.left - padding.right,
Expand All @@ -227,15 +239,15 @@ export default function Chart({ code }: StocksDeatailChartProps) {

drawBarChart(
LowerChartCtx,
chartData,
displayData,
lowerChartCanvas.width - padding.left - padding.right,
lowerChartCanvas.height - padding.top - padding.bottom,
padding,
);

drawUpperYAxis(
UpperYCtx,
chartData,
displayData,
upperChartYCanvas.width - padding.left - padding.right,
upperChartYCanvas.height - padding.top - padding.bottom,
upperLabelNum,
Expand All @@ -248,7 +260,7 @@ export default function Chart({ code }: StocksDeatailChartProps) {

drawLowerYAxis(
LowerYCtx,
chartData,
displayData,
lowerChartYCanvas.width - padding.left - padding.right,
lowerChartYCanvas.height - padding.top - padding.bottom,
lowerLabelNum,
Expand All @@ -261,7 +273,7 @@ export default function Chart({ code }: StocksDeatailChartProps) {

drawXAxis(
ChartXCtx,
chartData,
displayData,
chartXCanvas.width - padding.left - padding.right,
chartXCanvas.height,
padding,
Expand Down Expand Up @@ -300,8 +312,52 @@ export default function Chart({ code }: StocksDeatailChartProps) {
drawLowerYAxis,
drawXAxis,
moveAverageToggle,
dataRange,
],
);
const handleWheel = useCallback(
(e: WheelEvent<HTMLDivElement>) => {
if (!data) return;

const wheelPower = 0.1;
const curRange = dataRange.end - dataRange.start;

// 축소
if (e.deltaY > 0) {
// 늘어나야함 & 데이터 최대 갯수보다 작아야함.
const newRange = Math.min(curRange * (1 + wheelPower), data.length);
const newStart = Math.max(data.length - newRange, 0);

setDataRange({
start: newStart,
end: data.length - 1,
});
}

// 확대
if (e.deltaY < 0) {
// 줄어야함 & 최소 데이터 갯수보단 커야함.
const newRange = Math.max(curRange * (1 - wheelPower), minDisplayData);
const newStart = Math.max(data.length - newRange, 0);

setDataRange({
start: newStart,
end: data.length - 1,
});
}
},
[data, dataRange],
);

useEffect(() => {
if (data) {
setDataRange((prev) => ({
...prev,
start: 0,
end: data.length - 1,
}));
}
}, [data]);

useEffect(() => {
if (isLoading || !data) return;
Expand Down Expand Up @@ -382,6 +438,7 @@ export default function Chart({ code }: StocksDeatailChartProps) {
ref={containerRef}
className='mt-2 flex h-[200px] w-full flex-col'
onMouseMove={getCanvasMousePosition}
onWheel={handleWheel}
>
{/* Upper 차트 영역 */}
<div className='flex flex-row'>
Expand Down Expand Up @@ -419,24 +476,37 @@ export default function Chart({ code }: StocksDeatailChartProps) {
</button>
<div className='text-xs text-black'>이동평균선</div>
<div className='flex gap-1'>
<span className='text-xs text-orange-500'>5</span>
{mouseIndex !== null && data ? (
<span className={'text-xs'}>
{Math.floor(
Number(data[mouseIndex].mov_avg_5),
).toLocaleString()}
</span>
) : null}
<span className='text-xs text-green-600'>20</span>
{mouseIndex !== null && data ? (
<span className={'text-xs'}>
{Math.floor(
Number(data[mouseIndex].mov_avg_20),
).toLocaleString()}
</span>
) : null}
{mouseIndex !== null ? (
data && !isNaN(Number(data[mouseIndex].mov_avg_5)) ? (
<>
<span className='text-xs text-orange-500'>5</span>
<span className='text-xs'>
{Math.floor(
Number(data[mouseIndex].mov_avg_5),
).toLocaleString()}
</span>
</>
) : null
) : (
<span className='text-xs text-orange-500'>5</span>
)}

{mouseIndex !== null ? (
data && !isNaN(Number(data[mouseIndex].mov_avg_20)) ? (
<>
<span className='text-xs text-green-600'>20</span>
<span className={'text-xs'}>
{Math.floor(
Number(data[mouseIndex].mov_avg_20),
).toLocaleString()}
</span>
</>
) : null
) : (
<span className='text-xs text-green-600'>20</span>
)}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion FE/src/components/TopFive/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default function Card({
<div className={`w-[150px] text-right ${color}`}>
<p className='font-normal'>
{plusOrMinus}
{Math.abs(Number(changePrice))}({percentAbsolute}
{Math.abs(Number(changePrice)).toLocaleString()}({percentAbsolute}
%)
</p>
</div>
Expand Down
Loading

0 comments on commit 63f1bd7

Please sign in to comment.