Skip to content

Commit 3665427

Browse files
committed
Updating
1 parent be2f8e2 commit 3665427

8 files changed

+213
-94
lines changed

lib/main.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ void main() {
66
app.run();
77
}
88

9-
List<DemoMenuItem> get _rootMenus =>
10-
[_examples];
9+
List<DemoMenuItem> get _rootMenus => [_examples];
1110

1211
DemoMenuItem get _examples =>
1312
DemoMenuItem('Examples', children: [_productionLine]);
1413

1514
DemoMenuItem get _productionLine =>
1615
DemoMenuItem('Production line', page: () => ProductionLinePage());
17-

lib/production_line/production_line.dart

+31-36
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import 'package:simdart/simdart.dart';
55
/// Represents the configuration for a production line simulation algorithm.
66
class ProductionLine {
77
/// Creates an instance of the algorithm configuration.
8-
ProductionLine({required this.packerCount, required this.assemblerCount,required this.inspectorCount,
8+
ProductionLine({
9+
required this.packerCount,
10+
required this.assemblerCount,
11+
required this.inspectorCount,
912
required this.requestedItemCount,
1013
required this.requestInterval,
1114
required this.assemblyDuration,
@@ -45,28 +48,22 @@ class ProductionLine {
4548
/// The rejection rate during inspection, represented as a percentage (0-100).
4649
final double rejectionProbability;
4750

48-
final List<SimulationTrack> tracks =[];
51+
final List<SimulationTrack> tracks = [];
4952

5053
Future<SimulationResult> run() async {
51-
SimDart sim = SimDart(onTrack: (track) {
52-
tracks.add(track);
53-
if (track.operation != Operation.resume) {
54-
print('${track.name}:${track.time}:${track.operation}');
55-
}
56-
});
57-
58-
54+
SimDart sim = SimDart(
55+
executionPriority: ExecutionPriority.low,
56+
onTrack: (track) {
57+
tracks.add(track);
58+
});
5959

6060
sim.addResource(LimitedResource(id: 'p', capacity: packerCount));
6161
sim.addResource(LimitedResource(id: 'i', capacity: inspectorCount));
6262
sim.addResource(LimitedResource(id: 'a', capacity: assemblerCount));
6363

6464
for (int i = 0; i < requestedItemCount; i++) {
65-
sim.process(
66-
_assemblyItem,
67-
start: i * requestInterval,
68-
resourceId: 'a',
69-
name: 'assemblyItem');
65+
sim.process(_assemblyItem,
66+
start: i * requestInterval, resourceId: 'a', name: 'assemblyItem');
7067
}
7168

7269
await sim.run();
@@ -83,16 +80,15 @@ class ProductionLine {
8380
assembledCount > 0 ? duration / assembledCount : 0;
8481

8582
return SimulationResult(
86-
assembleCount: assembledCount,
87-
packagedCount: packagedCount,
88-
rejectedCount: rejectedCount,
89-
rejectionRate: rejectionRate,
90-
assembleRate: assembleRate,
91-
packagingRate: packagingRate,
92-
averageProductionDuration: averageProductionDuration,
93-
duration: duration,
94-
tracks: tracks
95-
);
83+
assembleCount: assembledCount,
84+
packagedCount: packagedCount,
85+
rejectedCount: rejectedCount,
86+
rejectionRate: rejectionRate,
87+
assembleRate: assembleRate,
88+
packagingRate: packagingRate,
89+
averageProductionDuration: averageProductionDuration,
90+
duration: duration,
91+
tracks: tracks);
9692
}
9793

9894
void _assemblyItem(EventContext context) async {
@@ -128,15 +124,14 @@ class SimulationResult {
128124
final int duration;
129125
final List<SimulationTrack> tracks;
130126

131-
SimulationResult({
132-
required this.assembleCount,
133-
required this.packagedCount,
134-
required this.rejectedCount,
135-
required this.rejectionRate,
136-
required this.assembleRate,
137-
required this.packagingRate,
138-
required this.averageProductionDuration,
139-
required this.duration,
140-
required this.tracks
141-
});
127+
SimulationResult(
128+
{required this.assembleCount,
129+
required this.packagedCount,
130+
required this.rejectedCount,
131+
required this.rejectionRate,
132+
required this.assembleRate,
133+
required this.packagingRate,
134+
required this.averageProductionDuration,
135+
required this.duration,
136+
required this.tracks});
142137
}

lib/production_line/production_line_example.dart

+133-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import 'package:davi/davi.dart';
12
import 'package:flutter/material.dart';
3+
import 'package:simdart/simdart.dart';
24
import 'package:simdart_demo/production_line/production_line.dart';
35
import 'package:simdart_demo/production_line/radio_button.dart';
46
import 'package:simdart_demo/production_line/result_card.dart';
@@ -15,12 +17,10 @@ class ProductionLineExample extends StatefulWidget {
1517

1618
class ProductionLineExampleState extends State<ProductionLineExample> {
1719
bool loading = false;
18-
int duration = 0;
19-
2020

2121
ValueNotifier<int> packers = ValueNotifier(5);
2222
ValueNotifier<int> assemblers = ValueNotifier(3);
23-
ValueNotifier<int> inspectors=ValueNotifier(2);
23+
ValueNotifier<int> inspectors = ValueNotifier(2);
2424
ValueNotifier<int> requestedItemCount = ValueNotifier(20);
2525
ValueNotifier<int> requestInterval = ValueNotifier(1);
2626
ValueNotifier<int> assemblyDuration = ValueNotifier(5);
@@ -33,26 +33,43 @@ class ProductionLineExampleState extends State<ProductionLineExample> {
3333

3434
@override
3535
Widget build(BuildContext context) {
36+
TextStyle titleStyle = TextStyle(fontWeight: FontWeight.bold);
3637
List<Widget> children = [
38+
Text("Simulation setup", style: titleStyle),
3739
_buildForm(context),
38-
ElevatedButton(
39-
onPressed: !loading ? _run : null, child: Text('Run: $duration'))
40+
TextButton(
41+
onPressed: !loading ? _run : null, child: Text('Run the simulation'))
4042
];
4143
if (loading) {
4244
children.add(CircularProgressIndicator());
4345
} else if (simulationResult != null) {
46+
children.add(Text("Simulation result", style: titleStyle));
47+
4448
children.add(ResultGrid(result: simulationResult!));
4549

46-
children.add(Wrap(spacing: 16,
47-
runSpacing: 16,children: [SparklineResource(title: 'Assemblers usage',
48-
simulationResult: simulationResult!,
49-
resourceId: 'a'),
50-
SparklineResource(title: 'Inspectors usage',
50+
children.add(Wrap(spacing: 32, runSpacing: 16, children: [
51+
SparklineResource(
52+
title: 'Assemblers usage',
53+
simulationResult: simulationResult!,
54+
resourceId: 'a'),
55+
SparklineResource(
56+
title: 'Inspectors usage',
5157
simulationResult: simulationResult!,
5258
resourceId: 'i'),
53-
SparklineResource(title: 'Packers usage',
59+
SparklineResource(
60+
title: 'Packers usage',
5461
simulationResult: simulationResult!,
55-
resourceId: 'p')]));
62+
resourceId: 'p')
63+
]));
64+
65+
children.add(Text("Simulation events", style: titleStyle));
66+
67+
children.add(EventsViewer(
68+
key: UniqueKey(),
69+
tracks: simulationResult!.tracks,
70+
assemblers: assemblers.value,
71+
inspectors: inspectors.value,
72+
packers: packers.value));
5673
}
5774

5875
return Column(
@@ -64,13 +81,11 @@ class ProductionLineExampleState extends State<ProductionLineExample> {
6481
Widget _buildForm(BuildContext context) {
6582
TableBuilder tableBuilder = TableBuilder();
6683

67-
68-
6984
tableBuilder.row()
70-
..add(_buildText('Assemblers:'))
71-
..add(RadioButton(value: 3, selectedValue: assemblers))
72-
..add(RadioButton(value: 5, selectedValue: assemblers))
73-
..add(RadioButton(value: 7, selectedValue: assemblers));
85+
..add(_buildText('Assemblers:'))
86+
..add(RadioButton(value: 3, selectedValue: assemblers))
87+
..add(RadioButton(value: 5, selectedValue: assemblers))
88+
..add(RadioButton(value: 7, selectedValue: assemblers));
7489

7590
tableBuilder.row()
7691
..add(_buildText('Inspectors:'))
@@ -79,10 +94,10 @@ class ProductionLineExampleState extends State<ProductionLineExample> {
7994
..add(RadioButton(value: 8, selectedValue: inspectors));
8095

8196
tableBuilder.row()
82-
..add(_buildText('Packers:'))
83-
..add(RadioButton(value: 5, selectedValue: packers))
84-
..add(RadioButton(value: 10, selectedValue: packers))
85-
..add(RadioButton(value: 15, selectedValue: packers));
97+
..add(_buildText('Packers:'))
98+
..add(RadioButton(value: 5, selectedValue: packers))
99+
..add(RadioButton(value: 10, selectedValue: packers))
100+
..add(RadioButton(value: 15, selectedValue: packers));
86101

87102
tableBuilder.row()
88103
..add(_buildText('Requested items:'))
@@ -93,8 +108,8 @@ class ProductionLineExampleState extends State<ProductionLineExample> {
93108
tableBuilder.row()
94109
..add(_buildText('Request interval (min):'))
95110
..add(RadioButton(value: 1, selectedValue: requestInterval))
96-
..add(RadioButton(value: 10, selectedValue: requestInterval))
97-
..add(RadioButton(value: 20, selectedValue: requestInterval));
111+
..add(RadioButton(value: 5, selectedValue: requestInterval))
112+
..add(RadioButton(value: 10, selectedValue: requestInterval));
98113

99114
tableBuilder.row()
100115
..add(_buildText('Assembly duration (min):'))
@@ -133,9 +148,9 @@ class ProductionLineExampleState extends State<ProductionLineExample> {
133148
});
134149

135150
ProductionLine productionLine = ProductionLine(
136-
assemblerCount:assemblers.value,
137-
inspectorCount:inspectors.value,
138-
packerCount:packers.value,
151+
assemblerCount: assemblers.value,
152+
inspectorCount: inspectors.value,
153+
packerCount: packers.value,
139154
inspectionDuration: inspectionDuration.value,
140155
packagingDuration: packagingDuration.value,
141156
assemblyDuration: assemblyDuration.value,
@@ -163,32 +178,119 @@ class ResultGrid extends StatelessWidget {
163178
spacing: 16,
164179
runSpacing: 16,
165180
children: <Widget>[
166-
ResultCard(value: result.assembleCount.toString(), text: 'Assembled'),
181+
ResultCard(
182+
value: result.assembleCount.toString(),
183+
text: 'Assembled',
184+
icon: Icons.build),
167185
ResultCard(
168186
value: result.rejectedCount.toString(),
169187
text: 'Rejected',
188+
icon: Icons.block,
170189
textColor: Colors.red),
171190
ResultCard(
172191
value: result.packagedCount.toString(),
173192
text: 'Packaged',
193+
icon: Icons.inventory_2_outlined,
174194
textColor: Colors.green),
175195
ResultCard(
176-
value: result.duration.toString(), text: 'Total duration (min)'),
196+
value: result.duration.toString(),
197+
text: 'Total duration (min)',
198+
icon: Icons.schedule),
177199
ResultCard(
178200
value: result.assembleRate.toStringAsFixed(2),
179-
text: 'Assemble rate (items/min)'),
201+
text: 'Assemble rate (items/min)',
202+
icon: Icons.trending_up),
180203
ResultCard(
181204
value: '${result.rejectionRate.toStringAsFixed(2)}%',
182205
text: 'Rejection rate',
206+
icon: Icons.trending_up,
183207
textColor: Colors.red),
184208
ResultCard(
185209
value: result.packagingRate.toStringAsFixed(2),
186210
text: 'Packaging rate (items/min)',
211+
icon: Icons.trending_up,
187212
textColor: Colors.green),
188213
ResultCard(
189214
value: result.averageProductionDuration.toStringAsFixed(2),
190-
text: 'Avg. production duration (min/item)'),
215+
text: 'Avg. production duration (min/item)',
216+
icon: Icons.trending_up),
191217
],
192218
);
193219
}
194220
}
221+
222+
class EventsViewer extends StatelessWidget {
223+
const EventsViewer(
224+
{super.key,
225+
required this.tracks,
226+
required this.packers,
227+
required this.assemblers,
228+
required this.inspectors});
229+
230+
final List<SimulationTrack> tracks;
231+
final int packers;
232+
final int assemblers;
233+
final int inspectors;
234+
235+
@override
236+
Widget build(BuildContext context) {
237+
return SizedBox(height: 300, child: _table());
238+
}
239+
240+
Widget _table() {
241+
DaviModel<SimulationTrack> model = DaviModel(
242+
rows: tracks,
243+
columns: [
244+
DaviColumn(
245+
name: 'Time (min)', cellValue: (params) => params.data.time),
246+
DaviColumn(
247+
name: 'Status',
248+
cellValue: (params) => params.data.status,
249+
cellTextStyle: (params) => params.data.status == Status.rejected
250+
? TextStyle(color: Colors.red)
251+
: null),
252+
DaviColumn(name: 'Name', cellValue: (params) => params.data.name),
253+
DaviColumn(
254+
cellPadding: EdgeInsets.all(4),
255+
name: 'Assemblers',
256+
cellBarValue: (params) =>
257+
params.data.resourceUsage['a']! / assemblers,
258+
cellBarStyle: CellBarStyle(
259+
barBackground: Colors.transparent,
260+
barForeground: (value) {
261+
return Color.lerp(
262+
Colors.green[200], Colors.red[200], value)!;
263+
}),
264+
cellBarValueStringify: (params) =>
265+
'${params.data.resourceUsage['a']!}/$assemblers'),
266+
DaviColumn(
267+
cellPadding: EdgeInsets.all(4),
268+
name: 'Inspectors',
269+
cellBarValue: (params) =>
270+
params.data.resourceUsage['i']! / inspectors,
271+
cellBarStyle: CellBarStyle(
272+
barBackground: Colors.transparent,
273+
barForeground: (value) {
274+
return Color.lerp(
275+
Colors.green[200], Colors.red[200], value)!;
276+
}),
277+
cellBarValueStringify: (params) =>
278+
'${params.data.resourceUsage['i']!}/$inspectors'),
279+
DaviColumn(
280+
cellPadding: EdgeInsets.all(4),
281+
name: 'Packers',
282+
cellBarValue: (params) =>
283+
params.data.resourceUsage['p']! / packers,
284+
cellBarStyle: CellBarStyle(
285+
barBackground: Colors.transparent,
286+
barForeground: (value) {
287+
return Color.lerp(
288+
Colors.green[200], Colors.red[200], value)!;
289+
}),
290+
cellBarValueStringify: (params) =>
291+
'${params.data.resourceUsage['p']!}/$packers')
292+
],
293+
sortingMode: SortingMode.disabled);
294+
return Davi(model, columnWidthBehavior: ColumnWidthBehavior.fit);
295+
}
296+
}

lib/production_line/radio_button.dart

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import 'package:flutter/material.dart';
22

3-
class RadioButton extends StatelessWidget{
4-
5-
const RadioButton({super.key, required this.value, required this.selectedValue});
3+
class RadioButton extends StatelessWidget {
4+
const RadioButton(
5+
{super.key, required this.value, required this.selectedValue});
66

77
final int value;
88
final ValueNotifier<int> selectedValue;
@@ -26,5 +26,4 @@ class RadioButton extends StatelessWidget{
2626
]);
2727
});
2828
}
29-
30-
}
29+
}

0 commit comments

Comments
 (0)