11import * as am5stock from '@amcharts/amcharts5/stock' ;
22import * as am5xy from '@amcharts/amcharts5/xy' ;
3- import { type PropsWithChildren , useEffect , useState } from 'react' ;
3+ import type { PropsWithChildren } from 'react' ;
44
55import { isNullish } from '~/shared/utils' ;
66import type { CandlestickData } from '../../types/tradeview.type' ;
77import { isDisposed } from '../../utils' ;
88import type { StockAxis } from './StockAxis' ;
99
10- type SeriesSettings = {
10+ export type SeriesSettings = {
1111 name ?: string ;
1212 clustered ?: boolean ;
1313 legendValueText ?: string ;
1414 legendRangeValueText ?: string ;
1515} ;
1616
17- type ValueSeriesProps = PropsWithChildren <
17+ export type ValueSeriesProps = PropsWithChildren <
1818 Partial < StockAxis > & {
1919 pastTimeData ?: CandlestickData [ ] ;
2020 seriesSettings ?: SeriesSettings ;
21+ fetchPastTimeData ?: ( ) => Promise < void > ;
2122 }
2223> ;
2324
@@ -30,86 +31,82 @@ export default function ValueSeries({
3031 dateAxis,
3132 pastTimeData,
3233 seriesSettings,
34+ fetchPastTimeData,
3335} : ValueSeriesProps ) {
34- const [ valueSeries , setValueSeries ] =
35- useState < am5xy . CandlestickSeries | null > ( null ) ;
36+ if (
37+ isNullish ( chartRoot ) ||
38+ isNullish ( stockChart ) ||
39+ isNullish ( mainPanel ) ||
40+ isNullish ( valueAxis ) ||
41+ isNullish ( dateAxis )
42+ ) {
43+ console . error ( 'ValueSeries should be used within StockAxis' ) ;
44+ return ;
45+ }
3646
37- useEffect ( ( ) => {
38- if ( ! valueSeries || ! pastTimeData ) return ;
39- valueSeries . data . setAll ( pastTimeData ) ;
40- } , [ valueSeries , pastTimeData ] ) ;
47+ if ( isDisposed ( chartRoot , stockChart , mainPanel , valueAxis , dateAxis ) ) return ;
4148
42- useEffect ( ( ) => {
43- if (
44- isNullish ( chartRoot ) ||
45- isNullish ( stockChart ) ||
46- isNullish ( mainPanel ) ||
47- isNullish ( valueAxis ) ||
48- isNullish ( dateAxis )
49- ) {
50- console . error ( 'ValueSeries should be used within StockAxis' ) ;
51- return ;
52- }
49+ const newValueSeries = mainPanel . series . push (
50+ am5xy . CandlestickSeries . new ( chartRoot , {
51+ name : seriesSettings ?. name || 'MSFT' ,
52+ clustered : seriesSettings ?. clustered || false ,
53+ valueXField : 'Timestamp' ,
54+ valueYField : 'Close' ,
55+ highValueYField : 'High' ,
56+ lowValueYField : 'Low' ,
57+ openValueYField : 'Open' ,
58+ calculateAggregates : true ,
59+ xAxis : dateAxis ,
60+ yAxis : valueAxis ,
61+ legendValueText :
62+ seriesSettings ?. legendValueText ||
63+ '시작가: [bold]{openValueY}[/] 최고가: [bold]{highValueY}[/] 최저가: [bold]{lowValueY}[/] 종가: [bold]{valueY}[/]' ,
64+ legendRangeValueText : seriesSettings ?. legendRangeValueText || '' ,
65+ } ) ,
66+ ) ;
5367
54- if ( isDisposed ( chartRoot , stockChart , mainPanel , valueAxis , dateAxis ) )
55- return ;
68+ stockChart . set ( 'stockSeries' , newValueSeries ) ;
69+ mainPanel . set (
70+ 'cursor' ,
71+ am5xy . XYCursor . new ( chartRoot , {
72+ yAxis : valueAxis ,
73+ xAxis : dateAxis ,
74+ snapToSeries : [ newValueSeries ] ,
75+ snapToSeriesBy : 'y!' ,
76+ } ) ,
77+ ) ;
5678
57- const newValueSeries = mainPanel . series . push (
58- am5xy . CandlestickSeries . new ( chartRoot , {
59- name : seriesSettings ?. name || 'MSFT' ,
60- clustered : seriesSettings ?. clustered || false ,
61- valueXField : 'Timestamp' ,
62- valueYField : 'Close' ,
63- highValueYField : 'High' ,
64- lowValueYField : 'Low' ,
65- openValueYField : 'Open' ,
66- calculateAggregates : true ,
67- xAxis : dateAxis ,
68- yAxis : valueAxis ,
69- legendValueText :
70- seriesSettings ?. legendValueText ||
71- '시작가: [bold]{openValueY}[/] 최고가: [bold]{highValueY}[/] 최저가: [bold]{lowValueY}[/] 종가: [bold]{valueY}[/]' ,
72- legendRangeValueText : seriesSettings ?. legendRangeValueText || '' ,
73- } ) ,
74- ) ;
79+ const volumeSeries = mainPanel . series . push (
80+ am5xy . ColumnSeries . new ( chartRoot , {
81+ name : 'Volume' ,
82+ valueXField : 'Timestamp' ,
83+ valueYField : 'Volume' ,
84+ xAxis : dateAxis ,
85+ yAxis : valueAxis ,
86+ legendValueText : '[bold]{valueY}' ,
87+ legendRangeValueText : '' ,
88+ } ) ,
89+ ) ;
7590
76- stockChart . set ( 'stockSeries' , newValueSeries ) ;
77- mainPanel . set (
78- 'cursor' ,
79- am5xy . XYCursor . new ( chartRoot , {
80- yAxis : valueAxis ,
81- xAxis : dateAxis ,
82- snapToSeries : [ newValueSeries ] ,
83- snapToSeriesBy : 'y!' ,
84- } ) ,
85- ) ;
86- setValueSeries ( newValueSeries ) ;
91+ const valueLegend = mainPanel . plotContainer . children . push (
92+ am5stock . StockLegend . new ( chartRoot , {
93+ stockChart : stockChart ,
94+ } ) ,
95+ ) ;
8796
88- const volumeSeries = mainPanel . series . push (
89- am5xy . ColumnSeries . new ( chartRoot , {
90- name : 'Volume' ,
91- valueXField : 'Timestamp' ,
92- valueYField : 'Volume' ,
93- xAxis : dateAxis ,
94- yAxis : valueAxis ,
95- legendValueText : '[bold]{valueY}' ,
96- legendRangeValueText : '' ,
97- } ) ,
98- ) ;
97+ valueLegend . data . setAll ( [ newValueSeries ] ) ;
9998
100- const valueLegend = mainPanel . plotContainer . children . push (
101- am5stock . StockLegend . new ( chartRoot , {
102- stockChart : stockChart ,
103- } ) ,
104- ) ;
99+ dateAxis . on ( 'start' , async ( value ) => {
100+ if ( ! value ) return ;
105101
106- valueLegend . data . setAll ( [ newValueSeries ] ) ;
102+ if ( value < 0 ) {
103+ fetchPastTimeData ?.( ) ;
104+ // dateAxis.zoom(0, 1, 0);
105+ }
106+ } ) ;
107107
108- return ( ) => {
109- newValueSeries . dispose ( ) ;
110- valueLegend . dispose ( ) ;
111- } ;
112- } , [ valueAxis , mainPanel , stockChart , dateAxis , chartRoot , seriesSettings ] ) ;
108+ newValueSeries . data . clear ( ) ;
109+ newValueSeries . data . setAll ( pastTimeData || [ ] ) ;
113110
114111 return children ;
115112}
0 commit comments