0

我实际上使用了两个依赖:syncfusion颤动图虚线

我的图表看起来像这样(见图1)

在此处输入图像描述

您可以点击图表上的项目符号点(或篮球表情符号)以显示虚线和工具提示小部件。我的问题是,如果我的图表上没有足够的高度,显示的小部件会在底部(这不是我们的目标,见图 2)。我怎样才能实现始终在图表顶部显示我的小部件?

在此处输入图像描述

我用溢出框和堆栈搜索,但经过几个小时后,我可以自己完成。该图表的代码可在此处获得:

https://pastebin.com/6VX1VhRH

import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:lifetizr/misc/utils.dart';
import 'package:lifetizr/ui/screens/homepage/homepage_viewmodel.dart';
import 'package:lifetizr/ui/widgets/activity_block_preview.dart';
import 'package:stacked/stacked.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:theme_provider/theme_provider.dart';

class ChartBlock extends StatefulWidget {
  @override
  _ChartBlockState createState() => _ChartBlockState();
}

class _ChartBlockState extends State<ChartBlock> {
  List<_DataPoint> graphData = [];

  @override
  void initState() {
    super.initState();
    loadData();
  }

  void loadData() async {
    await HomepageViewModel().getGraphData().then(
      (value) {
        List<_DataPoint> tmpData = [];

        tmpData.add(_DataPoint(DateTime.fromMillisecondsSinceEpoch(0).toString(), 290));

        for (var item in value['allBloodglucoses']['edges']) {
          tmpData.add(_DataPoint(
              item['node']['timestamp'], item['node']['bloodGlucose']));
        }

        setState(
          () {
            graphData = tmpData;
          },
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final controller = ThemeProvider.controllerOf(context);

    return ViewModelBuilder<HomepageViewModel>.reactive(
      viewModelBuilder: () => HomepageViewModel(),
      builder: (context, model, child) {
        return SfCartesianChart(
          trackballBehavior: TrackballBehavior(
              lineWidth: 5,
              lineColor: reverseColorGrabber(controller),
              lineType: TrackballLineType.vertical,
              enable: true,
              shouldAlwaysShow: true,
              tooltipAlignment: ChartAlignment.far,
              tooltipSettings: InteractiveTooltip(
                arrowWidth: 0,
                arrowLength: 0,
                borderColor: reverseColorGrabber(controller),
                borderRadius: 15,
                borderWidth: 15,
                connectorLineWidth: 50,
                format: 'point.y mg/dL',
                enable: true,
                color: reverseColorGrabber(controller),
              )),
          primaryXAxis: CategoryAxis(
              visibleMinimum: 0,
              visibleMaximum: graphData.length.toDouble() / 6),
          zoomPanBehavior: ZoomPanBehavior(
            enablePanning: true,
          ),
          indicators: [],
          // Enable tooltip
          tooltipBehavior: TooltipBehavior(
            color: Colors.transparent,
            canShowMarker: false,
            enable: true,
            builder: (dynamic d, dynamic f, dynamic g, int i, int j) {
              if (i == 1 || i == 4 || i == 3)
                return Container(
                  height: 100,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      Container(
                        padding: EdgeInsets.all(5),
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(25),
                          color: Colors.green,
                        ),
                        child: InkWell(
                          onTap: () {
                            print("Pressed");
                          },
                          child: Container(
                              width: 80,
                              child: ActivityBlockPreview(
                                score: 18,
                                pictureUrl: "https://i.imgur.com/nlRr5vn.jpeg",
                              )),
                        ),
                      ),
                      Expanded(
                        child: DottedLine(
                          direction: Axis.vertical,
                          lineLength: double.infinity,
                          lineThickness: 1.0,
                          dashLength: 4.0,
                          dashColor: reverseColorGrabber(controller),
                          dashRadius: 0.0,
                          dashGapLength: 4.0,
                          dashGapColor: Colors.transparent,
                          dashGapRadius: 0.0,
                        ),
                      ),
                    ],
                  ),
                );
              else
                return null;
            },
          ),
          series: <ChartSeries<_DataPoint, String>>[
            SplineSeries<_DataPoint, String>(
              color: reverseColorGrabber(controller),
              width: 5,
              pointColorMapper: (_DataPoint data, int i) {
                if (i == 0) return Colors.transparent;
              },
              dataSource: <_DataPoint>[...graphData],
              xValueMapper: (_DataPoint point, _) =>
                  DateFormat('H:mm').format(DateTime.parse(point.timestamp)),
              yValueMapper: (_DataPoint point, _) => point.glucose,
              // Enable data label
              dataLabelSettings: DataLabelSettings(
                isVisible: true,
                labelAlignment: ChartDataLabelAlignment.top,
                builder: (dynamic d, dynamic f, dynamic g, int i, int _) {
                  if (i == 1 || i == 4)
                    return Container(
                      height: 20,
                      width: 20,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(30),
                        border: Border.all(width: 3, color: Colors.red),
                        color: Colors.white,
                      ),
                    );
                  if (i == 3) {
                    return Text(
                      "",
                      style: TextStyle(fontSize: 20),
                    );
                  } else
                    return null;
                },
              ),
            )
          ],
        );
      },
    );
  }
}

class _DataPoint {
  _DataPoint(this.timestamp, this.glucose);

  final String timestamp;
  final double glucose;
}


class ActivityBlockPreview extends StatefulWidget {
  final int score;
  final String pictureUrl;
  final bool isSportActivity;
  final bool isSleepActivity;
  final String sportEmoji;

  const ActivityBlockPreview(
      {this.score,
      this.pictureUrl,
      this.isSportActivity = false,
      this.isSleepActivity = false,
      this.sportEmoji});

  @override
  _ActivityBlockPreviewState createState() => _ActivityBlockPreviewState();
}

class _ActivityBlockPreviewState extends State<ActivityBlockPreview> {
  @override
  Widget build(BuildContext context) {
    var controller = ThemeProvider.controllerOf(context);

    return Container(
      decoration: BoxDecoration(
          color: colorGrabber(controller),
          borderRadius: BorderRadius.circular(60)),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          CircleAvatar(
            backgroundColor: colorGrabber(controller),
            backgroundImage: widget.isSportActivity == false &&
                    widget.isSleepActivity == false
                ? NetworkImage(
                    widget.pictureUrl,
                  )
                : null,
            child: widget.isSportActivity == true || widget.isSleepActivity
                ? Text(widget.sportEmoji)
                : Container(),
          ),
          if (!widget.isSportActivity)
            Padding(
              padding: const EdgeInsets.only(left: 5, right: 10),
              child: Text(
                widget.score.toString(),
                style: TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                ),
              ),
            )
        ],
      ),
    );
  }
}
4

1 回答 1

1

目前,当数据点上方没有空间来呈现其自定义工具提示小部件时,它会向下移动并被呈现。这是默认行为。但是,如果您希望始终在相应数据点上方呈现自定义工具提示小部件,则可以将图表轴的rangePadding属性设置为ChartRangePadding.additional以便在轴的开始和结束处添加额外的范围填充。此外,如果提供rangePadding值作为附加没有解决问题,那么您需要根据可用的数据点设置图表的特定范围,方法是使用图表轴的最大属性,以便工具提示小部件构建器有足够的空间在相应数据上方进行渲染观点。请参阅下面的代码片段以供进一步参考。

代码片段:

将 rangePadding 属性值设置为附加值:

SfCartesianChart(
          primaryYAxis: NumericAxis(
              rangePadding: ChartRangePadding.additional
          ),
          // Your configurations
)

为图表的 y 轴设置特定范围:

SfCartesianChart(
          primaryYAxis: NumericAxis(
              minimum: 0,
              maximum: 300
          ),
          // Your configurations
)

有关rangePadding属性和自定义图表范围的进一步参考,请查看下面的用户指南。

于 2020-11-25T09:51:09.677 回答