Hello I tried to make a simple chart in flutter with date in x axis and data in Y axis. When I push a button data is increase for the current date. first goal is completed with the code bellow. But now I don't know how to make chart more dynamic, I want statistic of my pressed button for each new day. I don't know how to add dynamicaly a new column of data for each new days.

import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:intl/intl.dart';
void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class ClicksPerYear {
  final String year;
  final int clicks;
  final charts.Color color;

  ClicksPerYear(this.year, this.clicks, Color color)
      : this.color = new charts.Color(
      r: color.red, g: color.green, b: color.blue, a: color.alpha);
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  var currentTime;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    var data = [

      new ClicksPerYear('2015', 3, Colors.red),
      new ClicksPerYear('2016', 7, Colors.orange),
      new ClicksPerYear('2017', 42, Colors.yellow),
      new ClicksPerYear('$currentTime', _counter, Colors.green),
    ];

    var series = [
      new charts.Series(
        domainFn: (ClicksPerYear clickData, _) => clickData.year,
        measureFn: (ClicksPerYear clickData, _) => clickData.clicks,
        colorFn: (ClicksPerYear clickData, _) => clickData.color,
        id: 'Clicks',
        data: data,

      ),
    ];
    var chart = new charts.BarChart(
      series,
      animate: true,
    );

    var chartWidget = new Padding(
      padding: new EdgeInsets.all(32.0),
      child: new SizedBox(
        height: 200.0,
        child: chart,
      ),
    );

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            chartWidget,
          ],
        ),
      ),

      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            DateTime now = DateTime.now();
            currentTime = DateFormat('dd/MM/yyyy').format(now);
            _incrementCounter();
          });
        },
        child: Icon(Icons.add,),

      ),

    );
  }
}

1 Answers

2
Yamin On Best Solutions

There are some tiny issues with the codes you shared. I tried to fix them and prepare an updated version based on your own code. check out below tips:

1) State of an object.

You've used the counter provided by the initial example of flutter. this counter is a member variable of the parent widget and there is only one counter available. so you have to make the other bars static! which doesn't seem good. converting it to a List or Map will solve it but it's better to hold the value inside the object itself.

e.g suppose you want to use 2016 data in another page. you have to get the data from the parent widget and pass it to a new page. But if you keep the clicks inside the object, you just need to pass the object itself.

2) Local variables inside the Build method

The data list is defined at the beginning of the build method. in this case, whenever the widget rebuilds itself, it will initiate the data list. which doesn't seem good! the list is available and any changes should be applied to it. refining it may remove the previous changes.

3) Using map instead of List

Although there is no issue with using List type for data variable, I suggest using Map type instead. If you want to use List, whenever you want to apply any changes into the element of the data, you need to search through it and find the right element. But with Map type, you can just store the key and use it later.

Check out the corrected code and let me know if you have any question about it:

import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:intl/intl.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class ClicksPerYear {
  final String year;
  int clicks;
  final charts.Color color;

  ClicksPerYear(this.year, this.clicks, Color color)
      : this.color = new charts.Color(
            r: color.red, g: color.green, b: color.blue, a: color.alpha);

  incrementClick() {
    clicks++;
  }
}

class _MyHomePageState extends State<MyHomePage> {
  var currentTime = DateFormat('dd/MM/yyyy').format(DateTime.now());
  Map<String, ClicksPerYear> data;

  @override
  void initState() {
    data = {
      '2015': ClicksPerYear('2015', 3, Colors.red),
      '2016': ClicksPerYear('2016', 7, Colors.orange),
      '2017': ClicksPerYear('2017', 42, Colors.yellow),
      '$currentTime': ClicksPerYear('$currentTime', 0, Colors.green),
    };
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var series = [
      new charts.Series(
          domainFn: (ClicksPerYear clickData, _) => clickData.year,
          measureFn: (ClicksPerYear clickData, _) => clickData.clicks,
          colorFn: (ClicksPerYear clickData, _) => clickData.color,
          id: 'Clicks',
          data: data.values.toList()),
    ];
    var chart = new charts.BarChart(
      series,
      animate: true,
    );

    var chartWidget = new Padding(
      padding: new EdgeInsets.all(32.0),
      child: new SizedBox(
        height: 200.0,
        child: chart,
      ),
    );

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(child: chartWidget),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: FloatingActionButton(
              onPressed: () {
                setState(() {
                  data.putIfAbsent(
                      '2012', () => ClicksPerYear('2012', 42, Colors.teal));
                });
              },
              child: Icon(
                Icons.add,
              ),
              backgroundColor: Colors.red,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: FloatingActionButton(
              onPressed: () {
                setState(() {
                  DateTime now = DateTime.now();
                  currentTime = DateFormat('dd/MM/yyyy').format(now);
                  data[currentTime].incrementClick();
                });
              },
              child: Icon(
                Icons.add,
              ),
            ),
          ),
        ],
      ),
    );
  }
}