import 'dart:developer';
import 'package:Player160/widgets/common_graph_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:Player160/constants/app_colors.dart';
import 'package:Player160/constants/assest_path.dart';
class CustomeSfCartesianChart extends StatefulWidget {
final Object data;
final String type;
final String title;
final dynamic avg;
final int? scrollChageIndex;
CustomeSfCartesianChart(
{Key? key,
required this.data,
required this.type,
required this.title,
this.avg,
this.scrollChageIndex})
: super(key: key);
@override
_CustomeSfCartesianChartState createState() =>
_CustomeSfCartesianChartState();
}
class _CustomeSfCartesianChartState extends State<CustomeSfCartesianChart> {
late TooltipBehavior _tooltipBehavior;
dynamic selectIndex = 0;
bool showTooptip = false;
bool callOnce = true;
bool showlastTooptip = false;
dynamic dx = 0;
dynamic dy = 0;
dynamic dataX = 0;
dynamic dataY = 0;
List<SalesData> personalMetricData = [];
dynamic headerValue = '';
dynamic suffixValue = '';
dynamic subtitle = '';
dynamic totalSavetitle = '';
dynamic boxColor = '';
late GlobalKey<State> globalKey;
double? oldAxisVisibleMin, oldAxisVisibleMax;
var mapData;
setUpData() {
mapData =
{
"title": "topSpeedKmh",
"average": 23.012456140350885,
"unit": "",
"data": [
{
"matchId": "01FDYSNHPW6RWG3JEE9W3J1PNJ",
"date": "2021-08-21T21: 00: 00.000Z",
"data": 19.53,
"title": "topSpeedKmh",
"percentage": 0,
"color": Color(0xff82c713),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FXG1HV9ZX84JMHFYP0YXKHWV",
"date": " 2021-09-13T21: 00: 00.000Z",
"data": 25.39,
"title": " topSpeedKmh",
"percentage": 30.00512032770097,
"color": Color(0xff82c713),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FXFF224E0BQ69T0JSPCGZEXB",
"date": "2021-09-13T21: 00: 00.000Z",
"data": 25.39,
"title": "topSpeedKmh",
"percentage": 0.0,
"color": Color(0xffe32326),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FXFAD3TYW5674BFWHE42VRZ0",
"date": "2021-10-04T19: 16: 39.827Z",
"data": 16.82,
"title": "topSpeedKmh",
"percentage": -33.753446238676645,
"color": Color(0xffe32326),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FV02J3WY71H10YKWW14RQP5K",
"date": "2021-12-12T22: 00: 00.000Z",
"data": 16.36,
"title": "topSpeedKmh",
"percentage": -2.7348394768133226,
"color": Color(0xff82c713),
"opponentTeamLogo":
"https: //api.staging.track160.com/api/v0/data/account-01FV01SA2TFRZVZSAMAB44RY4N/media/890ad535-041d-415f-a48b-adf9e9d71ee6",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0
},
{
"matchId": "01FTDZGMXT4NDN0FRHH3QQ60M3",
"date": "2021-12-12T22: 00: 00.000Z",
"data": 16.36,
"title": "topSpeedKmh",
"percentage": 0.0,
"color": Color(0xff82c713),
"opponentTeamLogo":
"https: //api.staging.track160.com/api/v0/data/account-01FT8143DFTR1FPHTA0TK6JTK7/media/652724fc-96bf-4c2d-83e2-512a46ae01a2",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0
},
{
"matchId": "01FV7HT34CR7YHEZ16QY1P995W",
"date": "2021-12-20T22: 00: 00.000Z",
"data": 23.75,
"title": "topSpeedKmh",
"percentage": 45.17114914425429,
"color": Color(0xff82c713),
"opponentTeamLogo":
"https: //api.staging.track160.com/api/v0/data/account-01FV01SA2TFRZVZSAMAB44RY4N/media/9fd8b147-dd41-43f9-8e2b-af86fddf3560",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0
},
{
"matchId": "01FTZ791ZXA9VX7TNK741N9H84",
"date": "2021-12-20T22: 00: 00.000Z",
"data": 23.75,
"title": "topSpeedKmh",
"percentage": 0.0,
"color": Color(0xffe32326),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FX800K4WYFV7K3E3NZYKH87S",
"date": "2022-01-02T22: 00: 00.000Z",
"data": 23.1,
"title": "topSpeedKmh",
"percentage": -2.7368421052631517,
"color": Color(0xff82c713),
"opponentTeamLogo":
"https: //api.staging.track160.com/api/v0/data/account-01FV01SA2TFRZVZSAMAB44RY4N/media/4cb53661-2de2-434b-84c0-396ec5d7db1c",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0
},
{
"matchId": "01FY1MJN2E1B7GEN28CR7SB8GY",
"date": "2022-01-02T22: 00: 00.000Z",
"data": 23.1,
"title": "topSpeedKmh",
"percentage": 0.0,
"color": Color(0xff82c713),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01FXQB2HRNKW437BX2TX27AKVH",
"date": "2022-01-21T22: 00: 00.000Z",
"data": 28.99,
"title": "topSpeedKmh",
'percentage': 25.497835497835485,
"color": Color(0xffe32326),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
{
"matchId": "01G00CRPZAWK05P24KHHHZZKGS",
"date": "2022-01-31T10: 00: 00Z",
"data": 28.85,
"title": "topSpeedKmh",
"percentage": -0.4829251466022664,
"color": Color(0xffe32326),
"opponentTeamLogo": "",
"totalShots": 0,
"accuratePasses": 0,
"totalPasses": 0,
},
]
}
as Map;
personalMetricData.clear();
for (Map<String, dynamic> i in mapData['data']) {
personalMetricData.add(SalesData.fromJson(i));
}
// Key which uses to access the chart state.
globalKey = GlobalKey<State>();
if (personalMetricData.isNotEmpty) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
setState(() {
callOnce = true;
//for display all data
// oldAxisVisibleMin = personalMetricData.length > 6
// ? personalMetricData.length - 6.toDouble()
// : 0.toDouble();
// oldAxisVisibleMax = personalMetricData.length == 1
// ? 1
// : personalMetricData.length - 1.toDouble();
showTooptip = true;
showlastTooptip = true;
dataX = 300.0;
dataY = 50.0;
selectIndex = personalMetricData.length - 1;
subtitle =
'${personalMetricData[selectIndex].percentage.toStringAsFixed(1).contains('.0') ? personalMetricData[selectIndex].percentage.toStringAsFixed(1).split('.0')[0] : personalMetricData[selectIndex].percentage.toStringAsFixed(1)}%';
boxColor = personalMetricData[selectIndex].percentage.isNegative
? AppColors.toolTipRed
: AppColors.parrotGreen;
headerValue = personalMetricData[selectIndex].data.runtimeType == int
? '${personalMetricData[selectIndex].data}'
: '${personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}';
suffixValue = widget.type;
if (widget.title == 'totalSaves') {
totalSavetitle =
'${personalMetricData[selectIndex].data.runtimeType == int ? personalMetricData[selectIndex].data : personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}/${personalMetricData[selectIndex].data.runtimeType == int ? personalMetricData[selectIndex].totalShots : personalMetricData[selectIndex].totalShots.toDouble().toStringAsFixed(1)}';
}
if (widget.title == 'passAccuracy') {
totalSavetitle =
'${personalMetricData[selectIndex].accuratePasses.runtimeType == int ? personalMetricData[selectIndex].accuratePasses : personalMetricData[selectIndex].accuratePasses.toDouble().toStringAsFixed(1)}/${personalMetricData[selectIndex].totalPasses.runtimeType == int ? personalMetricData[selectIndex].totalPasses : personalMetricData[selectIndex].totalPasses.toDouble().toStringAsFixed(1)}';
}
//for display all data
// personalMetricData;
personalMetricData = personalMetricData.length > 6
? personalMetricData.sublist(
personalMetricData.length - 6, personalMetricData.length)
: personalMetricData;
});
});
}
}
@override
void initState() {
_tooltipBehavior = TooltipBehavior(enable: true);
super.initState();
setUpData();
}
@override
void didUpdateWidget(CustomeSfCartesianChart oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.data != widget.data) {
setUpData();
}
}
tool(TooltipArgs args) {
if (personalMetricData.isNotEmpty) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
setState(() {
showTooptip = true;
showlastTooptip = false;
dx = args.locationX;
dy = args.locationY;
selectIndex = args.pointIndex;
subtitle =
'${personalMetricData[selectIndex].percentage.toStringAsFixed(1).contains('.0') ? personalMetricData[selectIndex].percentage.toStringAsFixed(1).split('.0')[0] : personalMetricData[selectIndex].percentage.toStringAsFixed(1)}%';
boxColor = personalMetricData[selectIndex].percentage.isNegative
? AppColors.toolTipRed
: AppColors.parrotGreen;
headerValue = personalMetricData[selectIndex].data.runtimeType == int
? '${personalMetricData[selectIndex].data}'
: '${personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}';
suffixValue = widget.type;
if (widget.title == 'totalSaves') {
totalSavetitle =
'${personalMetricData[selectIndex].data.runtimeType == int ? personalMetricData[selectIndex].data : personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}/${personalMetricData[selectIndex].data.runtimeType == int ? personalMetricData[selectIndex].totalShots : personalMetricData[selectIndex].totalShots.toDouble().toStringAsFixed(1)}';
}
if (widget.title == 'passAccuracy') {
totalSavetitle =
'${personalMetricData[selectIndex].accuratePasses.runtimeType == int ? personalMetricData[selectIndex].accuratePasses : personalMetricData[selectIndex].accuratePasses.toDouble().toStringAsFixed(1)}/${personalMetricData[selectIndex].totalPasses.runtimeType == int ? personalMetricData[selectIndex].totalPasses : personalMetricData[selectIndex].totalPasses.toDouble().toStringAsFixed(1)}';
}
});
});
}
}
markerRender(MarkerRenderArgs args) {
if (personalMetricData.isNotEmpty) {
dynamic markerIndex = args.pointIndex;
if (personalMetricData[markerIndex].percentage.isNegative) {
args.color = AppColors.toolTipRed;
args.borderWidth = 0.0;
args.markerHeight = 12.0;
args.markerWidth = 12.0;
args.borderColor = AppColors.toolTipRed;
} else {
args.color = AppColors.parrotGreen;
args.markerHeight = 12.0;
args.markerWidth = 12.0;
args.borderWidth = 0.0;
args.borderColor = AppColors.parrotGreen;
}
}
}
getfirstmarkerPoint(double x, double y) {
if (callOnce) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
if (personalMetricData.isNotEmpty) {
setState(() {
dataX = x;
dataY = y;
callOnce = false;
});
}
});
}
}
chartTouchInteractionDown(ChartTouchInteractionArgs args) {
if (showTooptip) {
setState(() {
showTooptip = false;
});
} else {
return null;
}
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.18,
width: MediaQuery.of(context).size.width * 0.8,
child: personalMetricData.isNotEmpty
? Stack(
children: [
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: SfCartesianChart(
onChartTouchInteractionDown:
(ChartTouchInteractionArgs args) =>
chartTouchInteractionDown(args),
plotAreaBorderWidth: 0,
//for display all data
// plotAreaBackgroundColor: AppColors.red,
// onActualRangeChanged: (ActualRangeChangedArgs args) {
// if (args.orientation == AxisOrientation.horizontal) {
// oldAxisVisibleMin = args.visibleMin.toDouble();
// oldAxisVisibleMax = args.visibleMax.toDouble();
// }
// },
// enableAxisAnimation: true,
// zoomPanBehavior: ZoomPanBehavior(
// // Enables pinch zooming
// enablePanning: true,
// ),
primaryXAxis: DateTimeAxis(
rangePadding: ChartRangePadding.normal,
dateFormat: DateFormat.MMMd(),
minimum: mapData['data'].isNotEmpty?DateTime.parse(mapData['data'][0]['date']):DateTime(2022,12,30),
maximum: mapData['data'].isNotEmpty?DateTime.parse(mapData['data'][mapData['data'].length-1]['date']):DateTime(2024,12,30),
//for display all data
// interval: 1.0,
// visibleMinimum: oldAxisVisibleMin,
// visibleMaximum: oldAxisVisibleMax,
majorGridLines: const MajorGridLines(
width: 0,
color: AppColors.white,
),
majorTickLines: const MajorTickLines(
width: 0,
color: AppColors.white,
),
labelStyle: const TextStyle(
fontSize: 10,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: AppColors.black),
labelPosition: ChartDataLabelPosition.outside,
edgeLabelPlacement: EdgeLabelPlacement.none,
labelAlignment: LabelAlignment.center,
// labelPlacement: LabelPlacement.onTicks,
// arrangeByIndex: true,
tickPosition: TickPosition.outside,
axisLine: const AxisLine(
color: AppColors.white,
width: 0,
)),
primaryYAxis: NumericAxis(
minimum: 0.0,
isVisible: false,
plotBands: <PlotBand>[
PlotBand(
isVisible: true,
start: widget.avg.toInt(),
end: widget.avg.toInt(),
borderWidth: 0.5,
borderColor: AppColors.grey8,
),
],
),
tooltipBehavior: TooltipBehavior(
canShowMarker: true,
enable: true,
),
onTooltipRender: (TooltipArgs args) => tool(args),
// Callback to customize the marker
onMarkerRender: (MarkerRenderArgs args) =>
markerRender(args),
series: <ChartSeries>[
LineSeries<SalesData, DateTime>(
// onCreateRenderer:
// (ChartSeries<dynamic, dynamic> series) {
// return CustomLineSeriesRenderer(
// series, getfirstmarkerPoint);
// },
enableTooltip: true,
markerSettings: const MarkerSettings(
shape: DataMarkerType.circle,
isVisible: true,
width: 12.0,
height: 12.0),
dataSource: personalMetricData,
pointColorMapper: (SalesData sales, _) =>
sales.color,
xValueMapper: (SalesData sales, _) => sales.date,
yValueMapper: (SalesData sales, _) =>
sales.data.toInt())
]),
),
Positioned(
//adding (MediaQuery.of(context).size.width * 0.15) for MA-370
// MediaQuery.of(context).size.width * 0.07
left: selectIndex == personalMetricData.length - 6
? MediaQuery.of(context).size.width * 0.14
: selectIndex == 0
? MediaQuery.of(context).size.width * 0.15
: 0.0,
child: Transform.translate(
offset: Offset(
showlastTooptip
? dataX.toDouble() - 65
: dx.toDouble() - 65,
showlastTooptip
? dataY.toDouble() - 45
: dy.toDouble() - 45),
child: showTooptip
? CommonGraphTooltip(
extraTitle: totalSavetitle,
boxColor: boxColor,
changePercentage: subtitle,
data: headerValue,
unit: suffixValue,
title: widget.title,
)
: Container(
color: AppColors.white,
),
))
],
)
: Container(
color: AppColors.white,
));
}
}
class CustomLineSeriesRenderer extends LineSeriesRenderer {
CustomLineSeriesRenderer(this.series, this.callBack);
ChartSeries<dynamic, dynamic> series;
final Function callBack;
@override
void drawDataMarker(int index, Canvas canvas, Paint fillPaint,
Paint strokePaint, double pointX, double pointY,
[CartesianSeriesRenderer? seriesRenderer]) {
if (index == series.dataSource!.length - 1) {
callBack(pointX, pointY);
} else if (series.dataSource!.length - 1 > 5 &&
(index + (series.dataSource!.length - 1) - 5) ==
series.dataSource!.length - 1) {
callBack(pointX, pointY);
}
super.drawDataMarker(
index, canvas, fillPaint, strokePaint, pointX, pointY, seriesRenderer);
}
}
class SalesData {
SalesData(this.date, this.data, this.percentage, this.color, this.totalShots,
this.accuratePasses, this.totalPasses);
final DateTime date;
final dynamic data;
final dynamic percentage;
final dynamic color;
final dynamic totalShots;
final dynamic accuratePasses;
final dynamic totalPasses;
factory SalesData.fromJson(Map<String, dynamic> dummydata) {
return SalesData(
// DateFormat.yMMMd()
// .format(DateTime.parse(dummydata['date']))
// .toString()
// .split(',')[0],
DateTime.parse(dummydata['date']),
// dummydata['date'].toString().split(',')[0],
dummydata['data'],
dummydata['percentage'],
dummydata['color'],
dummydata['totalShots'],
dummydata['accuratePasses'],
dummydata['totalPasses']
// dummydata[]
);
}
}