如何在颤动中为谷歌图表添加工具提示?

我试图在颤振中使用谷歌的图表(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;
    }
  }
}

下面附上一张截图:-** enter image description here

已经点击了六月,但在底部的蓝色条上只得到了蓝色的半圆形。

stack overflow how to add tooltip for google charts in flutter?
原文答案

答案:

作者头像

charts_flutter 包似乎已经停产。如果您不介意更改您正在使用的插件,您可能需要考虑切换到 fl_chart 插件。可以使用 BarChartGroupData showingTooltipIndicators 显示工具提示。