Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/routes/trade.$ticker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default function TradeRouteComponent({
<CoinPriceWithName name={coinInfo?.name} ticker={coinInfo?.ticker} />
)}
<div className="scrollbar-hide relative flex h-[calc(100dvh-116px)] flex-col gap-4 overflow-y-scroll p-4 md:grid md:grid-cols-2 md:grid-rows-5 xl:grid-cols-3 xl:grid-rows-2 2xl:grid-cols-4 2xl:grid-rows-2">
<div className="h-auto md:col-span-full md:row-span-2 md:row-start-1 xl:col-span-full xl:row-span-1 xl:row-start-1 2xl:col-span-2 2xl:col-start-2 2xl:row-start-1">
<div className="h-auto min-h-75 md:col-span-full md:row-span-2 md:row-start-1 xl:col-span-full xl:row-span-1 xl:row-start-1 2xl:col-span-2 2xl:col-start-2 2xl:row-start-1">
<Container>
<ContainerTitle>실시간 차트</ContainerTitle>
<Suspense fallback="차트데이터를 가져오고 있습니다.">
Expand Down
2 changes: 2 additions & 0 deletions src/features/tradeview/const/chart.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export const INTERVALS = [
];

export const INTERVAL_SELECTOR_HEIGHT = 26;

export const MINUTE = 60;
10 changes: 3 additions & 7 deletions src/features/tradeview/ui/Orderbook/chart.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as am5 from '@amcharts/amcharts5';
import * as am5xy from '@amcharts/amcharts5/xy';
import { useEffect, useLayoutEffect, useRef } from 'react';
import { formatCurrencyKR } from '~/shared/utils';
import type { OrderBookUnit } from '../../types/orderbook.type';

const THEME = {
Expand Down Expand Up @@ -33,18 +34,14 @@ export default function OrderbookChart({
if (!chartRef.current || !yAxisRef.current || !seriesRef.current) return;

const formattedData = data.map((item) => ({
price: item.price.toString(),
price: formatCurrencyKR(+item.price),
size: item.size,
priceY: item.price,
sizeX: item.size,
}));

yAxisRef.current.data.setAll(formattedData);
seriesRef.current.data.setAll(formattedData);

chartRef.current.series.each((series) => {
series.appear(1000);
});
}, [data]);

useLayoutEffect(() => {
Expand All @@ -69,7 +66,6 @@ export default function OrderbookChart({
am5.Rectangle.new(rootRef.current, {
stroke: am5.color('#fff'),
strokeOpacity: 0,
fill: THEME[type].barColor,
fillOpacity: 0.05,
}),
);
Expand Down Expand Up @@ -116,7 +112,7 @@ export default function OrderbookChart({
sequencedInterpolation: true,
tooltip: am5.Tooltip.new(rootRef.current, {
pointerOrientation: 'horizontal',
labelText: '[bold]{priceY}원 {sizeX}개',
labelText: "[bold]{priceY.formatNumber('#,###.##')}원 {sizeX}개",
}),
paddingBottom: 0,
paddingTop: 0,
Expand Down
8 changes: 0 additions & 8 deletions src/features/tradeview/ui/StockChart/Series.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
useContext,
useImperativeHandle,
useLayoutEffect,
useMemo,
useRef,
} from 'react';

Expand Down Expand Up @@ -114,13 +113,6 @@ export default function Series<T extends SeriesType>({

useImperativeHandle(ref, () => seriesApiRef.current.getInstance(), []);

const context = useMemo(
() => ({
series: seriesApiRef.current,
}),
[],
);

return (
<SeriesContext.Provider value={seriesApiRef.current}>
{children}
Expand Down
5 changes: 4 additions & 1 deletion src/features/tradeview/ui/StockChart/ToolTip.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { CandlestickData } from 'lightweight-charts';
import { useLayoutEffect, useRef } from 'react';
import { formatCurrencyKR } from '~/shared/utils';
import { formatDateKr } from '../../utils';
import { useChartContainer } from './ChartContainer';
import { useChartRoot } from './ChartRoot';
import { useSeries } from './Series';
Expand Down Expand Up @@ -36,6 +37,8 @@ export default function ToolTip() {
const { close, high, low, open, time } = param.seriesData.get(
chartSeries,
) as CandlestickData;
const date = new Date((time as number) * 1000);
const koreanDate = new Date(date.setHours(date.getHours() - 9));

toolTipElementRef.current.style.display = 'block';
toolTipElementRef.current.innerHTML = `<div style="border: 1px solid #d1d5db; background-color: white; padding: 0.5rem; border-radius: 0.5rem; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); color: #1f2937; z-index: 40;">
Expand All @@ -50,7 +53,7 @@ export default function ToolTip() {
<div style="font-weight: 500;">${formatCurrencyKR(close)}원</div>
</div>
<div style="border-top: 1px solid #e5e7eb; padding-top: 0.25rem; margin-top: 0.25rem;">
<div style="color: #6b7280; font-size: 0.75rem; line-height: 1rem;">${new Date((time as number) * 1000).toLocaleString()}</div>
<div style="color: #6b7280; font-size: 0.75rem; line-height: 1rem;">${formatDateKr(koreanDate)}</div>
</div>
</div>`;

Expand Down
20 changes: 16 additions & 4 deletions src/features/tradeview/ui/StockChart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ import Series from './Series';
import ToolTip from './ToolTip';

import api from '../../api/tradeview.endpoints';
import { INTERVALS } from '../../const/chart.const';
import { INTERVALS, MINUTE } from '../../const/chart.const';
import usePastTimeData from '../../hooks/usePastTimeData';
import useRealTimeData from '../../hooks/useRealTimeData';
import { extractCandlestickData, timestampToISOString } from '../../utils';
import {
extractCandlestickData,
priceFormatter,
timestampToISOString,
} from '../../utils';
import IntervalSelector from '../IntervalSelector';

type ChartProps = {
Expand All @@ -39,13 +43,15 @@ export default function Chart({ ticker = 'BTC', count = 30 }: ChartProps) {
const [isChartReady, setIsChartReady] = useState(false);
const realTimeData = useRealTimeData(ticker);
const pastTimeData = usePastTimeData(ticker, selectedInterval, count);
const prevRequestDate = useRef<Time | null>(null);

const chartOption: DeepPartial<TimeChartOptions> = useMemo(() => {
return {
timeScale: { timeVisible: true },
localization: {
locale: 'kr',
dateFormat: 'yyyy-MM-dd',
priceFormatter: priceFormatter(),
},
rightPriceScale: {
borderVisible: false,
Expand Down Expand Up @@ -89,6 +95,12 @@ export default function Chart({ ticker = 'BTC', count = 30 }: ChartProps) {
if (logicalRange.from < -0.5) {
const firstData = seriesRef.current?.dataByIndex(0) as CandlestickData;
if (!firstData || !firstData.time) return;
if (
prevRequestDate.current &&
prevRequestDate.current <= firstData.time
)
return;
prevRequestDate.current = firstData.time;

const firstDate = timestampToISOString(firstData.time as number);

Expand Down Expand Up @@ -137,12 +149,12 @@ export default function Chart({ ticker = 'BTC', count = 30 }: ChartProps) {

const timeDiff = +realTimeData.time - +latestTime.time;

if (timeDiff < 60 * selectedInterval) {
if (timeDiff < MINUTE * selectedInterval) {
seriesRef.current?.update({ ...realTimeData, time: latestTime.time });
} else {
seriesRef.current?.update({
...realTimeData,
time: (+latestTime.time + 60 * selectedInterval) as Time,
time: (+latestTime.time + MINUTE * selectedInterval) as Time,
});
}
}, [realTimeData, selectedInterval]);
Expand Down
16 changes: 16 additions & 0 deletions src/features/tradeview/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,19 @@ export function timestampToISOString(timestamp: number) {
const date = new Date(timestamp * 1000);
return date.toISOString().slice(0, -1);
}

export function priceFormatter() {
const currentLocale = window.navigator.languages[0];

return Intl.NumberFormat(currentLocale, {
style: 'currency',
currency: 'KRW',
}).format;
}

export function formatDateKr(date: Date) {
return Intl.DateTimeFormat('ko-KR', {
dateStyle: 'full',
timeStyle: 'short',
}).format(date);
}
Loading