chart clickable changs

This commit is contained in:
venbaittech 2025-12-15 16:17:49 +05:30
parent dda10c8d91
commit 23fd21b82b
8 changed files with 522 additions and 196 deletions

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,16 @@ class BarData {
final Color color;
final double value1;
final double value2;
final String id;
final String chartName;
final double shadowValue;
const BarData(this.color, this.value1, this.value2, this.shadowValue);
const BarData(
this.color,
this.value1,
this.value2,
this.id,
this.chartName,
this.shadowValue,
);
}

View File

@ -9,9 +9,9 @@ class ChartLayoutNotifier extends StateNotifier<List<ChartItem>> {
ChartLayoutNotifier() : super(_initialCharts);
static final List<BarData> _defaultData = [
BarData(Colors.blue, 10, 5, 8),
BarData(Colors.orange, 12, 6, 10),
BarData(Colors.green, 8, 5, 5),
BarData(Colors.blue, 10, 5, '4', 'a', 8),
BarData(Colors.orange, 12, 6, '5', 'b', 10),
BarData(Colors.green, 8, 5, '6', 'c', 5),
];
static final List<ChartItem> _initialCharts = [

View File

@ -1,3 +1,4 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
@ -9,6 +10,7 @@ import '../../../../core/services/api_service.dart';
import '../../../../data/models/bar_data.dart';
import '../../../providers/userRoleProvider.dart';
import '../../../themes/charts/barChart.dart';
import '../../../themes/indicators/input_field_decoration.dart';
class BussinessDashboard extends ConsumerStatefulWidget {
const BussinessDashboard({super.key});
@ -21,6 +23,8 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
dynamic managerId;
late ApiService apiService;
String? selectedInsurer;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getBusinessDshBdData = [];
List<Map<String, dynamic>> originalData = [];
@ -39,6 +43,12 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
List<Map<String, dynamic>> originalInsurerWise = [];
List<Map<String, dynamic>> filteredInsurerWise = [];
List<Map<String, dynamic>> getInsuranceTypeData = [];
List<Map<String, dynamic>> filteredInsuranceData = [];
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
bool isLoading = false;
bool isInsureWisePolicy = true;
bool isBrokerWisePolicy = true;
@ -175,6 +185,8 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
isInsureWisePolicy
? parseDouble(item['total_policies_pre_month'])
: parseDouble(item['total_premium_pre_month']),
item['insurer_id'] != null ? item['insurer_id'] : '0',
'Insurer',
5,
);
}).toList();
@ -213,6 +225,8 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
isBrokerWisePolicy
? parseDouble(item['total_policies_pre_month'])
: parseDouble(item['total_premium_pre_month']),
item['broker_id'] != null ? item['broker_id'] : '0',
'Broker',
5,
);
}).toList();
@ -251,6 +265,8 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
isProductWisePolicy
? parseDouble(item['total_policies_pre_month'])
: parseDouble(item['total_premium_pre_month']),
item['vehicle_type'] != null ? item['vehicle_type'] : '0',
'Product',
10,
);
}).toList();
@ -362,51 +378,64 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
final chartInsurerLabels = buildInsurerLabels();
print('chartInsurerData - $chartInsurerData');
print('chartInsurerLabels - $chartInsurerLabels');
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Insurer Wise (Previous / Current Month)',
style: _chartHeader,
return Card(
margin: const EdgeInsets.only(right: 10),
color: Colors.white,
elevation: 1, // card shadow
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer Wise', style: _chartHeader),
Text(
'(Previous / Current Month)',
style: _chartHeader.copyWith(
color: Colors.black87,
fontSize: 8,
),
),
],
),
),
),
Text(
isInsureWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isInsureWisePolicy,
onChanged: (val) => setState(() => isInsureWisePolicy = val),
// buildInsurer(context),
Text(
isInsureWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isInsureWisePolicy,
onChanged: (val) =>
setState(() => isInsureWisePolicy = val),
),
),
],
),
SizedBox(height: 10),
Expanded(
child: Container(
clipBehavior: Clip.none,
// color: Colors.red.shade100,
child: CustomBarChart(
dataList: chartInsurerData,
labels: chartInsurerLabels,
),
),
],
),
SizedBox(height: 10),
Expanded(
child: Container(
clipBehavior: Clip.none,
// color: Colors.red.shade100,
child: CustomBarChart(
dataList: chartInsurerData,
labels: chartInsurerLabels,
),
),
),
legendWidget(),
],
legendWidget(),
],
),
),
);
}
@ -416,46 +445,50 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
final chartBrokerLabels = buildBrokerLabels();
print('chartBrokerData - $chartBrokerData');
print('chartBrokerLabels - $chartBrokerLabels');
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Broker Wise (Previous / Current Month)',
style: _chartHeader,
return Card(
margin: const EdgeInsets.only(right: 10),
color: Colors.white,
elevation: 1, // card shadow
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Broker Wise (Previous / Current Month)',
style: _chartHeader,
),
),
),
Text(
isBrokerWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isBrokerWisePolicy,
onChanged: (val) => setState(() => isBrokerWisePolicy = val),
Text(
isBrokerWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
),
],
),
SizedBox(height: 10),
Expanded(
child: CustomBarChart(
dataList: chartBrokerData,
labels: chartBrokerLabels,
Transform.scale(
scale: 0.5,
child: Switch(
value: isBrokerWisePolicy,
onChanged: (val) =>
setState(() => isBrokerWisePolicy = val),
),
),
],
),
),
legendWidget(),
],
SizedBox(height: 10),
Expanded(
child: CustomBarChart(
dataList: chartBrokerData,
labels: chartBrokerLabels,
),
),
legendWidget(),
],
),
),
);
}
@ -465,46 +498,49 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
final chartProductLabels = buildProductLabels();
print('chartProductData - $chartProductData');
print('chartProductLabels - $chartProductLabels');
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Product Wise (Previous / Current Month)',
style: _chartHeader,
return Card(
margin: const EdgeInsets.only(right: 10),
color: Colors.white,
elevation: 1, // card shadow
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Product Wise (Previous / Current Month)',
style: _chartHeader,
),
),
),
Text(
isProductWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isProductWisePolicy,
onChanged: (val) => setState(() => isProductWisePolicy = val),
Text(
isProductWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
),
],
),
SizedBox(height: 10),
Expanded(
child: CustomBarChart(
dataList: chartProductData,
labels: chartProductLabels,
Transform.scale(
scale: 0.5,
child: Switch(
value: isProductWisePolicy,
onChanged: (val) =>
setState(() => isProductWisePolicy = val),
),
),
],
),
),
legendWidget(),
],
SizedBox(height: 10),
Expanded(
child: CustomBarChart(
dataList: chartProductData,
labels: chartProductLabels,
),
),
legendWidget(),
],
),
),
);
}
@ -523,6 +559,273 @@ class _BussinessDashboardState extends ConsumerState<BussinessDashboard> {
],
);
}
// Helper: Insurance plan type dropdown
Widget buildInsurer(BuildContext context) {
Map<String, dynamic>? selectedInsurerd = filteredInsurerWise.firstWhere(
(item) => item['id'].toString() == selectedInsurer,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 20,
width: MediaQuery.of(context).size.width * 0.08,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyInsurer,
selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null,
// items: (filter, infiniteScrollProps) {
// return filteredInsurersData;
// },
items: (filter, infiniteScrollProps) async {
if (filter.isEmpty) {
return filteredInsurerWise;
}
return filteredInsurerWise.where((item) {
return item['short_name'].toString().toLowerCase().contains(
filter.toLowerCase(),
);
}).toList();
},
itemAsString: (val) => val['short_name'].toString(), // what to show
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // compare by id
validator: (val) {
if (val == null) {
return "Required"; // error message
}
return null;
},
suffixProps: DropdownSuffixProps(
// make sure the dropdown button is visible
dropdownButtonProps: DropdownButtonProps(
isVisible: true,
padding: EdgeInsets.zero, // remove default padding
constraints: const BoxConstraints(
// shrink icon tap area
minWidth: 12,
minHeight: 12,
),
iconSize: 15, // smaller icon
// icon: const Icon(Icons.arrow_drop_down),
),
),
dropdownBuilder: (context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem != null
? selectedItem['short_name'].toString()
: "",
style: GoogleFonts.poppins(
fontSize: 11,
color: Color(0XFF6366F1),
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
softWrap: false,
),
),
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Insurer",
).copyWith(
filled: true,
fillColor:
Colors.white, // 👈 makes the dropdown input white
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
color: Color(0XFF6366F1),
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
color: Color(0XFF6366F1),
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 6,
),
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
menuProps: MenuProps(
backgroundColor:
Colors.white, // 👈 sets dropdown background to white
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
style: GoogleFonts.inter(fontSize: 11, color: Colors.black),
autofocus: true,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(1),
filled: true,
fillColor: Colors.white,
hintText: "Search Insurer...",
hintStyle: GoogleFonts.inter(
fontSize: 12,
color: Colors.black,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
itemBuilder: (context, item, isDisabled, isSelected) {
return Container(
// color: isSelected ? Colors.blue.withOpacity(0.1) : null,
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
child: Text(
item['short_name'].toString(),
style: GoogleFonts.inter(fontSize: 12, color: Colors.black),
),
);
},
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Insurer : ${val['name']}");
print("Id: ${val['id']}");
selectedInsurer = val['id'];
// widget.onInsurerChanged?.call(val['id']);
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
List<Map<String, dynamic>> _filterInsurancePlans(String filter) {
if (filter.isEmpty) return filteredInsuranceData;
return filteredInsuranceData.where((plan) {
return plan['insurance_plan_type'].toString().toLowerCase().contains(
filter.toLowerCase(),
);
}).toList();
}
DropdownSuffixProps _buildDropdownSuffix() {
return DropdownSuffixProps(
dropdownButtonProps: DropdownButtonProps(
isVisible: true,
padding: EdgeInsets.zero,
constraints: BoxConstraints(minWidth: 12, minHeight: 12),
iconSize: 8,
color: Colors.black45,
),
);
}
Widget _buildDropdownDisplay(dynamic selectedItem, String key, String hint) {
bool isEmpty =
selectedItem == null ||
selectedItem.isEmpty ||
selectedItem[key] == null;
return Container(
padding: EdgeInsets.zero,
alignment: Alignment.centerLeft,
child: Text(
isEmpty ? hint : selectedItem[key].toString(),
style: GoogleFonts.poppins(
fontSize: 11,
color: isEmpty ? Colors.grey.shade500 : Colors.black,
fontWeight: FontWeight.w400,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
softWrap: false,
),
);
}
DropDownDecoratorProps _buildDropdownDecorator() {
return DropDownDecoratorProps(
decoration: AppInputDecorations.dropdownDecoration().copyWith(
filled: true,
fillColor: Colors.white,
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(color: Color(0xFFE2E8F0), width: 0.5),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(color: Color(0xFFE2E8F0), width: 0.5),
),
contentPadding: EdgeInsets.symmetric(horizontal: 1, vertical: 6),
),
);
}
PopupProps<Map<String, dynamic>> _buildDropdownPopup(String displayKey) {
return PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 300, minWidth: 200),
menuProps: MenuProps(
backgroundColor: Colors.white,
elevation: 8,
borderRadius: BorderRadius.circular(8),
),
showSearchBox: true,
searchFieldProps: TextFieldProps(
autofocus: true,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
filled: true,
fillColor: Color(0xFFF8FAFC),
hintText: "Search...",
hintStyle: GoogleFonts.inter(fontSize: 11, color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(color: Color(0xFFE2E8F0)),
),
),
),
itemBuilder: (context, item, isDisabled, isSelected) {
return Container(
color: isSelected ? Colors.blue.withOpacity(0.1) : Colors.white,
padding: EdgeInsets.symmetric(horizontal: 5, vertical: 5),
child: Text(
item[displayKey].toString(),
style: GoogleFonts.inter(
fontSize: 11,
color: Colors.black87,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
),
),
);
},
);
}
}
final _headerStyle2 = GoogleFonts.poppins(

View File

@ -300,6 +300,8 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
isInsureWisePolicy
? parseDouble(item['total_policies_pre_month'])
: parseDouble(item['total_premium_pre_month']),
item['vehicle_type'] != null ? item['vehicle_type'] : 0,
'Productivity',
5,
);
}).toList();
@ -327,6 +329,8 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
isProductWisePolicy
? parseDouble(item['total_policies_pre_month'])
: parseDouble(item['total_premium_pre_month']),
item['vehicle_type'],
'Productivity',
10,
);
}).toList();
@ -416,59 +420,61 @@ class _ProductivityDashboardState extends ConsumerState<ProductivityDashboard> {
final chartStaffData = buildStaffBarData();
final chartStaffLabels = buildStaffLabels();
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(right: 20),
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Sales Executive Product Wise (Previous / Current Month)',
style: _chartHeader,
return Card(
margin: const EdgeInsets.only(right: 10),
color: Colors.white,
shadowColor: Colors.black,
elevation: 1, // card shadow
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
'Sales Executive Product Wise (Previous / Current Month)',
style: _chartHeader,
),
),
),
Text(
isInsureWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
Transform.scale(
scale: 0.5,
child: Switch(
value: isInsureWisePolicy,
onChanged: (val) {
setState(() {
isInsureWisePolicy = val;
});
// 👇 ADD THIS: Rebuild chart data with new toggle value
getProductivityDashBrdList(managerId);
},
Text(
isInsureWisePolicy ? "Policies" : "Premium",
style: _styleSmall1,
),
),
],
),
SizedBox(height: 10),
Expanded(
child: CustomStackedBarChart(
labels: staffLabels,
// maxY: (maxPremium * 1.1).ceilToDouble(),
maxY: _getSmartMaxValue(),
initialRotation: 1,
dataList: [],
productsList: staffChartData,
vehicleTypeNames:
staffVehicleTypeNames, // 👈 NEW: Pass vehicle names
Transform.scale(
scale: 0.5,
child: Switch(
value: isInsureWisePolicy,
onChanged: (val) {
setState(() {
isInsureWisePolicy = val;
});
// 👇 ADD THIS: Rebuild chart data with new toggle value
getProductivityDashBrdList(managerId);
},
),
),
],
),
),
Row(children: [Expanded(child: legendWidget())]),
],
SizedBox(height: 10),
Expanded(
child: CustomStackedBarChart(
labels: staffLabels,
// maxY: (maxPremium * 1.1).ceilToDouble(),
maxY: _getSmartMaxValue(),
initialRotation: 1,
dataList: [],
productsList: staffChartData,
vehicleTypeNames:
staffVehicleTypeNames, // 👈 NEW: Pass vehicle names
),
),
Row(children: [Expanded(child: legendWidget())]),
],
),
),
);
}

View File

@ -555,7 +555,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
final yesterday = today.subtract(Duration(days: 1));
fromDt = dateFormat.format(yesterday.subtract(Duration(days: 2)));
fromDt = dateFormat.format(yesterday.subtract(Duration(days: 15)));
toDt = dateFormat.format(yesterday);
print('PrevPending FROM TO - $fromDt - $toDt');
@ -578,7 +578,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print("ENQ LIST PAGE");
final today = DateTime.now();
fromDt = dateFormat.format(today.subtract(Duration(days: 2)));
fromDt = dateFormat.format(today.subtract(Duration(days: 5)));
// fromDt = dateFormat.format(today);
toDt = dateFormat.format(today);

View File

@ -60,7 +60,7 @@ class policylistState extends ConsumerState<policylist> {
}
Future.microtask(() {
final managerId = ref.read(managerIdProvider);
managerId = ref.read(managerIdProvider);
roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider);
@ -194,6 +194,7 @@ class policylistState extends ConsumerState<policylist> {
}
void filterDateRange() {
print('filterDateRange');
// Validate the form first
// if (!_formKey.currentState!.validate()) {
// // stop execution if validation fails
@ -216,7 +217,16 @@ class policylistState extends ConsumerState<policylist> {
// }
// Call your API
getStaffList(managerId, userId, roleId);
// getStaffList(managerId, userId, roleId);
// print("D61 => r : $roleId | mId: $id | uId: $userId");
if (userId != null && managerId != null) {
print('filterDateRange 1s');
print('manager - $managerId - userID -$userId - roledId -$roleId');
getStaffList(managerId!, userId, roleId);
}
print('filterDateRange 1');
}
void refrshfilterDateRange() {
@ -425,6 +435,7 @@ class policylistState extends ConsumerState<policylist> {
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onFilter: () {
print('onFilter');
// call your filter logic
filterDateRange();
},

View File

@ -32,11 +32,15 @@ class CustomBarChart extends StatefulWidget {
class _CustomBarChartState extends State<CustomBarChart> {
int touchedGroupIndex = -1;
late int rotationTurns;
dynamic managerId;
@override
void initState() {
super.initState();
rotationTurns = widget.initialRotation;
// Future.microtask(() {
// managerId = ref.read(managerIdProvider);
// });
}
BarChartGroupData generateBarGroup(
@ -53,7 +57,6 @@ class _CustomBarChartState extends State<CustomBarChart> {
// barsSpace: 30,
barRods: [
BarChartRodData(toY: value1, color: Colors.cyan.shade300, width: 4),
// BarChartRodData(toY: 2, color: Colors.orange.shade300, width: 6),
BarChartRodData(toY: value2, color: Colors.orange.shade300, width: 4),
],
@ -71,27 +74,6 @@ class _CustomBarChartState extends State<CustomBarChart> {
// verticalAxis: Axis.horizontal,
rotationQuarterTurns: rotationTurns,
// barTouchData: BarTouchData(
// // 1. Disable built-in touch handling
// handleBuiltInTouches: false,
// touchTooltipData: BarTouchTooltipData(
// // 3. Define the tooltip content
// getTooltipItem: (group, groupIndex, rod, rodIndex) {
// // You can customize the content here
// return BarTooltipItem(
// '${rod.toY.round().toString()}', // Explicit value
// GoogleFonts.poppins(
// color: Colors.black,
// fontSize: 8,
// fontWeight: FontWeight.w500,
// ),
// );
// },
// // Customize appearance
// getTooltipColor: (BarChartGroupData group) => Colors.transparent,
// tooltipRoundedRadius: 8,
// ),
// ),
barTouchData: BarTouchData(
enabled: true,
handleBuiltInTouches: true,
@ -124,6 +106,7 @@ class _CustomBarChartState extends State<CustomBarChart> {
return BarTooltipItem('${rod.toY.round()}', textStyle);
},
),
touchCallback: (FlTouchEvent e, BarTouchResponse? r) {
// optional: change state to highlight tapped group
if (r == null || r.spot == null) {
@ -131,6 +114,20 @@ class _CustomBarChartState extends State<CustomBarChart> {
return;
}
setState(() => touchedGroupIndex = r.spot!.touchedBarGroupIndex);
final spot = r.spot!;
final groupIndex = spot.touchedBarGroupIndex;
final rodIndex = spot.touchedRodDataIndex;
final barData = widget.dataList[groupIndex];
if (e is FlTapUpEvent) {
debugPrint(
'Tapped value → ${rodIndex == 0 ? barData.value1 : barData.value2} -> ${barData.id}-'
' ${rodIndex == 0 ? 'current' : 'previous'} -> ${barData.chartName}',
);
// await apiService.generateExcel()
}
},
),