flutter_charts 0.5.2 copy "flutter_charts: ^0.5.2" to clipboard
flutter_charts: ^0.5.2 copied to clipboard

Charts Library for Flutter, written in Dart with Flutter. Allows to create line chart and bar chart by specifying data as a simple array.

example/lib/main.dart

/// Example app for flutter_charts.
///
/// All classes without prefix in this code are either
/// - from material.dart or
/// - from flutter_charts.dart exports (this library)
/// Also, material.dart exports many dart files, including widgets.dart,
/// so Widget classes are referred to without prefix
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:tuple/tuple.dart' show Tuple2;
import 'dart:io' as io show exit;

// provides: data.dart, random_chart_data.dart, line_chart_options.dart
import 'package:flutter_charts/flutter_charts.dart';
import 'package:flutter_charts/src/util/string_extension.dart' show StringExtension;

import 'src/util/examples_descriptor.dart';

import 'dart:ui' as ui show Color;


// import 'package:flutter/material.dart' as material show Colors; // any color we can use is from here, more descriptive

/// Example of simple line chart usage in an application.
///
/// Library note: This file is on the same level as _lib_, so everything from _lib_ must
/// be imported using the "package:" scheme, e.g.
/// ```dart
///    import 'package:flutter_charts/flutter_charts.dart';
/// ```
void main() {
  // runApp is function (not method) in PROJ/packages/flutter/lib/src/widgets/binding.dart.
  //
  // Why we do not have to import binding.dart?
  //
  // In brief, because it is imported through another file, material.dart.
  //
  // Longer reason
  //
  //      - Because Any Flutter app must have:
  //        1) main() { runApp(MyApp()) } // entry point
  //        2) import 'package:flutter/material.dart';
  //          Note: *NOT* 'package:flutter/material/material.dart'.
  //          Note: material.dart is on path: PROJ/packages/flutter/lib/material.dart
  //          so another note:
  //             * the lib level is skipped int the import reference
  //             * package: represent a directory where packages
  //               for this project are installed in pub update package
  //      - And:
  //        3) The imported 'package:flutter/material.dart' contains line:
  //            export 'widgets.dart';
  //            which references, at the same level, a path:
  //               PROJ/packages/flutter/lib/widgets.dart
  //            which contains:
  //               export 'src/widgets/binding.dart';
  //               on path: PROJ/packages/flutter/lib/src/widgets/binding.dart
  //            which contains the function runApp().
  //
  //  So, eventually, the loading of binding.dart, and it's runApp() function
  //  in MyApp is achieved this way:
  //    1) This file (example/lib/main.dart) has
  //        - import 'package:flutter/material.dart' (references PROJ/packages/flutter/lib/material.dart)
  //    2) material.dart has
  //        - export 'widgets.dart'; (references same dir        PROJ/packages/flutter/lib/widgets.dart)
  //    3) widgets.dart has
  //        - export 'src/widgets/binding.dart'; (references dir PROJ/packages/flutter/lib/src/widgets/binding.dart)
  //    4) binding.dart has
  //        - the runApp() function
  //
  // This process achieves importing (heh via exports) the file
  //    packages/flutter/lib/src/widgets/binding.dart
  //    which has the runApp() function.
  //
  var exampleComboToRun = requestedExampleToRun();
  if (!ExamplesDescriptor().exampleComboIsAllowed(exampleComboToRun)) {
    // Better: SystemChannels.platform.invokeMethod('SystemNavigator.pop');
    io.exit(0);
  }
  
  // If using a client-specific font, such as GoogleFonts, this is needed, in conjunction with 
  // installing the fonts in pubspec.yaml. 
  // But these 2 additions are needed ONLY in integration tests. App works without those 2 additions.
  GoogleFonts.config.allowRuntimeFetching = false;

  runApp(const MyApp());
}

/// Pull values of environment variables named ['EXAMPLE_TO_RUN'] and ['CHART_TYPE_TO_SHOW']
///   passed to the program by `--dart-define` options.
///
/// Converts the dart-define(d) environment variables passed to 'flutter run', 'flutter test', or 'flutter driver',
///   to a tuple of enums which describe the example to run, and the chart type to show.
///
Tuple2<ExamplesEnum, ExamplesChartTypeEnum> requestedExampleToRun() {
  // Pickup what example to run, and which chart to show (line, vertical bar).
  const String exampleToRunStr = String.fromEnvironment('EXAMPLE_TO_RUN', defaultValue: 'ex10RandomData');
  ExamplesEnum exampleComboToRun = exampleToRunStr.asEnum(ExamplesEnum.values);

  const String chartTypeToShowStr = String.fromEnvironment('CHART_TYPE_TO_SHOW', defaultValue: 'lineChart');
  ExamplesChartTypeEnum chartTypeToShow = chartTypeToShowStr.asEnum(ExamplesChartTypeEnum.values);

  return Tuple2(exampleComboToRun, chartTypeToShow);
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  /// Builds the widget which becomes the root of the application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Charts Demo Title',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Charts Demo'),
    );
  }
}

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

  // This widget is the home page of your application. It is stateful,
  // meaning that it has a State object (defined below) that contains
  // fields that affect how it looks.

  // This class is the configuration for the state. It holds the
  // values (in this case the title) provided by the parent (in this
  // case the App widget) and used by the build method of the State.
  // Fields in a Widget subclass are always marked "final".

  final String title;

  /// Stateful widgets must implement the [createState] method.
  ///
  /// The [createState] method will typically return the
  /// new state of the widget.
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

/// This state object is created in the stateful widget's [MyHomePage] call to
/// [MyHomePage.createState].
///
/// In the rest of the lifecycle, this state object holds on one object,
/// - [descriptorOfExampleToRun]
///
/// The rest of the objects (options, data, etc) are created during the build.
///
/// While this home page state object is created only once (hence, the above
/// state's member [descriptorOfExampleToRun], is created only once, the charts shown
/// in this demo, the [LineChart] and the [VerticalBarChart], are recreated
/// in this object's [build] method - so, **the chart objects are created over
/// and over**.
///
/// Note: The (each [build]) recreated chart objects reuse the state's members
/// [descriptorOfExampleToRun], so this could be considered
/// "expensive to create".
///
/// Note: At the same time, because the this state's [build] calls
///    _ExampleDefiner definer = _ExampleDefiner(descriptorOfExampleToRun);
//     Widget chartToRun = definer.createRequestedChart();
/// recreates lineChartOptions, verticalBarChartOptions, chartData,
/// and xContainerLabelLayoutStrategy, the core of this state object (all members)
/// is effectively recreated on each state's [build] call.
///
class _MyHomePageState extends State<MyHomePage> {
  // Note (on null safety):
  //     To be able to have non-nullable types on members
  //     such as _lineChartOptions (and all others here), 2 things need be done:
  //   1. The member must be initialized with some non-null value,
  //      either in the definition or in constructor initializer list
  //   2. If a member is passed to a constructor (see  _MyHomePageState.fromOptionsAndData)
  //      the constructor value must still be marked "required".
  //      This serves as a lasso that enforces callers to set the non-null.
  //      But why Dart would not use the initialized value?

  /// Get the example to run from environment variable.
  Tuple2<ExamplesEnum, ExamplesChartTypeEnum> descriptorOfExampleToRun = requestedExampleToRun();

  /// Default constructor uses member defaults for all options and data.
  _MyHomePageState();

  void _chartStateChanger() {
    setState(() {
      // This call to setState tells the Flutter framework that
      // something has changed in this State, which causes it to rerun
      // the build method below so that the display can reflect the
      // updated values. If we changed state without calling
      // setState(), then the build method would not be called again,
      // and so nothing would appear to happen.

      /// here we create new random data to illustrate state change
      // _ExampleDefiner.createRequestedChart();
    });
  }

  /// Builds the widget that is the home page state.
  @override
  Widget build(BuildContext context) {
    // General notes on Windows and sizing in Flutter
    //
    // The (singleton?) window object is available anywhere using ui.
    // From window, we can get ui.window.devicePixelRatio, and also
    //   ui.Size windowLogicalSize = ui.window.physicalSize / devicePixelRatio
    // Note: Do not use ui.window for any sizing: see
    //       https://github.com/flutter/flutter/issues/11697
    //
    // MediaQueryData mediaQueryData = MediaQuery.of(context);
    // Use MediaQuery.of(context) for any sizing.
    // Note: mediaQueryData can still return 0 size,
    //       but if MediaQuery.of(context) is used, Flutter will guarantee
    //       the build(context) will be called again !
    //        (once non 0 size becomes available)
    //
    // Note: windowLogicalSize = size of the media (screen) in logical pixels
    // Note: same as ui.window.physicalSize / ui.window.devicePixelRatio;
    // ui.Size windowLogicalSize = mediaQueryData.size;
    //
    // `devicePixelRatio` = number of device pixels for each logical pixel.
    // Note: in all known hardware, size(logicalPixel) > size(devicePixel)
    // Note: this is also, practically, never needed
    // double logicalToDevicePixelSize = mediaQueryData.devicePixelRatio;
    //
    // `textScaleFactor` = number of font pixels for each logical pixel.
    // Note: with some fontSize, if text scale factor is 1.5
    //       => text font is 1.5x larger than the font size.
    // double fontScale = mediaQueryData.textScaleFactor;
    //
    // To give the LineChart full width and half of height of window.
    // final ui.Size chartLogicalSize =
    //     new Size(windowLogicalSize.width, windowLogicalSize.height / 2);
    //
    // print(" ### Size: ui.window.physicalSize=${ui.window.physicalSize}, "
    //     "windowLogicalSize = mediaQueryData.size = $windowLogicalSize,"
    //     "chartLogicalSize=$chartLogicalSize");

    // The [_ExampleDefiner] creates the instance of the example chart that will be displayed.
    _ExampleDefiner definer = _ExampleDefiner(descriptorOfExampleToRun);
    Widget chartToRun = definer.createRequestedChart();
    _ExampleSideEffects exampleSpecific = definer.exampleSideEffects;

    // [MyHomePage] extends [StatefulWidget].
    // [StatefulWidget] calls build(context) every time setState is called,
    // for instance as done by the _chartStateChanger method above.
    // The Flutter framework has been optimized to make rerunning
    // build methods fast, so that you can just rebuild anything that
    // needs updating rather than having to individually change
    // instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that
        // was created by the App.build method, and use it to set
        // our appbar title.
        title: Text(widget.title),
      ),
      // Center is a layout widget. It takes a single child and
      // positions it in the middle of the parent.
      body: Center(
        // Column is also layout widget. It takes a list of children
        // and arranges them vertically. By default, it sizes itself
        // to fit its children horizontally, and tries to be as tall
        // as its parent.
        //
        // Invoke "debug paint" (press "p" in the console where you
        // ran "flutter run", or select "Toggle Debug Paint" from the
        // Flutter tool window in IntelliJ) to see the wireframe for
        // each widget.
        //
        // Column has various properties to control how it sizes
        // itself and how it positions its children. Here we use
        // mainAxisAlignment to center the children vertically; the
        // main axis here is the vertical axis because Columns are
        // vertical (the cross axis would be horizontal).

        // Expanded can be around one child of a Row or a Column
        // (there can be one or more children of those layouts).
        //
        // In this document below, we use | as abbreviation for vertical expansion,
        // <--> for horizontal expansion.
        //
        // "Expanded" placed around one of children of Row, or Column,
        // stretches/pulls the expanded child in the parent's
        // "growing" direction.
        //
        // So:
        //   - Inside Column (children: [A, B, Expanded (C)]) stretches C in
        //     column's "growing" direction (that is vertically |)
        //     to the fullest available outside height.
        //   - For Row  (children: [A, B, Expanded (C)]) stretches C in
        //     row's "growing" direction (that is horizontally <-->)
        //     to the fullest available outside width.
        // The layout of this code, is, structurally like this:
        //   Column (
        //      mainAxisAlignment: MainAxisAlignment.center,
        //      children: [
        //        vvv,
        //        Expanded (
        //          Row  (
        //            crossAxisAlignment: CrossAxisAlignment.stretch,
        //            children: [
        //              >>>, Expanded (Chart), <<<,
        //            ]),
        //        ^^^
        //      ])
        // The outer | expansion, in the Column's middle child
        //   pulls/stretches the row vertically |
        //   BUT also needs explicit
        //   crossAxisAlignment: CrossAxisAlignment.stretch.
        //   The cross alignment stretch carries
        //   the | expansion to all <--> expanded children.
        //  Basically, while "Expanded" only applies stretch in one
        //    direction, another outside "Expanded" with CrossAxisAlignment.stretch
        //    can force the innermost child to be stretched in both directions.
        child: Column(
          // mainAxisAlignment: MainAxisAlignment.center, // = default, not needed
          children: <Widget>[
            ElevatedButton(
              // Style would need a custom MaterialStateColor extension.
              //   style: ButtonStyle(backgroundColor: MyMaterialStateColor.resolve(() => Set(Colors))),
              onPressed: _chartStateChanger,
              child: null,
            ),
            const Text(
              'vvvvvvvv:',
            ),
            Expanded(
              // expansion inside Column pulls contents |
              child: Row(
                // mainAxisAlignment: MainAxisAlignment.center, // = default, not needed
                // this stretch carries | expansion to <--> Expanded children
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Text(exampleSpecific.leftSqueezeText), // '>>>' by default
                  // LineChart is CustomPaint:
                  // A widget that provides a canvas on which to draw
                  // during the paint phase.

                  // Row -> Expanded -> Chart expands chart horizontally <-->
                  Expanded(
                    // #### Core chart
                    child: chartToRun, // verticalBarChart, lineChart
                  ),
                  Text(exampleSpecific.rightSqueezeText), // '<<' by default
                  // labels fit horizontally
                  // const Text('<<<<<<'), // default, labels tilted, all present
                  // const Text('<<<<<<<<<<<'),   // labels skipped (shows 3 labels, legend present)
                  // const Text('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'), // labels skipped (shows 2 labels, legend present but text vertical)
                  // const Text('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'),// labels do overlap, legend NOT present
                ],
              ),
            ),
            const Text('^^^^^^:'),
            ElevatedButton(
              // style would need a custom MaterialStateColor extension.
              // style: ButtonStyle(backgroundColor: MyMaterialStateColor.resolve(() => Set(Colors))),
              onPressed: _chartStateChanger,
              child: null,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _chartStateChanger,
        tooltip: 'New Random Data',
        child: const Icon(Icons.add),
      ),
    );
  }
}

/// An example user-defined extension of [LabelCommonOptions] overrides the [LabelCommonOptions.labelTextStyle]
/// which is the source for user-specific font on labels.
class MyLabelCommonOptions extends LabelCommonOptions {
  const MyLabelCommonOptions(
  ) : super ();
  
  /// Override [labelTextStyle] with a new font, color, etc.
  @override
  get labelTextStyle => GoogleFonts.comforter(
        textStyle: const TextStyle(
          color: ui.Color(0xFF757575),
          fontSize: 14.0,
          fontWeight: FontWeight.w400, // Regular
        ),
      );
  
  /* This alternative works in an app as well, but not in integration test. All style set in options defaults.
  get labelTextStyle =>
      const ChartOptions().labelCommonOptions.labelTextStyle.copyWith(
        fontFamily: GoogleFonts.comforter().fontFamily,
      );
  */
}

/// The enabler of widget changes in the main test app by the code in [_ExampleDefiner].
/// 
/// This enables support for each example ability to manipulate it's environment
/// (by environment we mean the widgets in main.dart outside the chart).
/// 
/// Some examples need to change widgets of the main test app that are not part of the Chart.
/// For example, some test examples need to run in an increasingly 'squeezed' space available for the chart,
/// to test label changes with available space.
/// 
/// This class allows to carry such changes from the [_ExampleDefiner] to the widgets in the main app.
/// 
class _ExampleSideEffects {
  String leftSqueezeText = '>>>';
  String rightSqueezeText = '<<';
}

/// Defines which example to run.
///
/// Collects all 'variables' that are needed for each example: chart data, labels, colors and so on.
/// Makes available the verticalBarChart and the lineChart constructed from the 'variables'.
class _ExampleDefiner {

  /// Construct the definer object for the example.
  _ExampleDefiner(this.descriptorOfExampleToRun);

  /// Tuple which describes the example
  Tuple2<ExamplesEnum, ExamplesChartTypeEnum> descriptorOfExampleToRun;

  /// Support for each example manipulate it's environment - the widgets in main.dart outside the chart.
  _ExampleSideEffects exampleSideEffects = _ExampleSideEffects();

  /// Creates the example chart with name given in [exampleComboToRun] 
  /// through command line parameter --dart-define.
  ///
  /// Example assumes Android emulator is running or an Android/iOS device is connected:
  /// - Running:
  ///   ```sh
  ///     flutter run example/lib/main.dart \
  ///       --dart-define=EXAMPLE_TO_RUN=ex10RandomData \
  ///       --dart-define=CHART_TYPE_TO_SHOW=lineChart
  ///   ```
  /// will set [exampleComboToRun] to a concrete Tuple of [ExamplesEnum] and [ExamplesChartTypeEnum], 
  /// such as `Tuple(ex10RandomData, lineChart)`
  Widget createRequestedChart() {
    // Example requested to run
    ExamplesEnum exampleComboToRun = descriptorOfExampleToRun.item1;
    ExamplesChartTypeEnum chartTypeToShow = descriptorOfExampleToRun.item2;

    // Declare chartData; the data object will be different in every examples.
    ChartData chartData;
    
    // Create chartOptions defaults here, so we do not repeat it in every example section,
    //   unless specific examples need to override this chartOptions default.
    ChartOptions chartOptions = const ChartOptions();

    // Declare a null xContainerLabelLayoutStrategy.
    // To use a specific, client defined extension of DefaultIterativeLabelLayoutStrategy or LayoutStrategy,
    //   just create the extension instance similar to the DefaultIterativeLabelLayoutStrategy below.
    // If xContainerLabelLayoutStrategy is not set in an example (remains null), the charts instantiate
    //   a DefaultIterativeLabelLayoutStrategy.
    LabelLayoutStrategy? xContainerLabelLayoutStrategy;
    
    /// Main switch that includes code to all examples.
    /// The example which [ExamplesEnum] and [ExamplesChartTypeEnum] is passed in the combo is returned.
    /// Each example can also generate side effects in [exampleSideEffects], which allow the code in this 
    /// [createRequestedChart] method to influence the returned chart's surrounding widgets in the main app.
    switch (exampleComboToRun) {
      case ExamplesEnum.ex10RandomData:
        // Example shows a demo-type data generated randomly in a range.
        chartData = RandomChartData.generated(chartOptions: chartOptions);
        break;

      case ExamplesEnum.ex30AnimalsBySeasonWithLabelLayoutStrategy:
        // Example shows an explicit use of the DefaultIterativeLabelLayoutStrategy.
        // The xContainerLabelLayoutStrategy, if set to null or not set at all, 
        //   defaults to DefaultIterativeLabelLayoutStrategy
        // Clients can also create their own LayoutStrategy.
        xContainerLabelLayoutStrategy = DefaultIterativeLabelLayoutStrategy(
          options: chartOptions,
        );
        chartData = ChartData(
          dataRows: const [
            [10.0, 20.0, 5.0, 30.0, 5.0, 20.0],
            [30.0, 60.0, 16.0, 100.0, 12.0, 120.0],
            [25.0, 40.0, 20.0, 80.0, 12.0, 90.0],
            [12.0, 30.0, 18.0, 40.0, 10.0, 30.0],
          ],
          xUserLabels: const ['Wolf', 'Deer', 'Owl', 'Mouse', 'Hawk', 'Vole'],
          dataRowsLegends: const [
            'Spring',
            'Summer',
            'Fall',
            'Winter',
          ],
          chartOptions: chartOptions,
        );
        // chartData.dataRowsDefaultColors(); // if not set, called in constructor
        break;

      case ExamplesEnum.ex31SomeNegativeValues:
        // Example shows a mix of positive and negative data values.
        chartData = ChartData(
          dataRows: const [
            [2000.0, 1800.0, 2200.0, 2300.0, 1700.0, 1800.0],
            [1100.0, 1000.0, 1200.0, 800.0, 700.0, 800.0],
            [0.0, 100.0, -200.0, 150.0, -100.0, -150.0],
            [-800.0, -400.0, -300.0, -400.0, -200.0, -250.0],
          ],
          xUserLabels: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
          dataRowsLegends: const [
            'Big Corp',
            'Medium Corp',
            'Print Shop',
            'Bar',
          ],
          chartOptions: chartOptions,
        );
        break;

      case ExamplesEnum.ex32AllPositiveYsYAxisStartsAbove0:
        // Example shows how to create ChartOptions instance 
        //   which will request to start Y axis at data minimum.
        // Even though startYAxisAtDataMinRequested is set to true, this will not be granted on bar chart,
        //   as it does not make sense there.
        chartOptions = const ChartOptions(
          dataContainerOptions: DataContainerOptions(
            startYAxisAtDataMinRequested: true,
          ),
        );
        chartData = ChartData(
          dataRows: const [
            [20.0, 25.0, 30.0, 35.0, 40.0, 20.0],
            [35.0, 40.0, 20.0, 25.0, 30.0, 20.0],
          ],
          xUserLabels: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
          dataRowsLegends: const [
            'Off zero 1',
            'Off zero 2',
          ],
          chartOptions: chartOptions,
        );
        break;

      case ExamplesEnum.ex33AllNegativeYsYAxisEndsBelow0:
        // Example shows how to create ChartOptions instance
        //   which will request to end Y axis at maximum data (as all data negative).
        // Even though startYAxisAtDataMinRequested is set to true, this will not be granted on bar chart,
        //   as it does not make sense there.
        chartOptions = const ChartOptions(
          dataContainerOptions: DataContainerOptions(
            startYAxisAtDataMinRequested: true,
          ),
        );
        chartData = ChartData(
          dataRows: const [
            [-20.0, -25.0, -30.0, -35.0, -40.0, -20.0],
            [-35.0, -40.0, -20.0, -25.0, -30.0, -20.0],
          ],
          xUserLabels: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
          dataRowsLegends: const [
            'Off zero 1',
            'Off zero 2',
          ],
          chartOptions: chartOptions,
        );
        break;
      case ExamplesEnum.ex34OptionsDefiningUserTextStyleOnLabels:
        // Example shows how to use user-defined font in the chart labels.
        // In fact, same approach can be used more generally, to set any property 
        //   in user-defined TextStyle (font, font color, etc - any property available on TextStyle) on labels. 
        // To achieve setting custom fonts and/or any member of TextStyle, 
        //   client can declare their own extension of 'LabelCommonOptions', and override the `labelTextStyle` getter.
        // A sample declaration of the class MyLabelCommonOptions, is given here as a comment.
        // ```dart
        //      /// An example user-defined extension of [LabelCommonOptions] overrides the [LabelCommonOptions.labelTextStyle]
        //      /// which is the source for user-specific font on labels.
        //      class MyLabelCommonOptions extends LabelCommonOptions {
        //        const MyLabelCommonOptions(
        //        ) : super ();
        //  
        //        /// Override [labelTextStyle] with a new font, color, etc.
        //        @override
        //        get labelTextStyle => GoogleFonts.comforter(
        //          textStyle: const TextStyle(
        //          color: ui.Color(0xFF757575),
        //          fontSize: 14.0,
        //          fontWeight: FontWeight.w400, // Regular
        //          ),
        //        );
        //  
        //        /* This alternative works in an app as well, but not in the integration test. All style set in options defaults.
        //        get labelTextStyle =>
        //          const ChartOptions().labelCommonOptions.labelTextStyle.copyWith(
        //            fontFamily: GoogleFonts.comforter().fontFamily,
        //          );
        //        */
        //      }
        // ```
        // Given such extended class, declare ChartOptions as follows:
        chartOptions = const ChartOptions(
          labelCommonOptions: MyLabelCommonOptions(),
          );
        // Then proceed as usual
        chartData = ChartData(
          dataRows: const [
            [20.0, 25.0, 30.0, 35.0, 40.0, 20.0],
            [35.0, 40.0, 20.0, 25.0, 30.0, 20.0],
          ],
          xUserLabels: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
          dataRowsLegends: const [
            'Font Test Series1',
            'Font Test Series2',
          ],
          chartOptions: chartOptions,
        );
        break;
      case ExamplesEnum.ex35AnimalsBySeasonNoLabelsShown:
        // Set chart options to show no labels
        chartOptions = const ChartOptions.noLabels();

        chartData = ChartData(
          dataRows: const [
            [10.0, 20.0, 5.0, 30.0, 5.0, 20.0],
            [30.0, 60.0, 16.0, 100.0, 12.0, 120.0],
            [25.0, 40.0, 20.0, 80.0, 12.0, 90.0],
            [12.0, 30.0, 18.0, 40.0, 10.0, 30.0],
          ],
          xUserLabels: const ['Wolf', 'Deer', 'Owl', 'Mouse', 'Hawk', 'Vole'],
          dataRowsLegends: const [
            'Spring',
            'Summer',
            'Fall',
            'Winter',
          ],
          chartOptions: chartOptions,
        );
        break;

      case ExamplesEnum.ex40LanguagesWithYOrdinalUserLabelsAndUserColors:
        // User-Provided Data (Y values), User-Provided X Labels, User-Provided Data Rows Legends, User-Provided Y Labels, User-Provided Colors
        // This example shows user defined Y Labels that derive order from data.
        //   When setting Y labels by user, the dataRows value scale
        //   is irrelevant. User can use for example interval <0, 1>,
        //   <0, 10>, or any other, even negative ranges. Here we use <0-10>.
        //   The only thing that matters is  the relative values in the data Rows.
        // Current implementation sets
        //   the minimum of dataRows range (1.0 in this example)
        //     on the level of the first Y Label ("Low" in this example),
        //   and the maximum  of dataRows range (10.0 in this example)
        //     on the level of the last Y Label ("High" in this example).
        chartData = ChartData(
          dataRows: const [
            [9.0, 4.0, 3.0, 9.0],
            [7.0, 6.0, 7.0, 6.0],
            [4.0, 9.0, 6.0, 8.0],
            [3.0, 9.0, 10.0, 1.0],
          ],
          xUserLabels: const ['Speed', 'Readability', 'Level of Novel', 'Usage'],
          dataRowsColors: const [
            Colors.blue,
            Colors.yellow,
            Colors.green,
            Colors.amber,
          ],
          dataRowsLegends: const ['Java', 'Dart', 'Python', 'Newspeak'],
          yUserLabels: const [
            'Low',
            'Medium',
            'High',
          ],
          chartOptions: chartOptions,
        );

        break;

      case ExamplesEnum.ex50StocksWithNegativesWithUserColors:
        // User-Provided Data (Y values), User-Provided X Labels, User-Provided Data Rows Legends, Data-Based Y Labels, User-Provided Colors,
        //        This shows a bug where negatives go below X axis.
        // If we want the chart to show User-Provided textual Y labels with
        // In each column, adding it's absolute values should add to same number:
        // todo-04-examples 100 would make more sense, to represent 100% of stocks in each category. Also columns should add to the same number?

        chartData = ChartData(
          // each column should add to same number. everything else is relative.
          dataRows: const [
            [-9.0, -8.0, -8.0, -5.0, -8.0],
            [-1.0, -2.0, -4.0, -1.0, -1.0],
            [7.0, 8.0, 7.0, 11.0, 9.0],
            [3.0, 2.0, 1.0, 3.0, 3.0],
          ],
          xUserLabels: const ['Energy', 'Health', 'Finance', 'Chips', 'Oil'],
          dataRowsLegends: const [
            '-2% or less',
            '-2% to 0%',
            '0% to +2%',
            'more than +2%',
          ],
          dataRowsColors: const [
            Colors.red,
            Colors.grey,
            Colors.greenAccent,
            Colors.black,
          ],
          chartOptions: chartOptions,
        );
        break;

      case ExamplesEnum.ex52AnimalsBySeasonLogarithmicScale:
        chartOptions = const ChartOptions(
          dataContainerOptions: DataContainerOptions(
            yTransform: log10,
            yInverseTransform: inverseLog10,
          ),
        );
        chartData = ChartData(
          dataRows: const [
            [10.0, 600.0, 1000000.0],
            [20.0, 1000.0, 1500000.0],
          ],
          xUserLabels: const ['Wolf', 'Deer', 'Mouse'],
          dataRowsLegends: const [
            'Spring',
            'Summer',
          ],
          chartOptions: chartOptions,
        );
        break;

      case ExamplesEnum.ex60LabelsIteration1:
        // Example with side effects cannot be simply pasted to your code, as the _ExampleSideEffects is private
        // This example shows the result with sufficient space to show all labels
        chartData = ChartData(
          dataRows: const [
            [200.0, 190.0, 180.0, 200.0, 250.0, 300.0],
            [300.0, 280.0, 260.0, 240.0, 300.0, 350.0],
          ],
          xUserLabels: const ['January', 'February', 'March', 'April', 'May', 'June'],
          dataRowsLegends: const [
            'Owl count',
            'Hawk count',
          ],
          chartOptions: chartOptions,
        );
        exampleSideEffects = _ExampleSideEffects()..leftSqueezeText=''.. rightSqueezeText='';
        break;

      case ExamplesEnum.ex60LabelsIteration2:
        // Example with side effects cannot be simply pasted to your code, as the _ExampleSideEffects is private
        // This example shows the result with sufficient space to show all labels, but not enough to be horizontal;
        // The iterative layout strategy makes the labels to tilt but show fully.
        chartData = ChartData(
          dataRows: const [
            [200.0, 190.0, 180.0, 200.0, 250.0, 300.0],
            [300.0, 280.0, 260.0, 240.0, 300.0, 350.0],
          ],
          xUserLabels: const ['January', 'February', 'March', 'April', 'May', 'June'],
          dataRowsLegends: const [
            'Owl count',
            'Hawk count',
          ],
          chartOptions: chartOptions,
        );
        exampleSideEffects = _ExampleSideEffects()..leftSqueezeText='>>'.. rightSqueezeText='<' * 3;
        break;

      case ExamplesEnum.ex60LabelsIteration3:
        // Example with side effects cannot be simply pasted to your code, as the _ExampleSideEffects is private
        // This example shows the result with sufficient space to show all labels, not even tilted;
        // The iterative layout strategy causes some labels to be skipped.
        chartData = ChartData(
          dataRows: const [
            [200.0, 190.0, 180.0, 200.0, 250.0, 300.0],
            [300.0, 280.0, 260.0, 240.0, 300.0, 350.0],
          ],
          xUserLabels: const ['January', 'February', 'March', 'April', 'May', 'June'],
          dataRowsLegends: const [
            'Owl count',
            'Hawk count',
          ],
          chartOptions: chartOptions,
        );
        exampleSideEffects = _ExampleSideEffects()..leftSqueezeText='>>'.. rightSqueezeText='<' * 6;
        break;

      case ExamplesEnum.ex60LabelsIteration4:
      // Example with side effects cannot be simply pasted to your code, as the _ExampleSideEffects is private
      // This example shows the result with sufficient space to show all labels, not even tilted;
      // The iterative layout strategy causes more labels to be skipped.
        chartData = ChartData(
          dataRows: const [
            [200.0, 190.0, 180.0, 200.0, 250.0, 300.0],
            [300.0, 280.0, 260.0, 240.0, 300.0, 350.0],
          ],
          xUserLabels: const ['January', 'February', 'March', 'April', 'May', 'June'],
          dataRowsLegends: const [
            'Owl count',
            'Hawk count',
          ],
          chartOptions: chartOptions,
        );
        exampleSideEffects = _ExampleSideEffects()..leftSqueezeText='>>'.. rightSqueezeText='<' * 30;
        break;

      case ExamplesEnum.ex900ErrorFixUserDataAllZero:

        /// Currently, setting [ChartDate.dataRows] requires to also set all of
        /// [chartData.xUserLabels], [chartData.dataRowsLegends], [chartData.dataRowsColors]
        // Fix was: Add default legend to ChartData constructor AND fix scaling util_dart.dart scaleValue.
        chartData = ChartData(
          dataRows: const [
            [0.0, 0.0, 0.0],
          ],
          // Note: When ChartData is defined,
          //       ALL OF  xUserLabels,  dataRowsLegends, dataRowsColors
          //       must be set by client
          xUserLabels: const ['Wolf', 'Deer', 'Mouse'],
          dataRowsLegends: const [
            'Row 1',
          ],
          dataRowsColors: const [
            Colors.blue,
          ],
          chartOptions: chartOptions,
        );
        break;
    }

    // LineChart or VerticalBarChart depending on what is set in environment.
    Widget chartToRun;

    switch (chartTypeToShow) {
      case ExamplesChartTypeEnum.lineChart:
        LineChartTopContainer lineChartContainer = LineChartTopContainer(
          chartData: chartData,
          xContainerLabelLayoutStrategy: xContainerLabelLayoutStrategy,
        );

        LineChart lineChart = LineChart(
          painter: LineChartPainter(
            lineChartContainer: lineChartContainer,
          ),
        );
        chartToRun = lineChart;
        break;
      case ExamplesChartTypeEnum.verticalBarChart:
        VerticalBarChartTopContainer verticalBarChartContainer = VerticalBarChartTopContainer(
          chartData: chartData,
          xContainerLabelLayoutStrategy: xContainerLabelLayoutStrategy,
        );

        VerticalBarChart verticalBarChart = VerticalBarChart(
          painter: VerticalBarChartPainter(
            verticalBarChartContainer: verticalBarChartContainer,
          ),
        );

        chartToRun = verticalBarChart;
        break;
    }
    // Returns the configured LineChart or VerticalBarChart that will be added to the [_MyHomePageState],
    //   depending on the chart type requested by [requestedExampleToRun]
    return chartToRun;
  }
}
83
likes
115
pub points
95%
popularity

Publisher

unverified uploader

Charts Library for Flutter, written in Dart with Flutter. Allows to create line chart and bar chart by specifying data as a simple array.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-2-Clause-Views (LICENSE)

Dependencies

decimal, flutter, google_fonts, logger, tuple, vector_math

More

Packages that depend on flutter_charts