在 Syncfusion Graph Flutter 中自定义工具提示宽度或位置

问题描述 投票:0回答:1

我们已将 Syncfusion Charts 集成到我们的 Flutter 应用程序中。当用户单击图表上的绘制点时,会显示工具提示。然而,这些工具提示中的文本通常太长,导致其被切断或难以阅读。

有没有办法自定义工具提示宽度或调整其位置来有效解决这个问题?

flutter charts tooltip syncfusion syncfusion-chart
1个回答
0
投票

我已经分析了您的查询,并且可以在使用 TooltipBehavior 中的 format 属性为工具提示提供较长文本时重现该问题,这是因为工具提示未在绘图区域内呈现。为了解决这个问题,我建议您在 TooltipBehavior 中使用 builder 属性。通过使用它,您可以在绘图区域内显示工具提示内容。我分享了一个用户指南文档链接供您参考。

UG链接:https://help.syncfusion.com/flutter/cartesian-charts/tooltip#tooltip-template

此外,我在提供更长的 x 值时遇到了类似的问题。为了解决此问题并确保默认的工具提示 UI,我设计了一个类似于默认工具提示的构建器工具提示小部件。我为该系列创建了一个自定义渲染器,以限制工具提示宽度并获取工具提示标记颜色。下面,我分享了一个代码片段和输出截图供您参考。

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';

void main() {
  runApp(const WorkaroundSample());
}

class WorkaroundSample extends StatefulWidget {
  const WorkaroundSample({super.key});

  @override
  State<WorkaroundSample> createState() => _WorkaroundSampleState();
}

class _WorkaroundSampleState extends State<WorkaroundSample> {
  late List<ChartData> _chartData;
  late Size _seriesSize;
  late Color _seriesColor;

  Size measureText(String textValue, TextStyle textStyle, [int? angle]) {
    final TextPainter textPainter = TextPainter(
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
      text: TextSpan(text: textValue, style: textStyle),
    );
    textPainter.layout();
    return Size(textPainter.width, textPainter.height);
  }

  @override
  void initState() {
    _chartData = <ChartData>[
      ChartData(
          'themeData.textTheme.bodySmall!.copyWiththemeData.textTheme.bodySmall!.copyWith',
          10),
      ChartData(
          'themeData.textTheme.boySmall!.copyWiththemeData.textTheme.bodySmall!.copyWith',
          22),
      ChartData(
          'themeData.textTheme.bodySmall!.copyWiththemeData.textTheme.bodySmall!.copWith',
          13),
      ChartData(
          'themeData.txtTheme.bodySmall!.copyWiththemeData.textTheme.bodySmall!.copyith',
          34),
      ChartData(
          'themeData.textTheme.bodySmall!.copyWiththemeDa.textTheme.bodySmall!.copyWith',
          12),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SfCartesianChart(
          primaryXAxis: const CategoryAxis(
            labelIntersectAction: AxisLabelIntersectAction.trim,
          ),
          tooltipBehavior: TooltipBehavior(
            enable: true,
            builder: (dynamic data, ChartPoint point, ChartSeries series,
                int pointIndex, int seriesIndex) {
              final ThemeData themeData = Theme.of(context);
              final TextStyle textStyle =
                  themeData.textTheme.bodySmall!.copyWith(
                color: themeData.colorScheme.onInverseSurface,
              );
              final TextStyle headerStyle =
                  textStyle.copyWith(fontWeight: FontWeight.bold);
              const String header =
                  "Robeco Sustainable Global Equities focus Fundamental (Global Stars)";
              final Size headerSize = measureText(header, headerStyle);
              final String text = '${point.x} : ${point.y}';
              final Size textSize = measureText(text, textStyle);
              const EdgeInsets tooltipInnerPadding = EdgeInsets.all(6);
              const EdgeInsets tooltipMarkerPadding = EdgeInsets.all(2.0);
              const double tooltipMarkerSize = 10.0;
              const EdgeInsetsDirectional tooltipItemSpacing =
                  EdgeInsetsDirectional.only(end: 3.0);

              double headerAlignedSize = max(headerSize.width, textSize.width);
              double dividerWidth = headerAlignedSize;
              if (headerAlignedSize >= _seriesSize.width) {
                headerAlignedSize =
                    _seriesSize.width - tooltipInnerPadding.horizontal;
                dividerWidth = headerAlignedSize;
              } else {
                dividerWidth +=
                    tooltipMarkerSize + tooltipMarkerPadding.horizontal;
              }

              dividerWidth = min(dividerWidth, _seriesSize.width);
              final double xTextSize = dividerWidth -
                  tooltipMarkerSize -
                  tooltipItemSpacing.horizontal -
                  tooltipMarkerPadding.horizontal -
                  tooltipInnerPadding.horizontal -
                  measureText(' : ${point.y}', textStyle).width;

              final bool hasHeader = header.isNotEmpty;
              Widget tooltip = Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  if (hasHeader)
                    SizedBox(
                      width: headerAlignedSize,
                      child: Center(child: Text(header, style: headerStyle)),
                    ),
                  if (hasHeader)
                    SizedBox(
                      width: dividerWidth,
                      child: Divider(
                        height: 10.0,
                        thickness: 0.5,
                        color: themeData.colorScheme.onInverseSurface,
                      ),
                    ),
                  if (text.isNotEmpty)
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Padding(
                          padding: tooltipItemSpacing,
                          child: Container(
                            padding: tooltipMarkerPadding,
                            width: tooltipMarkerSize,
                            height: tooltipMarkerSize,
                            decoration: BoxDecoration(
                              shape: BoxShape.circle,
                              color: _seriesColor,
                              border: Border.all(
                                color: Colors.white,
                                width: 1.0,
                              ),
                            ),
                          ),
                        ),
                        SizedBox(
                          width: xTextSize,
                          child: RichText(
                            overflow: TextOverflow.ellipsis,
                            text:
                                TextSpan(text: '${point.x}', style: textStyle),
                          ),
                        ),
                        Text(' : ${point.y}', style: textStyle),
                      ],
                    ),
                ],
              );

              return Padding(
                padding: tooltipInnerPadding,
                child: tooltip,
              );
            },
          ),
          series: [
            BubbleSeries<ChartData, String>(
              xValueMapper: (ChartData data, int index) => data.x,
              yValueMapper: (ChartData data, int index) => data.y,
              dataSource: _chartData,
              onCreateRenderer: (series) {
                return _BubbleSeriesRenderer(this);
              },
            ),
          ],
        ),
      ),
    );
  }
}

class _BubbleSeriesRenderer extends BubbleSeriesRenderer<ChartData, String> {
  _BubbleSeriesRenderer(this._state);

  final _WorkaroundSampleState _state;

  @override
  void customizeSegment(ChartSegment segment) {
    super.customizeSegment(segment);
    _state._seriesColor = segment.fillPaint.color;
  }

  @override
  void performLayout() {
    super.performLayout();
    _state._seriesSize = size;
  }
}

class ChartData {
  ChartData(
    this.x,
    this.y,
  );

  final String x;
  final num y;
}

输出截图:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.