Files
kulakpos_app/lib/Screens/DashBoard/numeric_axis.dart
2026-02-07 15:57:09 +07:00

269 lines
8.0 KiB
Dart

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:mobile_pos/constant.dart';
import 'package:mobile_pos/model/dashboard_overview_model.dart';
import 'chart_data.dart';
class DashboardChart extends StatefulWidget {
const DashboardChart({Key? key, required this.model}) : super(key: key);
final DashboardOverviewModel model;
@override
State<DashboardChart> createState() => _DashboardChartState();
}
class _DashboardChartState extends State<DashboardChart> {
List<ChartData> chartData = [];
@override
void initState() {
super.initState();
getData(widget.model);
}
void getData(DashboardOverviewModel model) {
chartData = [];
for (int i = 0; i < model.data!.sales!.length; i++) {
chartData.add(ChartData(
model.data!.sales![i].date!,
model.data!.sales![i].amount!.toDouble(),
model.data!.purchases![i].amount!.toDouble(),
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.white,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: chartData.length * 50.0, // Adjust width based on the number of data points
child: Stack(
alignment: Alignment.topRight,
children: [
BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
maxY: _getMaxY(),
barTouchData: BarTouchData(enabled: false),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: _getBottomTitles(value, meta),
);
},
reservedSize: 42,
),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false, reservedSize: 20),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: _getLeftTitles,
reservedSize: _getLeftTitleReservedSize(),
),
),
),
borderData: FlBorderData(
show: false,
),
gridData: FlGridData(
show: true,
drawVerticalLine: false,
drawHorizontalLine: true,
getDrawingHorizontalLine: (value) {
return const FlLine(
color: Color(0xffD1D5DB),
dashArray: [4, 4],
strokeWidth: 1,
);
},
),
barGroups: _buildBarGroups(),
),
),
Column(
children: [
SizedBox(),
const Spacer(),
Padding(
padding: const EdgeInsets.only(bottom: 42),
child: CustomPaint(
size: Size(
chartData.length * 50.0 - _getLeftTitleReservedSize(), // Adjust to match the width of the BarChart exactly
0.1),
painter: DashedBarPainter(
barHeight: 1,
barColor: const Color(0xffD1D5DB),
dashWidth: 4,
dashSpace: 4,
),
),
),
],
),
],
),
),
),
),
),
);
}
double _getMaxY() {
double maxY = 0;
for (var data in chartData) {
maxY = maxY > data.y ? maxY : data.y;
maxY = maxY > data.y1 ? maxY : data.y1;
}
return maxY + 10;
}
double _getLeftTitleReservedSize() {
double maxY = _getMaxY();
if (maxY < 999) {
return 32;
} else if (maxY < 1000) {
return 35;
} else if (maxY < 10000) {
return 54;
} else {
return 50; // Add more cases if needed
}
}
List<BarChartGroupData> _buildBarGroups() {
return chartData.asMap().entries.map((entry) {
int index = entry.key;
ChartData data = entry.value;
return BarChartGroupData(
x: index,
barRods: [
BarChartRodData(
toY: data.y,
color: Colors.green,
width: 6,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
BarChartRodData(
toY: data.y1,
color: kMainColor,
width: 6,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
],
barsSpace: 8,
);
}).toList();
}
Widget _getBottomTitles(double value, TitleMeta meta) {
const style = TextStyle(
color: Color(0xff4D4D4D),
fontSize: 12,
);
String text = chartData[value.toInt()].x;
return SideTitleWidget(
space: 8,
meta: TitleMeta(
min: meta.min,
max: meta.max,
parentAxisSize: meta.parentAxisSize,
axisPosition: meta.axisPosition,
appliedInterval: meta.appliedInterval,
sideTitles: meta.sideTitles,
formattedValue: meta.formattedValue,
axisSide: meta.axisSide,
rotationQuarterTurns: meta.rotationQuarterTurns,
),
child: Text(text, style: style),
);
}
Widget _getLeftTitles(double value, TitleMeta meta) {
// Skip the highest value (already handled in your code)
double maxY = _getMaxY();
if (value == maxY) {
return const SizedBox.shrink();
}
// Format the number
String formattedValue;
if (value >= 1e9) {
formattedValue = '${(value / 1e9).toStringAsFixed(1)}B';
} else if (value >= 1e6) {
formattedValue = '${(value / 1e6).toStringAsFixed(1)}M';
} else if (value >= 1e3) {
formattedValue = '${(value / 1e3).toStringAsFixed(1)}K';
} else {
formattedValue = value.toInt().toString();
}
return SideTitleWidget(
meta: meta,
child: Text(
formattedValue,
style: const TextStyle(
color: Colors.black,
fontSize: 12,
),
),
);
}
}
///---------------------------------dash line-------------------------------
class DashedBarPainter extends CustomPainter {
final double barHeight;
final Color barColor;
final double dashWidth;
final double dashSpace;
DashedBarPainter({
required this.barHeight,
required this.barColor,
this.dashWidth = 4.0,
this.dashSpace = 2.0,
});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = barColor
..style = PaintingStyle.stroke
..strokeWidth = barHeight;
final dashPath = Path();
for (double i = 0; i < size.width; i += dashWidth + dashSpace) {
dashPath.addRect(Rect.fromLTWH(i, 0, dashWidth, size.height));
}
canvas.drawPath(dashPath, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}