11"use client" ;
22
33import ReactECharts from 'echarts-for-react' ;
4- // Import specific types from ECharts
54import type { EChartsOption , LineSeriesOption } from 'echarts' ;
65import { useTheme } from 'next-themes' ;
76import { format } from 'date-fns' ;
@@ -34,23 +33,21 @@ const EchartsTrendChart: React.FC<EchartsTrendChartProps> = ({ trendData }) => {
3433
3534 const seriesData : LineSeriesOption [ ] = trendData . map ( user => {
3635 const data = sortedTimePoints . map ( time => {
37- // Find the last recorded score for the user at or before the current time point
3836 const lastPoint = [ ...user . history ]
3937 . filter ( p => new Date ( p . time ) . getTime ( ) <= time )
40- . pop ( ) ; // The last element is the latest score
41- return lastPoint ? lastPoint . score : 0 ;
38+ . pop ( ) ;
39+ const score = lastPoint ? lastPoint . score : 0 ;
40+ return [ time , score ] ;
4241 } ) ;
4342 return {
4443 name : user . nickname ,
4544 type : 'line' ,
46- step : 'end' , // Use a step chart to accurately represent score changes over time
47- symbol : 'none' , // Do not show symbols on data points for a cleaner look
45+ step : 'end' ,
46+ symbol : 'none' ,
4847 data : data ,
4948 } ;
5049 } ) ;
5150
52- const xAxisData = sortedTimePoints . map ( time => format ( new Date ( time ) , 'HH:mm:ss' ) ) ;
53-
5451 const option : EChartsOption = {
5552 backgroundColor : 'transparent' ,
5653 tooltip : {
@@ -60,38 +57,47 @@ const EchartsTrendChart: React.FC<EchartsTrendChartProps> = ({ trendData }) => {
6057 label : {
6158 backgroundColor : '#6a7985'
6259 }
60+ } ,
61+ formatter : ( params : any ) => {
62+ const time = format ( new Date ( params [ 0 ] . axisValue ) , 'yyyy-MM-dd HH:mm:ss' ) ;
63+ let tooltipHtml = `${ time } <br/>` ;
64+ params . forEach ( ( param : any ) => {
65+ tooltipHtml += `${ param . marker } ${ param . seriesName } : <strong>${ param . value [ 1 ] } </strong><br/>` ;
66+ } ) ;
67+ return tooltipHtml ;
6368 }
6469 } ,
6570 legend : {
6671 data : trendData . map ( user => user . nickname ) ,
6772 textStyle : {
6873 color : theme === 'dark' ? '#ccc' : '#333' ,
6974 } ,
70- bottom : 45 , // Position legend 45px from the bottom, above the slider
71- type : 'scroll' , // Allow legend to scroll if it has too many items
75+ bottom : 45 ,
76+ type : 'scroll' ,
7277 } ,
7378 grid : {
7479 left : '3%' ,
75- right : '50px' , // Increase right margin for vertical dataZoom slider
76- bottom : 80 , // Reserve 80px at the bottom for controls to prevent overlap
80+ right : '50px' ,
81+ bottom : 80 ,
7782 containLabel : true
7883 } ,
7984 toolbox : {
8085 feature : {
8186 saveAsImage : {
8287 title : 'Download' ,
8388 name : 'contest-trend' ,
84- backgroundColor : theme === 'dark' ? '#1f2937' : '#fff' // Set background for saved image
89+ backgroundColor : theme === 'dark' ? '#1f2937' : '#fff'
8590 }
8691 }
8792 } ,
8893 xAxis : [
8994 {
90- type : 'category' ,
91- boundaryGap : false ,
92- data : xAxisData ,
95+ type : 'time' ,
9396 axisLabel : {
94- color : theme === 'dark' ? '#ccc' : '#333'
97+ color : theme === 'dark' ? '#ccc' : '#333' ,
98+ formatter : ( value : number ) => {
99+ return format ( new Date ( value ) , 'yyyy-MM-dd HH:mm' ) ;
100+ }
95101 }
96102 }
97103 ] ,
@@ -104,29 +110,25 @@ const EchartsTrendChart: React.FC<EchartsTrendChartProps> = ({ trendData }) => {
104110 }
105111 ] ,
106112 dataZoom : [
107- // Horizontal slider for X-axis
108113 {
109114 type : 'slider' ,
110115 xAxisIndex : 0 ,
111116 start : 0 ,
112117 end : 100 ,
113- bottom : 10 , // Position 10px from the bottom
118+ bottom : 10 ,
114119 height : 20 ,
115120 } ,
116- // Vertical slider for Y-axis
117121 {
118122 type : 'slider' ,
119123 yAxisIndex : 0 ,
120124 start : 0 ,
121125 end : 100 ,
122- right : 10 , // Position 10px from the right
126+ right : 10 ,
123127 width : 20 ,
124128 } ,
125- // Inside zooming (mouse wheel) for both axes
126129 {
127130 type : 'inside' ,
128131 xAxisIndex : 0 ,
129- yAxisIndex : 0 ,
130132 start : 0 ,
131133 end : 100 ,
132134 } ,
0 commit comments