предисловие
Будь то в Интернете или на мобильных устройствах, диаграммы являются незаменимым инструментом для статистических данных.В настоящее время возможности флаттера на мобильной стороне становятся все более и более заметными.Написание некоторого статистического контента с помощью флаттера не требует реализации статистики диаграмм на 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
- 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((){
...
})
}