@@ -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
163219class _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