imaNNeo / fl_chart

FL Chart is a highly customizable Flutter chart library that supports Line Chart, Bar Chart, Pie Chart, Scatter Chart, and Radar Chart.
https://flchart.dev
MIT License
6.87k stars 1.78k forks source link

dublicated x-axis titles #1678

Closed Tobbyte closed 4 months ago

Tobbyte commented 5 months ago

first: thanks for your awesome work! Much appreciated!

Came across a strange behavior when showing close minX and maxX values: at some point the calculated interval goes < 1 and more titles than datapoints get shown.

for

LineChartData(
   minX: 0,
   maxX: 7,

all good - one title per data point (meta.appliedInterval is 1) :

Bildschirmfoto 2024-06-05 um 13 28 06

but

LineChartData(
   minX: 0,
   maxX: 6,

more titles than datapoints (meta.appliedInterval is 0.5)?

Bildschirmfoto 2024-06-05 um 13 36 00

Versions Flutter: 3.19.6 fl_chart: ^0.68.0

min example:

import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';

main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double intervalDump = 0;

  double sliderVal = 4;

  List<FlSpot> spots = [
    const FlSpot(0, 1),
    const FlSpot(1, 2),
    const FlSpot(2, -1),
    const FlSpot(3, -2),
    const FlSpot(4, 1),
    const FlSpot(5, -1),
    const FlSpot(6, 2),
    const FlSpot(7, 1),
    const FlSpot(8, 1),
    const FlSpot(9, 2),
    const FlSpot(10, -1),
    const FlSpot(11, -2),
    const FlSpot(12, 1),
    const FlSpot(13, -1),
    const FlSpot(14, 2),
    const FlSpot(15, 1),
  ];

  @override
  Widget build(context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Center(child: Text("interval:\n $intervalDump")),
            AspectRatio(
              aspectRatio: 1 / 1,
              child: LineChart(
                LineChartData(
                  lineTouchData: const LineTouchData(enabled: false), // btw: needed for showingIndicators?!
                  clipData: const FlClipData.all(),
                  minX: 0,
                  maxX: sliderVal,
                  minY: -3,
                  maxY: 3,
                  titlesData: FlTitlesData(
                    bottomTitles: AxisTitles(
                        sideTitles: SideTitles(
                      showTitles: true,
                      getTitlesWidget: ((value, meta) {
                        intervalDump = meta.appliedInterval;
                        return SideTitleWidget(
                          axisSide: meta.axisSide,
                          space: 0,
                          angle: -12,
                          child: Text(value.toString()),
                        );
                      }),
                    )),
                  ),
                  lineBarsData: [
                    LineChartBarData(
                      showingIndicators: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
                      dotData: FlDotData(
                        getDotPainter: (dot, a, data, i) => FlDotCirclePainter(
                          radius: 1,
                        ),
                        show: true,
                      ),
                      spots: spots,
                    ),
                  ],
                ),
              ),
            ),
            Slider(
                value: sliderVal,
                min: 1,
                max: spots.length - 1,
                onChanged: (newVal) {
                  setState(() {
                    sliderVal = newVal;
                  });
                })
          ],
        ),
      ),
    );
  }
}
Bildschirmfoto 2024-06-05 um 17 28 05
Tobbyte commented 4 months ago

still not sure why this problem exists in the first place (maybe the interval < 1 exists for auto scaling? 🤷‍♂️) Anyway, the solution is simple: getTitlesWidget

    if (interval < 1) {
      return const SizedBox.shrink();
    }