@@ -10,9 +10,8 @@ import {
10
10
GraphicComponent ,
11
11
} from 'echarts/components' ;
12
12
import { ECharts , EChartsOption } from 'echarts' ;
13
- import { mockData } from './mockData' ;
14
- import { colors } from '@pinpoint-fe/ui/src/constants' ;
15
- import { capitalize , set } from 'lodash' ;
13
+ import { colors , GetHeatmapAppData } from '@pinpoint-fe/ui/src/constants' ;
14
+ import { capitalize , debounce } from 'lodash' ;
16
15
import { defaultTickFormatter } from '@pinpoint-fe/ui/src/components/ReChart' ;
17
16
import { HeatmapSettingType } from './HeatmapSetting' ;
18
17
@@ -30,24 +29,29 @@ echarts.use([HeatmapChartEcharts, CanvasRenderer]);
30
29
export const HeatmapColor = {
31
30
success : '#34b994' ,
32
31
failed : '#eb4748' ,
32
+ selected : 'blue' ,
33
33
} ;
34
34
35
35
type HeatmapChartCoreProps = {
36
+ isLoading ?: boolean ;
37
+ data ?: GetHeatmapAppData . Response ;
36
38
setting : HeatmapSettingType ;
37
39
} ;
38
40
39
41
const HeatmapChartCore = React . forwardRef (
40
- ( { setting } : HeatmapChartCoreProps , ref : React . Ref < ReactEChartsCore > ) => {
42
+ ( { data , setting } : HeatmapChartCoreProps , ref : React . Ref < ReactEChartsCore > ) => {
41
43
const containerRef = React . useRef < HTMLDivElement > ( null ) ;
42
44
const [ containerSize , setContainerSize ] = React . useState ( {
43
45
width : 0 ,
44
46
height : 0 ,
45
47
} ) ;
48
+ const chartRef = React . useRef < ReactEChartsCore > ( null ) ;
46
49
47
- const successData : [ string , string , number ] [ ] = [ ] ;
48
- const failedData : [ string , string , number ] [ ] = [ ] ;
49
- let maxFailedCount = 0 ;
50
- let maxSuccessCount = 0 ;
50
+ const [ successRange , setSuccessRange ] = React . useState ( ) ; // 성공 범위: [시작, 끝]
51
+ const [ failRange , setFailRange ] = React . useState ( ) ; // 성공 범위: [시작, 끝]
52
+
53
+ const [ startCell , setStartCell ] = React . useState ( '' ) ; // 시작 셀: x-y
54
+ const [ endCell , setEndCell ] = React . useState ( '' ) ; // 끝 셀: x-y
51
55
52
56
React . useEffect ( ( ) => {
53
57
const wrapperElement = containerRef . current ;
@@ -65,45 +69,90 @@ const HeatmapChartCore = React.forwardRef(
65
69
} ;
66
70
} , [ ] ) ;
67
71
68
- const { matrixData } = mockData ;
69
- matrixData . forEach ( ( row ) => {
70
- row . cellData . forEach ( ( cell ) => {
71
- successData . push ( [ String ( row . timestamp ) , String ( cell . elapsedTime ) , cell . successCount ] ) ;
72
- failedData . push ( [ String ( row . timestamp ) , String ( cell . elapsedTime ) , cell . failCount ] ) ;
72
+ const isSelectedCell = React . useCallback (
73
+ ( x : number , y : number ) => {
74
+ const [ startX , startY ] = startCell . split ( '-' ) . map ( Number ) ;
75
+ const [ endX , endY ] = endCell . split ( '-' ) . map ( Number ) ;
76
+
77
+ if ( ! startX || ! startY || ! endX || ! endY ) {
78
+ return false ;
79
+ }
80
+
81
+ const left = Math . min ( startX , endX ) ;
82
+ const right = Math . max ( startX , endX ) ;
83
+ const top = Math . max ( startY , endY ) ;
84
+ const bottom = Math . min ( startY , endY ) ;
85
+
86
+ return x >= left && x <= right && y <= top && y >= bottom ;
87
+ } ,
88
+ [ startCell , endCell ] ,
89
+ ) ;
90
+
91
+ const dataForRender = React . useMemo ( ( ) => {
92
+ const successData : [ string , string , number ] [ ] = [ ] ;
93
+ const failData : {
94
+ value : [ string , string , number ] ;
95
+ itemStyle ?: {
96
+ color : string ;
97
+ opacity : number ;
98
+ } ;
99
+ } [ ] = [ ] ;
100
+ let maxFailCount = 0 ;
101
+ let maxSuccessCount = 0 ;
73
102
74
- maxSuccessCount = Math . max ( maxSuccessCount , cell . successCount ) ;
75
- maxFailedCount = Math . max ( maxFailedCount , cell . failCount ) ;
103
+ const { heatmapData } = data || { } ;
104
+ heatmapData ?. forEach ( ( row ) => {
105
+ row ?. cellDataList ?. forEach ( ( cell ) => {
106
+ successData . push ( [ String ( row . timestamp ) , String ( cell . elapsedTime ) , cell . successCount ] ) ;
107
+ failData . push ( {
108
+ value : [ String ( row . timestamp ) , String ( cell . elapsedTime ) , cell . failCount ] ,
109
+ itemStyle : isSelectedCell ( row . timestamp , cell . elapsedTime )
110
+ ? {
111
+ color : HeatmapColor . selected ,
112
+ opacity : 0.8 ,
113
+ }
114
+ : undefined ,
115
+ } ) ;
116
+
117
+ maxSuccessCount = Math . max ( maxSuccessCount , cell . successCount ) ;
118
+ maxFailCount = Math . max ( maxFailCount , cell . failCount ) ;
119
+ } ) ;
76
120
} ) ;
77
- } ) ;
78
121
79
- const totalSuccessCount = setting . yMax ;
80
- const totalFailedCount = setting . yMax ;
122
+ return { successData , failData , maxFailCount , maxSuccessCount } ;
123
+ } , [ data , startCell , endCell ] ) ;
81
124
82
- const xAxisData = matrixData . map ( ( row ) => String ( row . timestamp ) ) ;
83
- const yAxisData = matrixData [ 0 ] . cellData . map ( ( cell ) => String ( cell . elapsedTime ) ) ;
125
+ const xAxisData = React . useMemo ( ( ) => {
126
+ return data ?. heatmapData ?. map ( ( row ) => String ( row . timestamp ) ) || [ ] ;
127
+ } , [ data ] ) ;
128
+ const yAxisData = React . useMemo ( ( ) => {
129
+ return data ?. heatmapData ?. [ 0 ] . cellDataList ?. map ( ( cell ) => String ( cell . elapsedTime ) ) || [ ] ;
130
+ } , [ data ] ) ;
84
131
85
- // console.log('successData', successData);
86
- // console.log('failedData', failedData);
132
+ const totalSuccessCount = React . useMemo ( ( ) => {
133
+ return data ?. summary ?. totalSuccessCount || 0 ;
134
+ } , [ data ] ) ;
135
+ const totalFailedCount = React . useMemo ( ( ) => {
136
+ return data ?. summary ?. totalFailCount || 0 ;
137
+ } , [ data ] ) ;
87
138
88
139
const option : EChartsOption = {
89
140
tooltip : {
141
+ show : ! ! startCell ? false : true ,
90
142
borderColor : colors . gray [ 300 ] ,
91
143
textStyle : {
92
144
fontFamily : 'inherit' ,
93
145
fontSize : 8 ,
94
146
} ,
95
147
formatter : ( params : any ) => {
96
148
const { data } = params ;
97
- const [ timestamp , elapsedTime , failedCount ] = data ;
98
- const date = new Date ( timestamp ) ;
99
- const successCount =
100
- successData . find (
101
- ( item : [ string , string , number ] ) => item [ 0 ] === timestamp && item [ 1 ] === elapsedTime ,
102
- ) ?. [ 2 ] || 'N/A' ;
103
-
149
+ const [ timestamp , elapsedTime , failedCount ] = data ?. value ;
150
+ const successCount = dataForRender ?. successData . find ( ( item : [ string , string , number ] ) => {
151
+ return item [ 0 ] === timestamp && item [ 1 ] === elapsedTime ;
152
+ } ) ?. [ 2 ] ;
104
153
return `
105
154
<div style="display: flex; flex-direction: column; gap: 5px; padding: 2px;">
106
- <div style="margin-bottom: 5px;"><strong>${ defaultTickFormatter ( date . getTime ( ) ) } </strong></div>
155
+ <div style="margin-bottom: 5px;"><strong>${ defaultTickFormatter ( Number ( timestamp ) ) } </strong></div>
107
156
${ [ 'success' , 'failed' ]
108
157
. map ( ( type ) => {
109
158
const count = type === 'success' ? successCount : failedCount ;
@@ -114,7 +163,7 @@ const HeatmapChartCore = React.forwardRef(
114
163
<div style="display: flex; gap: 6px; align-items: center;">
115
164
<div style="width: 8px; height: 8px; background: ${ color } "></div>${ capitalize ( type ) }
116
165
</div>
117
- <div>${ Number ( count ) . toLocaleString ( ) } </div>
166
+ <div>${ count === undefined ? 'N/A' : Number ( count ) . toLocaleString ( ) } </div>
118
167
</div>
119
168
` ;
120
169
} )
@@ -127,18 +176,17 @@ const HeatmapChartCore = React.forwardRef(
127
176
left : setting . yMax . toString ( ) . length * 10 ,
128
177
right : '10px' ,
129
178
top : '2%' ,
130
- bottom : '20% ' ,
179
+ bottom : '100px ' ,
131
180
} ,
132
181
xAxis : {
133
182
type : 'category' ,
134
- data : xAxisData . sort ( ( a , b ) => new Date ( a ) . getTime ( ) - new Date ( b ) . getTime ( ) ) ,
183
+ data : xAxisData . sort ( ( a , b ) => Number ( a ) - Number ( b ) ) ,
135
184
axisLabel : {
136
185
interval : 'auto' ,
137
186
showMaxLabel : true ,
138
187
showMinLabel : true ,
139
188
formatter : ( value : string ) => {
140
- const date = new Date ( value ) ;
141
- return defaultTickFormatter ( date . getTime ( ) ) ;
189
+ return defaultTickFormatter ( Number ( value ) ) ;
142
190
} ,
143
191
} ,
144
192
} ,
@@ -173,14 +221,16 @@ const HeatmapChartCore = React.forwardRef(
173
221
} ,
174
222
visualMap : [
175
223
{
224
+ id : 'success' ,
176
225
min : 0 ,
177
- max : maxSuccessCount ,
226
+ max : dataForRender ?. maxSuccessCount ,
178
227
calculable : true ,
179
228
seriesIndex : 0 ,
180
229
orient : 'horizontal' ,
230
+ itemWidth : 14 ,
181
231
itemHeight : ( containerSize . width || 100 ) * 0.3 ,
182
232
right : '45%' ,
183
- bottom : '4 %' ,
233
+ bottom : '5 %' ,
184
234
hoverLink : false ,
185
235
formatter : ( value ) => {
186
236
if ( value === setting . yMax ) {
@@ -189,25 +239,29 @@ const HeatmapChartCore = React.forwardRef(
189
239
return Math . floor ( Number ( value ) ) . toLocaleString ( ) ;
190
240
} ,
191
241
inRange : {
192
- color : [ '#ffffff' , HeatmapColor . success ] ,
242
+ color : [ '#ffffff' , dataForRender ?. maxFailCount ? HeatmapColor . success : '#ffffff' ] ,
193
243
} ,
244
+ range : successRange ,
194
245
} ,
195
246
{
247
+ id : 'fail' ,
196
248
min : 0 ,
197
- max : maxFailedCount ,
249
+ max : dataForRender ?. maxFailCount ,
198
250
calculable : true ,
199
251
seriesIndex : 1 ,
200
252
orient : 'horizontal' ,
253
+ itemWidth : 14 ,
201
254
itemHeight : ( containerSize . width || 100 ) * 0.3 ,
202
255
left : '55%' ,
203
- bottom : '4 %' ,
256
+ bottom : '5 %' ,
204
257
hoverLink : false ,
205
258
formatter : ( value ) => {
206
259
return Math . floor ( Number ( value ) ) . toLocaleString ( ) ;
207
260
} ,
208
261
inRange : {
209
- color : [ '#ffffff' , HeatmapColor . failed ] ,
262
+ color : [ '#ffffff' , dataForRender ?. maxFailCount ? HeatmapColor . failed : '#ffffff' ] ,
210
263
} ,
264
+ range : failRange ,
211
265
} ,
212
266
] ,
213
267
graphic : [
@@ -236,12 +290,12 @@ const HeatmapChartCore = React.forwardRef(
236
290
{
237
291
name : 'success' ,
238
292
type : 'heatmap' ,
239
- data : successData ,
293
+ data : dataForRender ?. successData ,
240
294
} ,
241
295
{
242
296
name : 'failed' ,
243
297
type : 'heatmap' ,
244
- data : failedData ,
298
+ data : dataForRender ?. failData ,
245
299
itemStyle : {
246
300
opacity : 0.5 ,
247
301
} ,
@@ -261,7 +315,37 @@ const HeatmapChartCore = React.forwardRef(
261
315
ref = { ref }
262
316
echarts = { echarts }
263
317
option = { option }
264
- style = { { height : '100%' , width : '100%' , minHeight : 500 } }
318
+ style = { { height : '100%' , width : '100%' } }
319
+ onEvents = { {
320
+ mousedown : ( params : any , echartsInstance : ECharts ) => {
321
+ console . log ( 'mousedown' , params ) ;
322
+ setStartCell ( `${ params . value [ 0 ] } -${ params . value [ 1 ] } ` ) ;
323
+ setEndCell ( `${ params . value [ 0 ] } -${ params . value [ 1 ] } ` ) ;
324
+ } ,
325
+ mousemove : ( params : any ) => {
326
+ if ( ! startCell ) {
327
+ return ;
328
+ }
329
+ setEndCell ( `${ params . value [ 0 ] } -${ params . value [ 1 ] } ` ) ;
330
+ } ,
331
+ mouseup : ( params : any ) => {
332
+ console . log ( 'mouseup' , params , startCell , endCell ) ;
333
+ setStartCell ( '' ) ;
334
+ setEndCell ( '' ) ;
335
+ } ,
336
+ datarangeselected : debounce ( ( params : any ) => {
337
+ if ( params . visualMapId === 'success' ) {
338
+ setSuccessRange ( params . selected ) ;
339
+ } else if ( params . visualMapId === 'fail' ) {
340
+ setFailRange ( params . selected ) ;
341
+ }
342
+ } , 300 ) ,
343
+ // click: (params: any, echartsInstance: ECharts) => {
344
+ // console.log('click', params);
345
+ // setStartCell(`${params.value[0]}-${params.value[1]}`);
346
+ // // setRange([1000, 3000]);
347
+ // },
348
+ } }
265
349
/>
266
350
</ div >
267
351
) ;
0 commit comments