Skip to content

Commit d3006e2

Browse files
committed
FLUT-884481-[others][flutter]: Updated the Blog sample
1 parent 7cf0d33 commit d3006e2

File tree

1 file changed

+180
-141
lines changed

1 file changed

+180
-141
lines changed

lib/main.dart

Lines changed: 180 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -32,103 +32,146 @@ class _WindmillChartState extends State<_WindmillChart> {
3232
@override
3333
void initState() {
3434
_windEnergyData = [
35-
_WindEnergy('Brazil', 29135),
36-
_WindEnergy('United Kingdom', 30215),
37-
_WindEnergy('Spain', 31028),
38-
_WindEnergy('India', 44736),
39-
_WindEnergy('Germany', 69459),
40-
_WindEnergy('US', 148020),
41-
_WindEnergy('China', 441895),
35+
_WindEnergy('China', 441895, '+19.1%'),
36+
_WindEnergy('US', 148020, '+9.4%'),
37+
_WindEnergy('Germany', 69459, '+7.6%'),
38+
_WindEnergy('India', 44736, '+9.3%'),
39+
_WindEnergy('Spain', 31028, '+3.1%'),
40+
_WindEnergy('United Kingdom', 30215, '+10.4%'),
41+
_WindEnergy('Brazil', 29135, '+29.5%'),
4242
];
4343
super.initState();
4444
}
4545

4646
@override
4747
Widget build(BuildContext context) {
4848
return Scaffold(
49-
body: Stack(
50-
children: [
51-
CustomPaint(
52-
size: MediaQuery.of(context).size,
53-
painter: _BackgroundPainter(),
49+
body: Container(
50+
decoration: const BoxDecoration(
51+
gradient: LinearGradient(
52+
colors: [
53+
Color.fromARGB(255, 236, 207, 165),
54+
Color.fromARGB(255, 159, 217, 244),
55+
Color.fromARGB(255, 204, 238, 165),
56+
],
57+
begin: Alignment.topCenter,
58+
end: Alignment.bottomCenter,
59+
),
60+
),
61+
child: SfCartesianChart(
62+
plotAreaBorderWidth: 0,
63+
title: const ChartTitle(
64+
text:
65+
' Visualize the largest top 7 wind power producers by country ',
66+
textStyle: TextStyle(
67+
fontWeight: FontWeight.bold,
68+
color: Colors.brown,
69+
fontSize: 20,
70+
),
71+
),
72+
primaryXAxis: const CategoryAxis(
73+
title: AxisTitle(
74+
text: 'Wind Energy Producers by Country',
75+
textStyle: TextStyle(fontWeight: FontWeight.bold),
76+
),
77+
majorGridLines: MajorGridLines(width: 0),
78+
majorTickLines: MajorTickLines(color: Colors.brown),
79+
axisLine: AxisLine(color: Colors.brown, width: 2),
80+
labelStyle: TextStyle(fontWeight: FontWeight.bold),
5481
),
55-
SfCartesianChart(
56-
plotAreaBorderWidth: 0,
57-
primaryXAxis: const CategoryAxis(
58-
majorGridLines: MajorGridLines(width: 0),
59-
majorTickLines: MajorTickLines(color: Colors.white),
60-
axisLine: AxisLine(color: Colors.white, width: 2),
61-
labelStyle: TextStyle(fontWeight: FontWeight.bold),
82+
primaryYAxis: NumericAxis(
83+
title: const AxisTitle(
84+
text: 'Wind Energy Capacity (Megawatts)',
85+
textStyle: TextStyle(fontWeight: FontWeight.bold),
6286
),
63-
primaryYAxis: NumericAxis(
64-
title: const AxisTitle(text: 'Megawatts'),
65-
majorGridLines: const MajorGridLines(width: 0),
66-
majorTickLines: const MajorTickLines(color: Colors.white),
67-
axisLine: const AxisLine(color: Colors.white, width: 2),
68-
labelStyle: const TextStyle(fontWeight: FontWeight.bold),
69-
axisLabelFormatter: (AxisLabelRenderDetails args) {
70-
return ChartAxisLabel('${args.text} MW', args.textStyle);
87+
majorTickLines: const MajorTickLines(color: Colors.brown),
88+
axisLine: const AxisLine(color: Colors.brown, width: 2),
89+
labelStyle: const TextStyle(fontWeight: FontWeight.bold),
90+
axisLabelFormatter: (AxisLabelRenderDetails args) {
91+
double value = double.tryParse(args.text) ?? 0;
92+
String formattedText = _formatNumber(value);
93+
return ChartAxisLabel(formattedText, args.textStyle);
94+
},
95+
),
96+
series: <CartesianSeries<_WindEnergy, String>>[
97+
ColumnSeries(
98+
dataSource: _windEnergyData,
99+
xValueMapper: (_WindEnergy data, int index) => data.country,
100+
yValueMapper: (_WindEnergy data, int index) => data.megawatt,
101+
animationDuration: 0,
102+
onCreateRenderer: (ChartSeries<_WindEnergy, String> series) {
103+
return _CustomColumnSeriesRenderer();
71104
},
72105
),
73-
tooltipBehavior: TooltipBehavior(
74-
enable: true,
75-
activationMode: ActivationMode.singleTap,
76-
color: Colors.brown,
77-
borderColor: Colors.brown,
78-
borderWidth: 5,
79-
builder: (dynamic data, dynamic point, dynamic series,
80-
int pointIndex, int seriesIndex) {
81-
return Container(
106+
],
107+
tooltipBehavior: TooltipBehavior(
108+
enable: true,
109+
activationMode: ActivationMode.singleTap,
110+
color: Colors.brown,
111+
builder: (dynamic data, dynamic point, dynamic series,
112+
int pointIndex, int seriesIndex) {
113+
return Container(
114+
decoration: BoxDecoration(
82115
color: Colors.white,
83-
child: Padding(
84-
padding: const EdgeInsets.all(10),
85-
child: Row(
86-
mainAxisSize: MainAxisSize.min,
87-
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
88-
children: <Widget>[
89-
SizedBox(
90-
height: 30,
91-
width: 35,
92-
child: Image.asset(_countryImages(pointIndex)),
93-
),
94-
const SizedBox(width: 10),
95-
Text(
96-
'${point.y.toString()}MW',
97-
style: const TextStyle(
98-
fontSize: 12,
99-
color: Colors.black,
100-
fontWeight: FontWeight.bold,
116+
borderRadius: BorderRadius.circular(6),
117+
),
118+
child: Padding(
119+
padding: const EdgeInsets.all(10),
120+
child: Row(
121+
crossAxisAlignment: CrossAxisAlignment.start,
122+
mainAxisSize: MainAxisSize.min,
123+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
124+
children: <Widget>[
125+
Column(
126+
mainAxisSize: MainAxisSize.min,
127+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
128+
children: [
129+
SizedBox(
130+
height: 30,
131+
width: 35,
132+
child: Image.asset(_countryImages(pointIndex)),
133+
),
134+
const SizedBox(width: 30),
135+
],
136+
),
137+
Column(
138+
crossAxisAlignment: CrossAxisAlignment.start,
139+
mainAxisSize: MainAxisSize.min,
140+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
141+
children: [
142+
Text(
143+
'${data.country}',
144+
style: const TextStyle(
145+
fontSize: 12,
146+
color: Colors.black,
147+
fontWeight: FontWeight.bold,
148+
),
149+
),
150+
Text(
151+
'Megawatts: ${point.y.toString()}',
152+
style: const TextStyle(
153+
fontSize: 12,
154+
color: Colors.black,
155+
fontWeight: FontWeight.bold,
156+
),
101157
),
102-
),
103-
],
104-
),
158+
Text(
159+
'ANNUAL GROWTH RATE\n(2013-2023) ${data.rate}',
160+
style: const TextStyle(
161+
fontSize: 12,
162+
color: Colors.black,
163+
fontWeight: FontWeight.bold,
164+
),
165+
),
166+
],
167+
),
168+
],
105169
),
106-
);
107-
},
108-
),
109-
title: const ChartTitle(
110-
text:
111-
' Visualize the largest top 7 wind power producers by country ',
112-
textStyle: TextStyle(
113-
fontWeight: FontWeight.bold,
114-
color: Colors.brown,
115-
fontSize: 20,
116-
),
117-
backgroundColor: Colors.white,
118-
),
119-
series: <CartesianSeries<_WindEnergy, String>>[
120-
ColumnSeries(
121-
dataSource: _windEnergyData,
122-
xValueMapper: (_WindEnergy data, int index) => data.country,
123-
yValueMapper: (_WindEnergy data, int index) => data.megawatt,
124-
animationDuration: 0,
125-
onCreateRenderer: (ChartSeries<_WindEnergy, String> series) {
126-
return _CustomColumnSeriesRenderer();
127-
},
128-
),
129-
],
170+
),
171+
);
172+
},
130173
),
131-
],
174+
),
132175
),
133176
);
134177
}
@@ -153,6 +196,19 @@ class _WindmillChartState extends State<_WindmillChart> {
153196
return '';
154197
}
155198

199+
// Function to format numbers to a more readable form
200+
String _formatNumber(double num) {
201+
// Special case for zero to avoid decimal representation
202+
if (num == 0) {
203+
return '0';
204+
}
205+
if (num >= 1000) {
206+
return '${(num / 1000).toStringAsFixed(num >= 10000 ? 0 : 1)}K';
207+
}
208+
return num.toStringAsFixed(
209+
num == num.toInt() ? 0 : 1); // Remove ".0" for whole numbers
210+
}
211+
156212
@override
157213
void dispose() {
158214
_windEnergyData.clear();
@@ -161,9 +217,10 @@ class _WindmillChartState extends State<_WindmillChart> {
161217
}
162218

163219
class _WindEnergy {
164-
_WindEnergy(this.country, this.megawatt);
220+
_WindEnergy(this.country, this.megawatt, this.rate);
165221
final String country;
166222
final double megawatt;
223+
final String rate;
167224
}
168225

169226
// Custom renderer for column series
@@ -195,17 +252,14 @@ class _ColumnSegment extends ColumnSegment<_WindEnergy, String> {
195252
return;
196253
}
197254

198-
final Paint bladeFillPaint = Paint()
255+
final Paint fillPaint = Paint()
199256
..color = Colors.brown
200257
..style = PaintingStyle.fill;
201-
final Paint bladeStrokePaint = Paint()
258+
final Paint strokePaint = Paint()
202259
..color = Colors.white
203260
..strokeWidth = 2
204261
..style = PaintingStyle.stroke;
205262

206-
final Paint postFillPaint = bladeFillPaint;
207-
final Paint postStrokePaint = bladeStrokePaint;
208-
209263
final double bottom = segmentRect!.bottom;
210264
final double top = segmentRect!.top;
211265
final double centerX = segmentRect!.center.dx;
@@ -222,33 +276,59 @@ class _ColumnSegment extends ColumnSegment<_WindEnergy, String> {
222276
..lineTo(centerX - halfPostTopWidth, top)
223277
..close();
224278

225-
canvas.drawPath(_postPath, postFillPaint);
226-
canvas.drawPath(_postPath, postStrokePaint);
279+
canvas.drawPath(_postPath, fillPaint);
280+
canvas.drawPath(_postPath, strokePaint);
281+
282+
// Maintained a minimum value of 30 and a maximum value of 40 as the default
283+
// blade length range. Using the column segment value, I calculate the blade
284+
// length by normalizing it within this range. The formula maps the value to
285+
// a specified blade length range, ensuring proportional scaling.
286+
// This approach dynamically adjusts blade sizes based on the segment value.
287+
288+
// Constants for blade length range.
289+
const double minBladeLength = 30;
290+
const double maxBladeLength = 40;
291+
292+
// Constants for data normalization.
293+
const double minValue = 29135;
294+
const double maxValue = 441895;
295+
296+
// Calculate the normalized value of the segment (based on y).
297+
const double lengthRange = maxBladeLength - minBladeLength;
298+
final double normalizedFactor = (y - minValue) / (maxValue - minValue);
299+
300+
// Adjust blade length dynamically based on the reversed segment index.
301+
final double reverseScalingFactor =
302+
1 - (currentSegmentIndex * 0.1); // Decrease as segment index increases.
303+
304+
double bladeLength = normalizedFactor * lengthRange + minBladeLength;
305+
bladeLength *= reverseScalingFactor; // Apply reverse scaling factor
306+
307+
// Ensure the blade length doesn't drop below the minimum value.
308+
bladeLength = bladeLength.clamp(minBladeLength, maxBladeLength);
227309

228310
final Offset center = Offset(centerX, centerY);
229-
double bladeWidth = 20;
230-
double bladeLength =
231-
10 * (currentSegmentIndex < 3 ? 3 : currentSegmentIndex.toDouble());
311+
const double bladeWidth = 20;
232312

233313
// Define the angles for the three blades in radians.
234314
double angle1 = 0;
235315
double angle2 = 120 * pi / 180;
236316
double angle3 = 240 * pi / 180;
237317

238318
// Draw first blade.
239-
_drawBlade(canvas, center, angle1, bladeLength, bladeWidth, bladeFillPaint,
240-
bladeStrokePaint);
319+
_drawBlade(canvas, center, angle1, bladeLength, bladeWidth, fillPaint,
320+
strokePaint);
241321

242322
// Draw second blade.
243-
_drawBlade(canvas, center, angle2, bladeLength, bladeWidth, bladeFillPaint,
244-
bladeStrokePaint);
323+
_drawBlade(canvas, center, angle2, bladeLength, bladeWidth, fillPaint,
324+
strokePaint);
245325

246326
// Draw third blade.
247-
_drawBlade(canvas, center, angle3, bladeLength, bladeWidth, bladeFillPaint,
248-
bladeStrokePaint);
327+
_drawBlade(canvas, center, angle3, bladeLength, bladeWidth, fillPaint,
328+
strokePaint);
249329

250330
// Draws circle at the center of the windmill.
251-
canvas.drawCircle(center, 5, Paint()..color = Colors.white);
331+
canvas.drawCircle(center, 5, Paint()..color = Colors.brown);
252332
}
253333

254334
// Helper method to draw each blade
@@ -287,44 +367,3 @@ class _ColumnSegment extends ColumnSegment<_WindEnergy, String> {
287367
super.dispose();
288368
}
289369
}
290-
291-
class _BackgroundPainter extends CustomPainter {
292-
@override
293-
void paint(Canvas canvas, Size size) {
294-
final double width = size.width;
295-
final double height = size.height;
296-
final Rect backgroundRect = Rect.fromLTWH(0, 0, width, height);
297-
final Paint sunPaint = Paint()..color = Colors.yellow;
298-
final Paint skyPaint = Paint()
299-
..shader = const LinearGradient(
300-
colors: [
301-
Colors.orange,
302-
Color.fromARGB(255, 90, 190, 236),
303-
Colors.lightGreen,
304-
],
305-
begin: Alignment.topCenter,
306-
end: Alignment.bottomCenter,
307-
).createShader(backgroundRect);
308-
309-
canvas.drawRect(backgroundRect, skyPaint);
310-
canvas.drawCircle(Offset(width * 0.8, height * 0.2), 60, sunPaint);
311-
_drawCloud(canvas, Offset(width * 0.3, height * 0.3));
312-
_drawCloud(canvas, Offset(width * 0.6, height * 0.4));
313-
}
314-
315-
void _drawCloud(Canvas canvas, Offset position) {
316-
final Paint cloudPaint = Paint()..color = Colors.white;
317-
_drawOval(canvas, position.translate(-40, 10), 70, 40, cloudPaint);
318-
_drawOval(canvas, position.translate(40, 10), 70, 40, cloudPaint);
319-
_drawOval(canvas, position, 100, 60, cloudPaint);
320-
}
321-
322-
void _drawOval(Canvas canvas, Offset position, double width, double height,
323-
Paint paint) {
324-
canvas.drawOval(
325-
Rect.fromCenter(center: position, width: width, height: height), paint);
326-
}
327-
328-
@override
329-
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
330-
}

0 commit comments

Comments
 (0)