diff --git a/lib/src/chart/bar_chart/bar_chart_data.dart b/lib/src/chart/bar_chart/bar_chart_data.dart index aefafb2dc..8980f9bfd 100644 --- a/lib/src/chart/bar_chart/bar_chart_data.dart +++ b/lib/src/chart/bar_chart/bar_chart_data.dart @@ -47,6 +47,7 @@ class BarChartData extends AxisChartData with EquatableMixin { RangeAnnotations? rangeAnnotations, super.backgroundColor, ExtraLinesData? extraLinesData, + super.rotationQuarterTurns, }) : barGroups = barGroups ?? const [], groupsSpace = groupsSpace ?? 16, alignment = alignment ?? BarChartAlignment.spaceEvenly, @@ -94,6 +95,7 @@ class BarChartData extends AxisChartData with EquatableMixin { double? baselineY, Color? backgroundColor, ExtraLinesData? extraLinesData, + int? rotationQuarterTurns, }) => BarChartData( barGroups: barGroups ?? this.barGroups, @@ -109,6 +111,7 @@ class BarChartData extends AxisChartData with EquatableMixin { baselineY: baselineY ?? this.baselineY, backgroundColor: backgroundColor ?? this.backgroundColor, extraLinesData: extraLinesData ?? this.extraLinesData, + rotationQuarterTurns: rotationQuarterTurns ?? this.rotationQuarterTurns, ); /// Lerps a [BaseChartData] based on [t] value, check [Tween.lerp]. @@ -131,6 +134,7 @@ class BarChartData extends AxisChartData with EquatableMixin { backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), extraLinesData: ExtraLinesData.lerp(a.extraLinesData, b.extraLinesData, t), + rotationQuarterTurns: b.rotationQuarterTurns, ); } else { throw Exception('Illegal State'); @@ -153,6 +157,7 @@ class BarChartData extends AxisChartData with EquatableMixin { rangeAnnotations, backgroundColor, extraLinesData, + rotationQuarterTurns, ]; } diff --git a/lib/src/chart/base/axis_chart/axis_chart_data.dart b/lib/src/chart/base/axis_chart/axis_chart_data.dart index d1fbff802..4994dab01 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_data.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_data.dart @@ -29,6 +29,7 @@ abstract class AxisChartData extends BaseChartData with EquatableMixin { super.borderData, required super.touchData, ExtraLinesData? extraLinesData, + this.rotationQuarterTurns = 0, }) : gridData = gridData ?? const FlGridData(), rangeAnnotations = rangeAnnotations ?? const RangeAnnotations(), baselineX = baselineX ?? 0, @@ -62,6 +63,9 @@ abstract class AxisChartData extends BaseChartData with EquatableMixin { /// Extra horizontal or vertical lines to draw on the chart. final ExtraLinesData extraLinesData; + /// Rotates the chart by 90 degrees clockwise in each turn + final int rotationQuarterTurns; + /// Used for equality check, see [EquatableMixin]. @override List get props => [ @@ -79,11 +83,22 @@ abstract class AxisChartData extends BaseChartData with EquatableMixin { borderData, touchData, extraLinesData, + rotationQuarterTurns, ]; } /// Represents a side of the chart -enum AxisSide { left, top, right, bottom } +enum AxisSide { + left, + top, + right, + bottom; + + AxisSide rotateByQuarterTurns(int quarterTurns) { + const values = AxisSide.values; + return values[(values.indexOf(this) + quarterTurns) % values.length]; + } +} /// Contains meta information about the drawing title. class TitleMeta { @@ -96,6 +111,7 @@ class TitleMeta { required this.sideTitles, required this.formattedValue, required this.axisSide, + required this.rotationQuarterTurns, }); /// min axis value @@ -122,6 +138,11 @@ class TitleMeta { /// Determines the axis side of titles (left, top, right, bottom) final AxisSide axisSide; + + /// Chart is rotated by 90 degrees clockwise in each turn + /// + /// default is zero, which means chart is normal and upward + final int rotationQuarterTurns; } /// It gives you the axis value and gets a String value based on it. diff --git a/lib/src/chart/base/axis_chart/axis_chart_scaffold_widget.dart b/lib/src/chart/base/axis_chart/axis_chart_scaffold_widget.dart index 44492a483..7774dd205 100644 --- a/lib/src/chart/base/axis_chart/axis_chart_scaffold_widget.dart +++ b/lib/src/chart/base/axis_chart/axis_chart_scaffold_widget.dart @@ -316,7 +316,12 @@ class _AxisChartScaffoldWidgetState extends State { Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { - return Stack(children: stackWidgets(constraints)); + return RotatedBox( + quarterTurns: widget.data.rotationQuarterTurns, + child: Stack( + children: stackWidgets(constraints), + ), + ); }, ); } diff --git a/lib/src/chart/base/axis_chart/side_titles/side_titles_widget.dart b/lib/src/chart/base/axis_chart/side_titles/side_titles_widget.dart index 2a134e9bd..d0f67603f 100644 --- a/lib/src/chart/base/axis_chart/side_titles/side_titles_widget.dart +++ b/lib/src/chart/base/axis_chart/side_titles/side_titles_widget.dart @@ -5,6 +5,7 @@ import 'package:fl_chart/src/extensions/bar_chart_data_extension.dart'; import 'package:fl_chart/src/extensions/edge_insets_extension.dart'; import 'package:fl_chart/src/extensions/fl_border_data_extension.dart'; import 'package:fl_chart/src/extensions/fl_titles_data_extension.dart'; +import 'package:fl_chart/src/extensions/size_extension.dart'; import 'package:fl_chart/src/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -105,13 +106,18 @@ class _SideTitlesWidgetState extends State { } Size get viewSize { + late Size size; final chartVirtualRect = widget.chartVirtualRect; if (chartVirtualRect == null) { - return widget.parentSize; + size = widget.parentSize; + } else { + size = chartVirtualRect.size + + Offset(thisSidePaddingTotal, thisSidePaddingTotal); } - return chartVirtualRect.size + - Offset(thisSidePaddingTotal, thisSidePaddingTotal); + return size.rotateByQuarterTurns( + widget.axisChartData.rotationQuarterTurns, + ); } double get axisOffset { @@ -195,6 +201,7 @@ class _SideTitlesWidgetState extends State { axisSide: side, parentAxisSize: axisViewSize, axisPosition: metaData.axisPixelLocation, + rotationQuarterTurns: widget.axisChartData.rotationQuarterTurns, ), ), ); @@ -209,7 +216,7 @@ class _SideTitlesWidgetState extends State { final chartSize = Size( widget.parentSize.width - thisSidePaddingTotal, widget.parentSize.height - thisSidePaddingTotal, - ); + ).rotateByQuarterTurns(widget.axisChartData.rotationQuarterTurns); // Add 1 pixel to the chart's edges to avoid clipping the last title. final chartRect = (Offset.zero & chartSize).inflate(1); diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index 75417fda1..b32df77d3 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -58,6 +58,7 @@ class LineChartData extends AxisChartData with EquatableMixin { super.baselineY, super.clipData = const FlClipData.none(), super.backgroundColor, + super.rotationQuarterTurns, }) : super( touchData: lineTouchData, minX: minX ?? double.nan, @@ -109,6 +110,7 @@ class LineChartData extends AxisChartData with EquatableMixin { lerpBetweenBarsDataList(a.betweenBarsData, b.betweenBarsData, t)!, lineTouchData: b.lineTouchData, showingTooltipIndicators: b.showingTooltipIndicators, + rotationQuarterTurns: b.rotationQuarterTurns, ); } else { throw Exception('Illegal State'); @@ -135,6 +137,7 @@ class LineChartData extends AxisChartData with EquatableMixin { double? baselineY, FlClipData? clipData, Color? backgroundColor, + int? rotationQuarterTurns, }) => LineChartData( lineBarsData: lineBarsData ?? this.lineBarsData, @@ -155,6 +158,7 @@ class LineChartData extends AxisChartData with EquatableMixin { baselineY: baselineY ?? this.baselineY, clipData: clipData ?? this.clipData, backgroundColor: backgroundColor ?? this.backgroundColor, + rotationQuarterTurns: rotationQuarterTurns ?? this.rotationQuarterTurns, ); /// Used for equality check, see [EquatableMixin]. @@ -177,6 +181,7 @@ class LineChartData extends AxisChartData with EquatableMixin { baselineY, clipData, backgroundColor, + rotationQuarterTurns, ]; } diff --git a/lib/src/chart/scatter_chart/scatter_chart_data.dart b/lib/src/chart/scatter_chart/scatter_chart_data.dart index 63f035bfd..8659379cb 100644 --- a/lib/src/chart/scatter_chart/scatter_chart_data.dart +++ b/lib/src/chart/scatter_chart/scatter_chart_data.dart @@ -49,6 +49,7 @@ class ScatterChartData extends AxisChartData with EquatableMixin { FlClipData? clipData, super.backgroundColor, ScatterLabelSettings? scatterLabelSettings, + super.rotationQuarterTurns, }) : scatterSpots = scatterSpots ?? const [], scatterTouchData = scatterTouchData ?? ScatterTouchData(), showingTooltipIndicators = showingTooltipIndicators ?? const [], @@ -116,6 +117,7 @@ class ScatterChartData extends AxisChartData with EquatableMixin { b.scatterLabelSettings, t, ), + rotationQuarterTurns: b.rotationQuarterTurns, ); } else { throw Exception('Illegal State'); @@ -140,6 +142,7 @@ class ScatterChartData extends AxisChartData with EquatableMixin { FlClipData? clipData, Color? backgroundColor, ScatterLabelSettings? scatterLabelSettings, + int? rotationQuarterTurns, }) => ScatterChartData( scatterSpots: scatterSpots ?? this.scatterSpots, @@ -158,6 +161,7 @@ class ScatterChartData extends AxisChartData with EquatableMixin { clipData: clipData ?? this.clipData, backgroundColor: backgroundColor ?? this.backgroundColor, scatterLabelSettings: scatterLabelSettings ?? this.scatterLabelSettings, + rotationQuarterTurns: rotationQuarterTurns ?? this.rotationQuarterTurns, ); /// Used for equality check, see [EquatableMixin]. @@ -181,6 +185,7 @@ class ScatterChartData extends AxisChartData with EquatableMixin { backgroundColor, borderData, touchData, + rotationQuarterTurns, ]; }