Tal*_*leb 9 charts legend flutter dynamic-chart-series google-barchart
我使用charts_flutter创建BarChart,目前我想自定义它以构建如下图所示的 barChart:
在这里,我想做以下选项:
请看我的代码:
pubspec.yaml :
dev_dependencies:
flutter_test:
sdk: flutter
charts_flutter: ^0.9.0
Run Code Online (Sandbox Code Playgroud)
series_legend_options.dart :
import 'dart:math';
import 'package:charts_common/src/chart/common/behavior/legend/legend.dart';
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
const Color blueColor = Color(0xff1565C0);
const Color orangeColor = Color(0xffFFA000);
class LegendOptions extends StatelessWidget {
final List<charts.Series> seriesList;
static const secondaryMeasureAxisId = 'secondaryMeasureAxisId';
final bool animate;
LegendOptions(this.seriesList, {this.animate});
factory LegendOptions.withSampleData() {
return LegendOptions(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
@override
Widget build(BuildContext context) {
return charts.BarChart(
seriesList,
animate: animate,
barGroupingType: charts.BarGroupingType.grouped,
defaultRenderer: charts.BarRendererConfig(
cornerStrategy: const charts.ConstCornerStrategy(50)),
primaryMeasureAxis: charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(
desiredMinTickCount: 6,
desiredMaxTickCount: 10,
),
),
secondaryMeasureAxis: charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(
desiredTickCount: 6, desiredMaxTickCount: 10)),
selectionModels: [
charts.SelectionModelConfig(
changedListener: (charts.SelectionModel model) {
if (model.hasDatumSelection)
print(model.selectedSeries[0]
.measureFn(model.selectedDatum[0].index));
})
],
behaviors: [
charts.SeriesLegend.customLayout(
CustomLegendBuilder(),
position: charts.BehaviorPosition.top,
outsideJustification: charts.OutsideJustification.start,
),
],
);
}
static List<charts.Series<OrdinalSales, String>> _createSampleData() {
final desktopSalesData = [
OrdinalSales('2/14', 29),
OrdinalSales('2/15', 25),
OrdinalSales('2/16', 100),
OrdinalSales('2/17', 75),
OrdinalSales('2/18', 70),
OrdinalSales('2/19', 70),
];
final tabletSalesData = [
OrdinalSales('2/14', 10),
OrdinalSales('2/15', 25),
OrdinalSales('2/16', 8),
OrdinalSales('2/17', 20),
OrdinalSales('2/18', 38),
OrdinalSales('2/19', 70),
];
return [
charts.Series<OrdinalSales, String>(
id: 'expense',
domainFn: (OrdinalSales sales, _) => sales.year,
measureFn: (OrdinalSales sales, _) => sales.sales,
data: desktopSalesData,
colorFn: (_, __) => charts.ColorUtil.fromDartColor(orangeColor),
labelAccessorFn: (OrdinalSales sales, _) =>
'expense: ${sales.sales.toString()}',
displayName: "Expense"),
charts.Series<OrdinalSales, String>(
id: 'income',
domainFn: (OrdinalSales sales, _) => sales.year,
measureFn: (OrdinalSales sales, _) => sales.sales,
data: tabletSalesData,
colorFn: (_, __) => charts.ColorUtil.fromDartColor(blueColor),
displayName: "Income",
)..setAttribute(charts.measureAxisIdKey, secondaryMeasureAxisId),
];
}
}
//Here is my CustomLegendBuilder
class CustomLegendBuilder extends charts.LegendContentBuilder {
@override
Widget build(BuildContext context, LegendState<dynamic> legendState,
Legend<dynamic> legend,
{bool showMeasures}) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: legend.chart.currentSeriesList
.map<Widget>((e) => InkWell(
//Here i Want to show and hide series when click on the legend
onTap: () {},
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 10, vertical: 5),
margin: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.all(Radius.circular(100)),
),
child: Text(
e.displayName,
style: TextStyle(color: Colors.white),
)),
))
.toList()
..add(Spacer())
..add(Transform.rotate(
angle: 90 * (pi / 180),
child: Icon(
Icons.tune,
size: 30,
color: Colors.red,
),
)));
}
}
////////////////////////////////
class OrdinalSales {
final String year;
final int sales;
OrdinalSales(this.year, this.sales);
}
Run Code Online (Sandbox Code Playgroud)
和main.dart:
import 'package:flutter/material.dart';
import 'series_legend_options.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeWidget(),
);
}
}
class HomeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
margin: EdgeInsets.all(20),
height: 300,
child: LegendOptions.withSampleData(),
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
最后这是我的结果:
如果您使用过 charts_flutter 库,请帮助我,非常感谢 :)
小智 5
我很确定一定有更好的方法(更干净、更有组织)来做到这一点,但我将您的代码与 flutter_charts 开源代码合并,并正确设置了颜色,并且标签对点击它做出反应隐藏或显示变量。这是示例:
/// Custom legend builder
class CustomLegendBuilder extends charts.LegendContentBuilder {
/// Convert the charts common TextStlyeSpec into a standard TextStyle.
TextStyle _convertTextStyle(
bool isHidden, BuildContext context, common.TextStyleSpec textStyle) {
return new TextStyle(
inherit: true,
fontFamily: textStyle?.fontFamily,
fontSize:
textStyle?.fontSize != null ? textStyle.fontSize.toDouble() : null,
color: Colors.white);
}
Widget createLabel(BuildContext context, common.LegendEntry legendEntry,
common.SeriesLegend legend, bool isHidden) {
TextStyle style =
_convertTextStyle(isHidden, context, legendEntry.textStyle);
Color color = charts.ColorUtil.toDartColor(legendEntry.color) ?? Colors.blue;
return new GestureDetector(
child: Container(
height: 30,
width: 90,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: isHidden ? (color).withOpacity(0.26): color,
),
child: Center(child: Text(legendEntry.label, style: style))),
onTapUp: makeTapUpCallback(context, legendEntry, legend));
}
GestureTapUpCallback makeTapUpCallback(BuildContext context,
common.LegendEntry legendEntry, common.SeriesLegend legend) {
return (TapUpDetails d) {
switch (legend.legendTapHandling) {
case common.LegendTapHandling.hide:
final seriesId = legendEntry.series.id;
if (legend.isSeriesHidden(seriesId)) {
// This will not be recomended since it suposed to be accessible only from inside the legend class, but it worked fine on my code.
legend.showSeries(seriesId);
} else {
legend.hideSeries(seriesId);
}
legend.chart.redraw(skipLayout: true, skipAnimation: false);
break;
case common.LegendTapHandling.none:
default:
break;
}
};
}
@override
Widget build(BuildContext context, common.LegendState legendState,
common.Legend legend,
{bool showMeasures}) {
final entryWidgets = legendState.legendEntries.map((legendEntry) {
var isHidden = false;
if (legend is common.SeriesLegend) {
isHidden = legend.isSeriesHidden(legendEntry.series.id);
}
return createLabel(context, legendEntry, legend as common.SeriesLegend, isHidden);
}).toList();
return Padding(
padding: const EdgeInsets.only(right: 40.0, top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: entryWidgets),
);
}
}
Run Code Online (Sandbox Code Playgroud)
关于您希望在点击时显示的值,也许这就是您正在寻找的。我让它与 CustomCircleSymbolRenderer 一起使用。您将看到 TextElement 被硬编码为“1”。要实现它,您可以在图表类上保存一个变量并调用其内容:
class MyChart extends StatelessWidget {
final List data;
static String pointerValue;
MyChart(this.data);
Run Code Online (Sandbox Code Playgroud)
在图表内,“行为:[]”下方:
selectionModels: [
SelectionModelConfig(changedListener: (SelectionModel model) {
if (model.hasDatumSelection)
pointerValue = model.selectedSeries[0]
.measureFn(model.selectedDatum[0].index)
.toString();
})
],
Run Code Online (Sandbox Code Playgroud)
然后在自定义渲染器上:
canvas.drawText(
TextElement(MyChart.pointerValue, style: textStyle),
(bounds.left).round(),
(bounds.top - 28).round());
Run Code Online (Sandbox Code Playgroud)
我前段时间在网上找到了一个例子,但我不确定在哪里。
| 归档时间: |
|
| 查看次数: |
1658 次 |
| 最近记录: |