Я пытался создать диаграмму с всплывающей подсказкой, используя плагин Google chart (charts_flutter: ^ 0.8.1) во флаттере. Я застрял в этом на неделю и почти уложился в срок. Любая помощь будет принята с благодарностью.
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:charts_flutter/src/text_element.dart';
import 'package:charts_flutter/src/text_style.dart' as style;
import 'package:project/Utils/charts/GroupStackedTooltip.dart';
import 'package:project/Utils/styles.dart';
class GroupStackedChartView extends StatefulWidget {
GroupStackedChartView(
{this.userData,
this.chartData,
this.combisetList,
this.targetLine,
this.chartYAsixLabel,
this.chartTitle});
final userData, chartData, combisetList, targetLine, chartYAsixLabel, chartTitle;
@override
GroupStackedChartViewState createState() => GroupStackedChartViewState();
}
class DataPerYear {
final String year;
double clicks;
final charts.Color color;
DataPerYear(this.year, this.clicks, Color color)
: this.color = charts.Color(
r: color.red, g: color.green, b: color.blue, a: color.alpha);
}
class GroupStackedChartViewState extends State<GroupStackedChartView> {
String currentSideDrawer = "logout";
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Widget sideDrawerContent = Drawer();
List<charts.Series> seriesList;
var targetLine;
var totalOrders = 0;
var overalltotalOrders = 0;
var totalSetOrders = 0;
var totalComponentOrders = 0;
List<DataPerYear> sterile = [];
List<DataPerYear> nonSterile = [];
List<DataPerYear> setDrawing = [];
@override
void initState() {
targetLine = widget.targetLine;
formatChartData();
super.initState();
}
formatChartData() {
sterile = [
DataPerYear('Jan', 10, Color(0xff3197F3)),
DataPerYear('Feb', 80, Color(0xff3197F3)),
DataPerYear('Mar', 0, Color(0xff3197F3)),
DataPerYear('Apr', 40, Color(0xff3197F3)),
DataPerYear('May', 0, Color(0xff3197F3)),
DataPerYear('Jun', 90, Color(0xff3197F3)),
DataPerYear('Jul', 0, Color(0xff3197F3)),
DataPerYear('Aug', 100, Color(0xff3197F3)),
DataPerYear('Sep', 50, Color(0xff3197F3)),
DataPerYear('Oct', 0, Color(0xff3197F3)),
DataPerYear('Nov', 70, Color(0xff3197F3)),
DataPerYear('Dec', 0, Color(0xff3197F3)),
];
nonSterile = [
DataPerYear('Jan', 10, Color(0xff3197F3)),
DataPerYear('Feb', 80, Color(0xff3197F3)),
DataPerYear('Mar', 0, Color(0xff3197F3)),
DataPerYear('Apr', 40, Color(0xff3197F3)),
DataPerYear('May', 0, Color(0xff3197F3)),
DataPerYear('Jun', 90, Color(0xff3197F3)),
DataPerYear('Jul', 0, Color(0xff3197F3)),
DataPerYear('Aug', 100, Color(0xff3197F3)),
DataPerYear('Sep', 50, Color(0xff3197F3)),
DataPerYear('Oct', 0, Color(0xff3197F3)),
DataPerYear('Nov', 70, Color(0xff3197F3)),
DataPerYear('Dec', 0, Color(0xff3197F3)),
];
setDrawing = [
DataPerYear('Jan', 10, Color(0xff3197F3)),
DataPerYear('Feb', 80, Color(0xff3197F3)),
DataPerYear('Mar', 0, Color(0xff3197F3)),
DataPerYear('Apr', 40, Color(0xff3197F3)),
DataPerYear('May', 0, Color(0xff3197F3)),
DataPerYear('Jun', 90, Color(0xff3197F3)),
DataPerYear('Jul', 0, Color(0xff3197F3)),
DataPerYear('Aug', 100, Color(0xff3197F3)),
DataPerYear('Sep', 50, Color(0xff3197F3)),
DataPerYear('Oct', 0, Color(0xff3197F3)),
DataPerYear('Nov', 70, Color(0xff3197F3)),
DataPerYear('Dec', 0, Color(0xff3197F3)),
];
}
@override
Widget build(BuildContext context) {
return barChart();
}
barChart() {
// Bar chart data START-------------------------------------------------------------------------
var series = [
charts.Series(
domainFn: (DataPerYear clickData, _) => clickData.year,
measureFn: (DataPerYear clickData, _) => clickData.clicks,
colorFn: (DataPerYear clickData, _) => clickData.color,
id: 'Clicks',
data: setDrawing,
labelAccessorFn: (DataPerYear clickData, _) =>
'${clickData.clicks.toString()}',
fillColorFn: (DataPerYear clickData, _) =>
charts.ColorUtil.fromDartColor(Color(0xffAECDEE)),
),
charts.Series(
domainFn: (DataPerYear clickData, _) => clickData.year,
measureFn: (DataPerYear clickData, _) => clickData.clicks,
colorFn: (DataPerYear clickData, _) => clickData.color,
id: 'Clicks',
data: nonSterile,
labelAccessorFn: (DataPerYear clickData, _) => '',
fillColorFn: (DataPerYear clickData, _) =>
charts.ColorUtil.fromDartColor(Color(0xff78B4F0)),
),
charts.Series(
domainFn: (DataPerYear clickData, _) => clickData.year,
measureFn: (DataPerYear clickData, _) => clickData.clicks,
colorFn: (DataPerYear clickData, _) => clickData.color,
id: 'Clicks',
data: sterile,
labelAccessorFn: (DataPerYear clickData, _) => '',
fillColorFn: (DataPerYear clickData, _) =>
charts.ColorUtil.fromDartColor(Color(0xff479CF0)),
),
];
var chart = charts.BarChart(
series,
animate: true,
// vertical: false,
// domainAxis: new charts.OrdinalAxisSpec(),
domainAxis: new charts.OrdinalAxisSpec(
renderSpec: new charts.SmallTickRendererSpec(
labelStyle: new charts.TextStyleSpec(
fontSize: 16,
color: charts.ColorUtil.fromDartColor(Color(0xff202020)),
fontFamily: 'Open_Sans',
fontWeight: 'w700',
lineHeight: 2,
),
lineStyle: new charts.LineStyleSpec(
color: charts.ColorUtil.fromDartColor(Color(0xff202020)),
// thickness: 2,
))),
primaryMeasureAxis: new charts.NumericAxisSpec(
renderSpec: new charts.GridlineRendererSpec(
labelStyle: new charts.TextStyleSpec(
fontSize: 16,
color: charts.ColorUtil.fromDartColor(Color(0xff202020)),
fontFamily: 'Open_Sans',
// fontWeight: Material,
// lineHeight: 2,
),
lineStyle: new charts.LineStyleSpec(
// color: charts.MaterialPalette.black
color: charts.ColorUtil.fromDartColor(Color(0xff202020)),
))),
// domainAxis: new charts.OrdinalAxisSpec(renderSpec: new charts.NoneRenderSpec()),
// barRendererDecorator: new charts.BarLabelDecorator<String>(),
defaultRenderer: new charts.BarRendererConfig(
groupingType: charts.BarGroupingType.stacked,
// weightPattern: [1, 3, 1],
stackHorizontalSeparator: 50,
// cornerStrategy: const charts.ConstCornerStrategy(30)
barRendererDecorator: new charts.BarLabelDecorator(
// labelAnchor: charts.BarLabelAnchor.middle,
labelPosition: charts.BarLabelPosition.outside,
insideLabelStyleSpec: new charts.TextStyleSpec(
fontSize: 14,
color: charts.ColorUtil.fromDartColor(Colors.white),
// lineHeight: 0.14,
fontWeight: '700',
),
outsideLabelStyleSpec: new charts.TextStyleSpec(
fontSize: 14,
color: charts.ColorUtil.fromDartColor(Color(0xff202020)),
lineHeight: 0.14,
// fontWeight: '700',
),
),
),
barGroupingType: charts.BarGroupingType.stacked,
customSeriesRenderers: [
new charts.BarTargetLineRendererConfig<String>(
// ID used to link series to this renderer.
customRendererId: 'customTargetLine',
),
],
selectionModels: [
charts.SelectionModelConfig(
changedListener: (charts.SelectionModel model) {
if (model.hasDatumSelection) {
GroupStackedToolTipMgr.setTitle({
'title':
'${model.selectedSeries[0].measureFn(model.selectedDatum[0].index)}',
'subTitle': '',
'itemCount': 3,
'repaintIndex': 1,
});
}
})
],
behaviors: [
new charts.LinePointHighlighter(
symbolRenderer: CustomCircleSymbolRenderer(),
drawFollowLinesAcrossChart: false,
defaultRadiusPx: 5,
showVerticalFollowLine:
charts.LinePointHighlighterFollowLineType.none,
selectionModelType: charts.SelectionModelType.info,
showHorizontalFollowLine:
charts.LinePointHighlighterFollowLineType.none,
),
],
);
var chartWidget = Container(
height: 388,
// padding: EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 340,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 20,
height: 400,
alignment: Alignment.center,
margin: EdgeInsets.only(right: 10),
child: RotatedBox(
quarterTurns: 3,
child: Text(
'Set Samples',
style: small.copyWith(height: 1),
))),
Container(
width: MediaQuery.of(context).size.width - 120,
child: chart,
),
],
),
),
SizedBox(
height: 30,
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 16,
height: 16,
color: Color(0xff479CF0),
margin: EdgeInsets.only(
right: 8,
),
),
Text(
'Sterile Set',
style: inputLabel.copyWith(height: 1.2),
),
Container(
width: 16,
height: 16,
color: Color(0xff78B4F0),
margin: EdgeInsets.only(right: 8, left: 24),
),
Text(
'Non-Sterile Set',
style: inputLabel.copyWith(height: 1.2),
),
Container(
width: 16,
height: 16,
color: Color(0xffAECDEE),
margin: EdgeInsets.only(right: 8, left: 24),
),
Text(
'Set Drawings',
style: inputLabel.copyWith(height: 1.2),
),
],
),
),
],
),
);
// Bar chart data End----------------------------------------------------------------------------
return Card(
elevation: 0,
color: Color(0xfffafafa),
child: Container(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.chartTitle,
style: heading5,
),
SizedBox(height: 24),
chartWidget,
],
),
),
);
}
}
файл всплывающей подсказки: -
import 'dart:math';
import 'package:charts_flutter/flutter.dart';
import 'package:charts_flutter/src/text_element.dart' as ChartText;
import 'package:charts_flutter/src/text_style.dart' as ChartStyle;
import 'package:flutter/material.dart';
String _title;
String _subTitle;
int _itemCounter;
int _repaintIndex;
bool _flag;
class GroupStackedToolTipMgr {
static String get title => _title;
static String get subTitle => _subTitle;
static int get itemCounter => _itemCounter;
static int get repaintIndex => _repaintIndex;
static bool get flag => _flag;
static set flag(_val){
_flag = _val;
}
static setTitle(Map<String, dynamic> data) {
_flag = false;
if (data['title'] != null && data['title'].length > 0) {
_title = data['title'];
}
if (data['subTitle'] != null && data['subTitle'].length > 0) {
_subTitle = data['subTitle'];
}
if (data['itemCounter'] != null && data['itemCounter'] > 0) {
_itemCounter = data['itemCounter'];
}
if (data['repaintIndex'] != null) {
_repaintIndex = data['repaintIndex'];
}
}
}
class CustomCircleSymbolRenderer extends CircleSymbolRenderer {
double height = 150;
static int counter = 0;
static Rectangle<num> prevBounds;
@override
bool shouldRepaint(CircleSymbolRenderer oldRenderer) {
print("should repaint called");
return super.shouldRepaint(oldRenderer);
}
@override
void paint(ChartCanvas canvas, Rectangle<num> bounds,
{List<int> dashPattern,
Color fillColor,
FillPatternType fillPattern,
Color strokeColor,
double strokeWidthPx}) {
super.paint(canvas, bounds,
dashPattern: dashPattern,
fillColor: fillColor,
strokeColor: strokeColor,
strokeWidthPx: strokeWidthPx);
counter +=1;
print("paint called.."+GroupStackedToolTipMgr.flag.toString());
print(counter.toString()+"===>"+GroupStackedToolTipMgr.itemCounter.toString());
if(counter>GroupStackedToolTipMgr.itemCounter){
counter = 0;
}
if(counter == GroupStackedToolTipMgr.repaintIndex && !GroupStackedToolTipMgr.flag){
// if((prevBounds.top!=bounds.top) && !GroupStackedToolTipMgr.flag){
print("bounds.."+bounds.left.toString()+"::"+bounds.top.toString());
canvas.drawRect(
Rectangle(
bounds.left,
bounds.top + 10,
bounds.width + 75,
bounds.height + 25
),
fill: ColorUtil.fromDartColor(Colors.black),
// fill: MaterialPalette.red.shadeDefault,
);
// canvas.drawPolygon(
// );
ChartStyle.TextStyle textStyle = ChartStyle.TextStyle();
textStyle.color = Color.white;
textStyle.fontSize = 14;
textStyle.fontFamily = 'Open_Sans';
canvas.drawText(
ChartText.TextElement(GroupStackedToolTipMgr.title, style: textStyle),
(bounds.left + 12).round(),
(bounds.top + 16).round(),
);
print("DrawText::"+GroupStackedToolTipMgr.title);
GroupStackedToolTipMgr.flag = true;
prevBounds = bounds;
}
}
}
A прикрепленный скриншот ниже: - введите описание изображения здесь
Вы нажали июньский месяц, но получили только синий полукруг в нижней синей полосе.