Flutter использует библиотеку диаграмм для определения функций диаграмм.

Flutter
Flutter использует библиотеку диаграмм для определения функций диаграмм.

предисловие

Будь то в Интернете или на мобильных устройствах, диаграммы являются незаменимым инструментом для статистических данных.В настоящее время возможности флаттера на мобильной стороне становятся все более и более заметными.Написание некоторого статистического контента с помощью флаттера не требует реализации статистики диаграмм на iOS и Android отдельно , Это также позволяет избежать некоторых различий в отображении iOS и Android на диаграмме, делая производительность обоих концов более равномерной. Google также официально предоставил решение для флаттер-чартов, chart_flutter, Хотя его возможностей все еще несколько недостаточно, я считаю, что с его скоростью обновления он будет иметь больше функций и будет более стабильным в будущем.

способность

В настоящее время charts_flutter обновлен до версии 0.6.0, смотрите журнал обновлений, чтобы увидетьздесь

Поддерживаемые типы диаграмм

Текущая библиотека диаграмм поддерживает три типа диаграмм, каждая из которых имеет несколько параметров конфигурации.

  • Гистограмма, поддерживает наложение нескольких рядов данных, горизонтальное отображение, временные ряды (отображается со временем по оси абсцисс, данные изменяются в соответствии с порядком времени)

  • Линейный график, поддерживает временные ряды

  • Круговая диаграмма

    条形图与三个分组系列 条形图与分组和堆积的条形图 折线图 饼图

Простой в использовании

Сначала найдите аннотациюДокументация

открыть первымpubspec.yamlфайл, добавить

flutter:
    sdk:flutter
  charts_flutter:^0.6.0

Теперь запустите функцию IDE, чтобы получить пакет, или используйте флаттер-пакеты для запуска из терминала.

В качестве примера используйте простейший пример из документации

/// Bar chart example
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:flutter/material.dart';
class SimpleBarChart extends StatelessWidget {
  final List<charts.Series> seriesList;
  final bool animate;
  SimpleBarChart(this.seriesList, {this.animate});
  /// Creates a [BarChart] with sample data and no transition.
  factory SimpleBarChart.withSampleData() {
    return new SimpleBarChart(
      _createSampleData(),
      // Disable animations for image tests.
      animate: false,
    );
  }
  @override
  Widget build(BuildContext context) {
    return new charts.BarChart(
      seriesList,
      animate: animate,
    );
  }
  /// Create one series with sample hard coded data.
  static List<charts.Series<OrdinalSales, String>> _createSampleData() {
    final data = [
      new OrdinalSales('2014', 5),
      new OrdinalSales('2015', 25),
      new OrdinalSales('2016', 100),
      new OrdinalSales('2017', 75),
    ];
    return [
      new charts.Series<OrdinalSales, String>(
        id: 'Sales',
        colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: data,
      )
    ];
  }
}
/// Sample ordinal data type.
class OrdinalSales {
  final String year;
  final int sales;

  OrdinalSales(this.year, this.sales);
}

Эффект следующий

效果

Кратко объясните функцию каждой части

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

Введение пакета диаграммы, поскольку диаграммы определяют пространство имен для всего содержимого в пакете диаграммы, поэтому нам нужно только chart.xxx для вызова содержимого в пакете.

Сначала определите класс данных для поддержки типа блока данных диаграммы.

class OrdinalSales {
  final String year;
  final int sales;

  OrdinalSales(this.year, this.sales);
}

Здесь, если используется временной ряд, тоfinal String yearпросто используйтеfinal DateTime year

Затем используйте метод *_createSampleData*, чтобы собрать данные в формат, поддерживаемый диаграммами.

static List<charts.Series<OrdinalSales, String>> _createSampleData() {
    final data = [
      new OrdinalSales('2014', 5),
      new OrdinalSales('2015', 25),
      new OrdinalSales('2016', 100),
      new OrdinalSales('2017', 75),
    ];

    return [
      new charts.Series<OrdinalSales, String>(
        id: 'Sales',
        colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: data,
      )
    ];
  }

Причина использования static здесь заключается в том, что место, где он вызывается раньше, определяется ключевым словом factory, а другие места, где он вызывается, могут завершить вызов компонента через SimpleBarChart.withSampleData (). Как правило, этот метод передает параметр данных для инициализации ведомого интерфейса.Динамические данные, полученные из . Этот метод возвращает тип List>, где тип Series определяется следующим образом:

  • id: уникальный идентификатор для одной системы данных, используемый для отображения нескольких серий диаграмм.
  • colorFn: Цвет диаграммы столбца, используемый для определения текущих данных
  • domain: Указывает на вещи, которые необходимо соблюдать, например, «магазин».
  • measure: используется для представления данных, таких как «продажи в магазине».
  • data:источник данных

Следующим шагом является определение метода построения для рендеринга данных диаграммы.

@override
Widget build(BuildContext context) {
    return new charts.BarChart(
      seriesList,
      animate: animate,
    );
}

charts.BarChartОн заключается в определении обычной диаграммы, в которой класс, определяющий диаграмму, также имеетTimeSeriesChart(определение графика по времени по оси абсцисс),LineChart(линейный график),OrdinalComboChart,PieChart(круговая диаграмма),ScatterPlotChartЖдать

пользовательская абсцисса

В большинстве случаев данные по абсциссе таблицы данных могут быть просто числом типа int или английским параметром, полученным из интерфейса. Нам нужно преобразовать его в читаемый текст. Ниже приведен пример:

Widget build(BuildContext context){
    final ticks=new charts.StaticOrdinalTickProviderSpec([
        new charts.TickSpec(
            '2018',
            label: '2018年',
            style: new charts.TextStyleSpec(//可对x轴设置颜色等
                color: new charts.Color(r: 0x4C, g: 0xAF, b: 0x50)))
        ),
         new charts.TickSpec(
            '2019',
            label: '2019年',
            style: new charts.TextStyleSpec(//可对x轴设置颜色等
                color: new charts.Color(r: 0x4C, g: 0xAF, b: 0x50)))
        ),
    ]);
    return new charts.BarChart(
      seriesList,
      animate: animate,
      domainAxis: new charts.OrdinalAxisSpec(
        tickProviderSpec: ticks,
      ),
    );
}

Эффект следующий:

Для Barchart Class Force DomainAxis инициализируйте класс OrdinalAxisspec (поскольку я использую BARCHARTS, это ORDINALAXISSPEC, если это TimeSerieschart, то используйте DateTimeAxisspec), первый параметр в Tickspec соответствует * new OrdinalSales ('2018', 5) * 2018 , метка указывает данные, которые необходимо отобразить, а стиль можно использовать для определения цвета размера символов по горизонтали и т. д.

пользовательская ордината

Подобно пользовательской абсциссе, ордината определяется, например, посредством primaryMeasureAxis.

...
    return new charts.BarChart(
      seriesList,
      animate: animate,
      domainAxis: new charts.OrdinalAxisSpec(
        tickProviderSpec: ticks,
      ),
      primaryMeasureAxis:new charts.NumericAxisSpec(
                tickFormatterSpec: new charts.BasicNumericTickFormatterSpec((value)=>{
                    '${value / 10000}万';
                });
      ),
    );
...

BasicNumericTickFormatterSpec передаст функцию обратного вызова. Параметром в функции являются исходные данные типа num. Например, если исходные данные 100 000, они станут отображать 100 000.

Этот метод также можно использовать для определения абсцисс.

Определить отображение информации о щелчке

Если я нажму на столбец на диаграмме, как заставить его отображать определенные данные, диаграммы предоставляют способ получить конкретную информацию о щелчке

...
selectionModels: [
    new charts.SelectionModelConfig(
      type: charts.SelectionModelType.info,
      changedListener: _onSelectionChanged,
    )
  ],
...
void _onSelectionChanged(charts.SelectionModel model){
    ...
}

Модель - это некоторая информация, возвращаемая после щелчка. Вы можете получить информацию о щелчке через model.selectedDatum. Чтобы получить конкретную информацию, вы можете проверить информацию через точку останова и получить необходимые данные.

Я определил компонент, который отображается после нажатия, и мне нужно взять его себе:

class ShowDetail extends StatelessWidget {
  final String time;
  final String type;
  final double number;
  final bool left;
  ShowDetail({this.time, this.type, this.number, this.left = true});
  @override
  Widget build(BuildContext context) {
    var style = TextStyle(color: Colors.white, fontSize: 10);
    // var position = left ? {'left': 0} : {'right': -10};
    return Positioned(
      right: left ? null : -10,
      left: left ? 50 : null,
      child: Container(
          width: 125,
          // height: 35,
          color: Color.fromRGBO(0, 0, 0, 0.7),
          padding: EdgeInsets.all(4),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                time,
                style: style,
              ),
              Container(
                width: 165,
                height: 15,
                child: Stack(
                  children: [
                    Positioned(
                      child: new CustomPaint(
                          size: new Size(13, 13), painter: new MyPainter()),
                    ),
                    Positioned(
                        left: 10,
                        child: Text(
                          type,
                          style: style,
                        )),
                    Positioned(
                      right: 1,
                      child: Text(
                        number.toString(),
                        style: style,
                      ),
                    ),
                  ],
                ),
              ),
            ],
          )),
    );
  }
}

//小点点
class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Paint _paint = Paint()
      ..colorFilter = ColorFilter.mode(
          Color.fromARGB(243, 190, 35, 1), BlendMode.srcATop) //颜色渲染模式
      ..filterQuality = FilterQuality.high; //颜色渲染模式的质量
    canvas.drawCircle(new Offset(6, 8), 4, _paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

пример вызова


ShowDetail(
  time: clickTime,
  type: type,
  number: cost,
  left: left,
)

Где время представляет содержимое на горизонтальной оси, тип представляет собой тип диаграммы, число представляет содержимое на вертикальной оси, а левое значение указывает, находится ли оно слева или справа. Это написано по моему собственному делу, вы можете изменить его самостоятельно, полный код можно посмотретьздесь

Эффект:

Дефекты компонентов и решения

Изменения данных не обновляют проблему

Добавьте компонент Container вне графа определения и добавьте значение ключа.

Нажмите, чтобы сообщить об ошибке

Проблема: когда я использую линейный график, после нажатия на скорость линейного графика я использую setState, чтобы сообщить об ошибке '_drawAreaBoundsOutdated == false': это неверно..

Решение: Это дефект библиотеки графиков. В настоящее время я не нашел хорошего решения. Следующее решение может устранить ошибку.

Future.delayed(const Duration(milliseconds: 500), () {
  setState((){
    ...
  })
}