import 'dart:developer';
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 dynamic avg;
final int? scrollChageIndex;
CustomeSfCartesianChart(
{Key? key,
required this.data,
required this.type,
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 boxColor = '';
late GlobalKey<State> globalKey;
double? oldAxisVisibleMin, oldAxisVisibleMax;
setUpData() {
var mapData = widget.data as Map;
print('Data item2${widget.data}');
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;
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.toDouble().toStringAsFixed(1)}%';
boxColor = personalMetricData[selectIndex].percentage.isNegative
? AppColors.toolTipRed
: AppColors.parrotGreen;
headerValue =
'${personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}';
suffixValue = widget.type;
personalMetricData;
// '${widget.type == 'topSpeed' ? 'km/h' : widget.type == 'totalDistance' ? 'km' : widget.type == 'possesion' ? '%' : 'min'}';
});
});
}
}
@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.toInt().toDouble().toStringAsFixed(1)}%';
boxColor = personalMetricData[selectIndex].percentage.isNegative
? AppColors.toolTipRed
: AppColors.parrotGreen;
headerValue =
'${personalMetricData[selectIndex].data.toDouble().toStringAsFixed(1)}';
suffixValue = widget.type;
// '${widget.type == 'topSpeed' ? 'km/h' : widget.type == 'totalDistance' ? 'km' : widget.type == 'possesion' ? '%' : 'min'}';
});
});
}
}
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;
});
}
});
}
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.2,
width: MediaQuery.of(context).size.width * 0.8,
child: personalMetricData.isNotEmpty
? Stack(
children: [
SfCartesianChart(
onChartTouchInteractionDown:
(ChartTouchInteractionArgs args) {
setState(() {
showTooptip = false;
});
},
plotAreaBorderWidth: 0,
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: CategoryAxis(
interval: 1,
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.inside,
axisLine: const AxisLine(
color: AppColors.white,
width: 0,
)),
primaryYAxis: NumericAxis(
isVisible: false,
rangePadding: ChartRangePadding.normal,
plotBands: <PlotBand>[
PlotBand(
textStyle: const TextStyle(
color: AppColors.grey8,
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400),
// horizontalTextPadding: '-50%',
textAngle: 0,
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, String>(
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(
left: selectIndex == personalMetricData.length - 6
? MediaQuery.of(context).size.width * 0.07
: 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() - 40
: dy.toDouble() - 40),
child: showTooptip
? Stack(
children: <Widget>[
Container(
child: selectIndex == 0
? Image.asset(
AssetPath.bubbleLeft,
color: boxColor,
width: MediaQuery.of(context)
.size
.width *
0.22,
fit: BoxFit.contain,
)
: Image.asset(
AssetPath.bubbleRight,
color: boxColor,
width: MediaQuery.of(context)
.size
.width *
0.22,
fit: BoxFit.contain,
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
top: 3.0, left: 15.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Text('$headerValue',
textScaleFactor: 1.0,
style: TextStyle(
color: boxColor ==
AppColors
.parrotGreen
? AppColors.black
: AppColors.white,
fontSize: 14.0,
fontFamily: 'Lato',
fontWeight:
FontWeight.w400)),
Padding(
padding: const EdgeInsets.only(
left: 5.0),
child: Text(
'$suffixValue',
textScaleFactor: 1.0,
style: TextStyle(
color: boxColor ==
AppColors
.parrotGreen
? AppColors.black
: AppColors.white,
fontSize: 10.0,
fontFamily: 'Lato',
fontWeight:
FontWeight.w400),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 3.0, left: 15.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Icon(
boxColor == AppColors.parrotGreen
? Icons.arrow_upward
: Icons
.arrow_downward_outlined,
size: 13,
color: boxColor ==
AppColors.parrotGreen
? AppColors.black
: AppColors.white,
),
Text(
'($subtitle)',
textScaleFactor: 1.0,
style: TextStyle(
color: boxColor ==
AppColors.parrotGreen
? AppColors.black
: AppColors.white,
fontSize: 12.0,
fontFamily: 'Lato',
fontWeight: FontWeight.w400),
),
],
),
),
],
),
],
)
: 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,
);
final String date;
final dynamic data;
final dynamic percentage;
final dynamic color;
factory SalesData.fromJson(Map<String, dynamic> dummydata) {
return SalesData(
DateFormat.yMMMd()
.format(DateTime.parse(dummydata['date']))
.toString()
.split(',')[0],
// dummydata['date'].toString().split(',')[0],
dummydata['data'],
dummydata['percentage'],
dummydata['color'],
// dummydata[]
);
}
}