In this article, we will walk you through creating a Flutter application that displays sales data using hardcoded data. This simple yet effective tutorial will help you visualize sales data through various time intervals—daily, monthly, and yearly—using charts.
This Flutter application displays a sales data chart using hardcoded data.
Here's a summary of the code:
flutter create
.
main
function calls runApp
to start the application with MyApp
.MyApp
is a StatefulWidget
with its state defined in _MyAppState
._MyAppState
initializes the app and builds the MaterialApp
with a centered SalesData
widget.SalesData
uses the flutter_hooks
package for state management.getHardcodedOrders
function.SfCartesianChart
widget from the syncfusion_flutter_charts
package.DailySalesData
class holds the sales data for a specific date.getHardcodedOrders
provides a list of hardcoded ReadyOrders
.prepareDailyData
, prepareMonthlyData
, and prepareYearlyData
convert the list of ReadyOrders
into a list of DailySalesData
for different time intervals.
ReadyOrders
represents an order with a date and a list of OrderItem
s.OrderItem
represents an item in an order with a price.The core of this tutorial is given in the code.
SfCartesianChart(
primaryXAxis: DateTimeAxis(
title: AxisTitle(
text: selectedChartType.value == "Daily"
? "---Daily"
: selectedChartType.value == "Monthly"
? "---Months"
: "---Years",
),
dateFormat: selectedChartType.value == "Daily"
? DateFormat('yyyy-MM-dd')
: selectedChartType.value == "Monthly"
? DateFormat('yyyy-MM')
: DateFormat('yyyy'),
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
intervalType: selectedChartType.value == "Daily"
? DateTimeIntervalType.days
: selectedChartType.value == "Monthly"
? DateTimeIntervalType.months
: DateTimeIntervalType.years,
interval: 1,
),
title: ChartTitle(
text: selectedChartType.value == "Daily"
? 'Daily Sales Analysis'
: selectedChartType.value == "Monthly"
? 'Monthly Sales Analysis'
: 'Yearly Sales Analysis'),
legend: Legend(isVisible: true),
tooltipBehavior: TooltipBehavior(enable: true),
series: <CartesianSeries<DailySalesData, DateTime>>[
LineSeries<DailySalesData, DateTime>(
dataSource: data,
xValueMapper: (DailySalesData sales, _) => sales.date,
yValueMapper: (DailySalesData sales, _) => sales.sales,
name: 'Sales',
xAxisName: "Time",
yAxisName: "Amount",
dataLabelSettings: const DataLabelSettings(isVisible: true),
),
],
),
The description for the above code is here.
The SfCartesianChart
widget in the Flutter application is used to display sales data in a visually appealing manner. It utilizes the DateTimeAxis
as the primary X-axis, which allows for dynamic formatting based on the selected chart type—daily, monthly, or yearly.
The title of the X-axis changes accordingly to "---Daily", "---Months", or "---Years", and the date format adjusts to 'yyyy-MM-dd', 'yyyy-MM', or 'yyyy' respectively. The majorGridLines
are set to a width of 0 to enhance visual clarity, and edgeLabelPlacement
is set to shift, ensuring that labels do not overlap. The intervalType
is also adjusted based on the selection, using days, months, or years as needed, with an interval set to 1 for consistency.
The chart itself has a dynamic title that changes based on the selected time interval: 'Daily Sales Analysis', 'Monthly Sales Analysis', or 'Yearly Sales Analysis'. It includes a visible legend and enables tooltips for better interactivity. The LineSeries
is used to plot the sales data, with each DailySalesData
object mapped to the X-axis (date) and Y-axis (sales). The data labels are made visible for each point to provide immediate insights.
This setup makes the SfCartesianChart
a powerful tool for displaying and analyzing sales data over different time periods, enhancing the user's ability to understand trends and patterns.
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State
{ @override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SalesData(),
),
),
);
}
}
class SalesData extends HookWidget {
SalesData({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final orders = getHardcodedOrders();
final isLoading = false;
final selectedChartType = useState
("Daily"); if (orders.isEmpty) {
return Scaffold(
appBar: AppBar(title: Text("You don't have sales")),
body: const Center(child: CircularProgressIndicator(color: Color(0xffffa44f))),
);
}
List
data; if (selectedChartType.value == "Daily") {
data = prepareDailyData(orders);
} else if (selectedChartType.value == "Monthly") {
data = prepareMonthlyData(orders);
} else {
data = prepareYearlyData(orders);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF30b9b2),
title: Text("Sales Data"),
actions: [
DropdownButton
( dropdownColor: Color(0xFF30b9b2),
value: selectedChartType.value,
items:
['Daily', 'Monthly', 'Yearly'] .map((String value) => DropdownMenuItem
( value: value,
child: Text(
value,
style: const TextStyle(color: Colors.white),
),
))
.toList(),
onChanged: (String? newValue) {
selectedChartType.value = newValue!;
},
),
],
),
body: Column(
children: [
SfCartesianChart(
primaryXAxis: DateTimeAxis(
title: AxisTitle(
text: selectedChartType.value == "Daily"
? "---Daily"
: selectedChartType.value == "Monthly"
? "---Months"
: "---Years",
),
dateFormat: selectedChartType.value == "Daily"
? DateFormat('yyyy-MM-dd')
: selectedChartType.value == "Monthly"
? DateFormat('yyyy-MM')
: DateFormat('yyyy'),
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
intervalType: selectedChartType.value == "Daily"
? DateTimeIntervalType.days
: selectedChartType.value == "Monthly"
? DateTimeIntervalType.months
: DateTimeIntervalType.years,
interval: 1,
),
title: ChartTitle(
text: selectedChartType.value == "Daily"
? 'Daily Sales Analysis'
: selectedChartType.value == "Monthly"
? 'Monthly Sales Analysis'
: 'Yearly Sales Analysis'),
legend: Legend(isVisible: true),
tooltipBehavior: TooltipBehavior(enable: true),
series: <CartesianSeries<DailySalesData, DateTime>>[
LineSeries<DailySalesData, DateTime>(
dataSource: data,
xValueMapper: (DailySalesData sales, _) => sales.date,
yValueMapper: (DailySalesData sales, _) => sales.sales,
name: 'Sales',
xAxisName: "Time",
yAxisName: "Amount",
dataLabelSettings: const DataLabelSettings(isVisible: true),
),
],
),
],
),
);
}
}
class DailySalesData {
DailySalesData(this.date, this.sales);
final DateTime date;
final double sales;
}
List
getHardcodedOrders() { return [
ReadyOrders(
orderDate: DateTime(2023, 1, 1),
orderItems: [OrderItem(price: 50.0), OrderItem(price: 100.0)],
),
ReadyOrders(
orderDate: DateTime(2023, 1, 2),
orderItems: [OrderItem(price: 70.0)],
),
// Add more hardcoded orders as needed
];
}
List
prepareDailyData(List orders) { final Map<DateTime, double> salesMap = {};
for (var order in orders) {
final orderDate = DateTime(order.orderDate!.year, order.orderDate!.month, order.orderDate!.day);
for (var item in order.orderItems) {
salesMap[orderDate] = (salesMap[orderDate] ?? 0) + item.price;
}
}
final sortedEntries = salesMap.entries
.map((entry) => DailySalesData(entry.key, entry.value))
.toList()
..sort((a, b) => a.date.compareTo(b.date));
return sortedEntries;
}
List
prepareMonthlyData(List orders) { final Map<DateTime, double> salesMap = {};
for (var order in orders) {
final orderDate = DateTime(order.orderDate!.year, order.orderDate!.month);
for (var item in order.orderItems) {
salesMap[orderDate] = (salesMap[orderDate] ?? 0) + item.price;
}
}
final sortedEntries = salesMap.entries
.map((entry) => DailySalesData(entry.key, entry.value))
.toList()
..sort((a, b) => a.date.compareTo(b.date));
return sortedEntries;
}
List
prepareYearlyData(List orders) { final Map<DateTime, double> salesMap = {};
for (var order in orders) {
final orderDate = DateTime(order.orderDate!.year);
for (var item in order.orderItems) {
salesMap[orderDate] = (salesMap[orderDate] ?? 0) + item.price;
}
}
final sortedEntries = salesMap.entries
.map((entry) => DailySalesData(entry.key, entry.value))
.toList()
..sort((a, b) => a.date.compareTo(b.date));
return sortedEntries;
}
class ReadyOrders {
ReadyOrders({this.orderDate, required this.orderItems});
final DateTime? orderDate;
final List
orderItems; }
class OrderItem {
OrderItem({required this.price});
final double price;
}
Learn more about the video tutorial here Multi Vendor App