Skip to content
Snippets Groups Projects
heatmap.dart 3.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • import 'package:fl_chart/fl_chart.dart';
    import 'package:flutter/material.dart';
    
    import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
    
    import 'package:scrobbles/config/app_colors.dart';
    
    import 'package:scrobbles/models/data/heatmap.dart';
    
    import 'package:scrobbles/ui/widgets/abstracts/custom_chart.dart';
    
    class ChartHeatmap extends CustomChart {
    
      const ChartHeatmap({super.key, required this.chartData});
    
    
      final HeatmapData chartData;
    
    
      double get chartHeight => 150.0;
    
      double get titleFontSize => 9;
    
    
      final Color baseColor = AppColors.contentColorPink;
      final double scale = 8.0;
      final double darkenAmount = 50;
    
      @override
      Widget build(BuildContext context) {
    
        if (chartData.data.keys.isEmpty) {
    
          return SizedBox(
    
          );
        }
    
        return AspectRatio(
          aspectRatio: 3,
          child: ScatterChart(
            ScatterChartData(
              scatterSpots: getSpots(),
              minX: 0,
              maxX: 24,
              minY: 0,
              maxY: 7,
              borderData: FlBorderData(show: false),
    
              gridData: const FlGridData(show: false),
    
              titlesData: getTitlesData(),
              scatterTouchData: ScatterTouchData(enabled: false),
            ),
          ),
        );
      }
    
      Color getColorFromNormalizedValue(double value) {
    
        Color colorFrom = Colors.white;
        Color colorTo = Colors.pink;
    
        return Color.lerp(colorFrom, colorTo, value) ?? colorFrom;
    
      }
    
      int getMaxCount() {
        int maxValue = 0;
    
    
        chartData.data.forEach((day, hours) {
    
          hours.forEach((hour, count) {
            if (count > maxValue) {
              maxValue = count;
            }
          });
        });
    
        return maxValue;
      }
    
      List<ScatterSpot> getSpots() {
        List<ScatterSpot> spots = [];
    
        final int maxCount = getMaxCount();
    
    
        chartData.data.forEach((day, hours) {
    
          hours.forEach((hour, count) {
            double normalizedValue = count / maxCount;
    
            spots.add(ScatterSpot(
              hour.toDouble(),
    
              8 - day.toDouble(),
    
              dotPainter: FlDotSquarePainter(
                color: getColorFromNormalizedValue(normalizedValue),
                size: 12,
                strokeWidth: 0,
              ),
    
            ));
          });
        });
    
        return spots;
      }
    
    
      FlTitlesData getTitlesData() {
    
        const AxisTitles none = AxisTitles(
    
          sideTitles: SideTitles(showTitles: false),
        );
    
        final AxisTitles verticalTitles = AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            reservedSize: 40,
    
            getTitlesWidget: getVerticalTitlesWidgetWithValue,
    
            interval: 1,
          ),
        );
    
        final AxisTitles horizontalTitles = AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            reservedSize: 20,
    
            getTitlesWidget: getHorizontalTitlesWidgetWithHour,
    
            interval: 4,
          ),
        );
    
        return FlTitlesData(
          show: true,
          bottomTitles: horizontalTitles,
          leftTitles: verticalTitles,
          topTitles: none,
          rightTitles: none,
        );
      }
    
    
      Widget getVerticalTitlesWidgetWithValue(double value, TitleMeta meta) {
    
        final String dayShortName = getDayShortName(8 - value.toInt());
    
    
        return SideTitleWidget(
    
          space: 10,
          child: Text(
            tr(dayShortName),
            style: TextStyle(