Skip to content

Commit

Permalink
Allow to show titles when axis diff is zero, #842, #879
Browse files Browse the repository at this point in the history
  • Loading branch information
imaNNeo committed Feb 12, 2022
1 parent d316446 commit ad76163
Show file tree
Hide file tree
Showing 11 changed files with 613 additions and 512 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## newVersion
* **BUGFIX** Fix PieChart changing sections issue (we have disabled semantics for pieChart badgeWidgets), #861.
* **BUGFIX** Fix LineChart width smaller width or height lower than 40, #869, #857.
* **BUGFIX** Allow to show title when axis diff is zero.

## 0.41.0
* **BUGFIX** Fix getNearestTouchedSpot. Previously it returned the first occurrence of a spot within the threshold, and not the nearest, #641, #645.
Expand Down
153 changes: 71 additions & 82 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,117 +1,106 @@
import 'package:example/radar_chart/radar_chart_page.dart';
import 'package:example/scatter_chart/scatter_chart_page.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

import 'bar_chart/bar_chart_page.dart';
import 'bar_chart/bar_chart_page2.dart';
import 'bar_chart/bar_chart_page3.dart';
import 'line_chart/line_chart_page.dart';
import 'line_chart/line_chart_page2.dart';
import 'line_chart/line_chart_page3.dart';
import 'line_chart/line_chart_page4.dart';
import 'pie_chart/pie_chart_page.dart';
import 'utils/platform_info.dart';
import 'scatter_chart/scatter_chart_page.dart';

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

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
return const MaterialApp(
title: 'FlChart Demo',
showPerformanceOverlay: false,
theme: ThemeData(
primaryColor: const Color(0xff262545),
primaryColorDark: const Color(0xff201f39),
brightness: Brightness.dark,
),
home: const MyHomePage(title: 'fl_chart'),
home: MyHomePage(),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
const MyHomePage({Key? key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
int _currentPage = 0;
final List<ShowingTooltipIndicators> _showingTouchedTooltips = [];

final _controller = PageController(initialPage: 0);
final _duration = const Duration(milliseconds: 300);
final _curve = Curves.easeInOutCubic;
final _pages = const [
LineChartPage(),
BarChartPage(),
BarChartPage2(),
PieChartPage(),
LineChartPage2(),
LineChartPage3(),
LineChartPage4(),
BarChartPage3(),
ScatterChartPage(),
RadarChartPage(),
];

bool get isDesktopOrWeb => PlatformInfo().isDesktopOrWeb();

@override
void initState() {
super.initState();
_controller.addListener(() {
setState(() {
_currentPage = _controller.page!.round();
});
});
}
final Map<int, List<int>> _showingTouchedIndicators = {};

@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: PageView(
physics: isDesktopOrWeb
? const NeverScrollableScrollPhysics()
: const AlwaysScrollableScrollPhysics(),
controller: _controller,
children: _pages,
),
),
bottomNavigationBar: isDesktopOrWeb
? Container(
padding: const EdgeInsets.all(16),
color: Colors.transparent,
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Visibility(
visible: _currentPage != 0,
child: FloatingActionButton(
onPressed: () => _controller.previousPage(
duration: _duration, curve: _curve),
child: const Icon(Icons.chevron_left_rounded),
),
child: Center(
child: SizedBox(
width: 200,
height: 100,
child: LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
colors: [Colors.green],
spots: const [
FlSpot(0, 0),
FlSpot(1, 1),
FlSpot(2, 1),
],
showingIndicators: _showingTouchedIndicators[0] ?? [],
),
const Spacer(),
Visibility(
visible: _currentPage != _pages.length - 1,
child: FloatingActionButton(
onPressed: () => _controller.nextPage(
duration: _duration, curve: _curve),
child: const Icon(Icons.chevron_right_rounded),
),
LineChartBarData(
colors: [Colors.red],
spots: const [
FlSpot(0, 3),
FlSpot(1, 2),
FlSpot(2, 0),
],
showingIndicators: _showingTouchedIndicators[1] ?? [],
),
],
showingTooltipIndicators: _showingTouchedTooltips,
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback: (event, touchResponse) {
if (!event.isInterestedForInteractions ||
touchResponse?.lineBarSpots == null ||
touchResponse!.lineBarSpots!.isEmpty) {
setState(() {
_showingTouchedTooltips.clear();
_showingTouchedIndicators.clear();
});
return;
}

const showOnlyOnLineIndex = 0;
setState(() {
final sortedLineSpots = List.of(
touchResponse.lineBarSpots!.where((element) =>
element.barIndex == showOnlyOnLineIndex));
sortedLineSpots
.sort((spot1, spot2) => spot2.y.compareTo(spot1.y));

_showingTouchedIndicators.clear();

final touchedBarSpot =
touchResponse.lineBarSpots![showOnlyOnLineIndex];
final barPos = touchedBarSpot.barIndex;
_showingTouchedIndicators[barPos] = [
touchedBarSpot.spotIndex
];

_showingTouchedTooltips.clear();
_showingTouchedTooltips
.add(ShowingTooltipIndicators(sortedLineSpots));
});
},
),
),
)
: null,
),
),
),
),
);
}
}
168 changes: 82 additions & 86 deletions lib/src/chart/bar_chart/bar_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -386,49 +386,47 @@ class BarChartPainter extends AxisChartPainter<BarChartData> {
final drawSize = getChartUsableDrawSize(viewSize, holder);

// Left Titles
if (!data.isVerticalMinMaxIsZero) {
final leftTitles = targetData.titlesData.leftTitles;
final leftInterval = leftTitles.interval ??
Utils().getEfficientInterval(viewSize.height, data.verticalDiff);
if (leftTitles.showTitles) {
var verticalSeek = Utils()
.getBestInitialIntervalValue(data.minY, data.maxY, leftInterval);
while (verticalSeek <= data.maxY) {
if (leftTitles.checkToShowTitle(
data.minY, data.maxY, leftTitles, leftInterval, verticalSeek)) {
var x = 0 + getLeftOffsetDrawSize(holder);
var y = getPixelY(verticalSeek, drawSize, holder);

final text = leftTitles.getTitles(verticalSeek);

final span = TextSpan(
style: Utils().getThemeAwareTextStyle(
context, leftTitles.getTextStyles(context, verticalSeek)),
text: text,
);
final tp = TextPainter(
text: span,
textAlign: leftTitles.textAlign,
textDirection: leftTitles.textDirection,
textScaleFactor: holder.textScale,
);
tp.layout(
maxWidth: leftTitles.reservedSize,
minWidth: leftTitles.reservedSize,
);
x -= tp.width + leftTitles.margin;
y -= tp.height / 2;
x += Utils()
.calculateRotationOffset(tp.size, leftTitles.rotateAngle)
.dx;
canvasWrapper.drawText(tp, Offset(x, y), leftTitles.rotateAngle);
}
if (data.maxY - verticalSeek < leftInterval &&
data.maxY != verticalSeek) {
verticalSeek = data.maxY;
} else {
verticalSeek += leftInterval;
}
final leftTitles = targetData.titlesData.leftTitles;
final leftInterval = leftTitles.interval ??
Utils().getEfficientInterval(viewSize.height, data.verticalDiff);
if (leftTitles.showTitles) {
var verticalSeek = Utils()
.getBestInitialIntervalValue(data.minY, data.maxY, leftInterval);
while (verticalSeek <= data.maxY) {
if (leftTitles.checkToShowTitle(
data.minY, data.maxY, leftTitles, leftInterval, verticalSeek)) {
var x = 0 + getLeftOffsetDrawSize(holder);
var y = getPixelY(verticalSeek, drawSize, holder);

final text = leftTitles.getTitles(verticalSeek);

final span = TextSpan(
style: Utils().getThemeAwareTextStyle(
context, leftTitles.getTextStyles(context, verticalSeek)),
text: text,
);
final tp = TextPainter(
text: span,
textAlign: leftTitles.textAlign,
textDirection: leftTitles.textDirection,
textScaleFactor: holder.textScale,
);
tp.layout(
maxWidth: leftTitles.reservedSize,
minWidth: leftTitles.reservedSize,
);
x -= tp.width + leftTitles.margin;
y -= tp.height / 2;
x += Utils()
.calculateRotationOffset(tp.size, leftTitles.rotateAngle)
.dx;
canvasWrapper.drawText(tp, Offset(x, y), leftTitles.rotateAngle);
}
if (data.maxY - verticalSeek < leftInterval &&
data.maxY != verticalSeek) {
verticalSeek = data.maxY;
} else {
verticalSeek += leftInterval;
}
}
}
Expand Down Expand Up @@ -463,49 +461,47 @@ class BarChartPainter extends AxisChartPainter<BarChartData> {
}

// Right Titles
if (!data.isVerticalMinMaxIsZero) {
final rightTitles = targetData.titlesData.rightTitles;
final rightInterval = rightTitles.interval ??
Utils().getEfficientInterval(viewSize.height, data.verticalDiff);
if (rightTitles.showTitles) {
var verticalSeek = Utils()
.getBestInitialIntervalValue(data.minY, data.maxY, rightInterval);
while (verticalSeek <= data.maxY) {
if (rightTitles.checkToShowTitle(
data.minY, data.maxY, rightTitles, rightInterval, verticalSeek)) {
var x = drawSize.width + getLeftOffsetDrawSize(holder);
var y = getPixelY(verticalSeek, drawSize, holder);

final text = rightTitles.getTitles(verticalSeek);

final span = TextSpan(
style: Utils().getThemeAwareTextStyle(
context, rightTitles.getTextStyles(context, verticalSeek)),
text: text,
);
final tp = TextPainter(
text: span,
textAlign: rightTitles.textAlign,
textDirection: rightTitles.textDirection,
textScaleFactor: holder.textScale,
);
tp.layout(
maxWidth: rightTitles.reservedSize,
minWidth: rightTitles.reservedSize,
);
x += rightTitles.margin;
y -= tp.height / 2;
x -= Utils()
.calculateRotationOffset(tp.size, rightTitles.rotateAngle)
.dx;
canvasWrapper.drawText(tp, Offset(x, y), rightTitles.rotateAngle);
}
if (data.maxY - verticalSeek < rightInterval &&
data.maxY != verticalSeek) {
verticalSeek = data.maxY;
} else {
verticalSeek += rightInterval;
}
final rightTitles = targetData.titlesData.rightTitles;
final rightInterval = rightTitles.interval ??
Utils().getEfficientInterval(viewSize.height, data.verticalDiff);
if (rightTitles.showTitles) {
var verticalSeek = Utils()
.getBestInitialIntervalValue(data.minY, data.maxY, rightInterval);
while (verticalSeek <= data.maxY) {
if (rightTitles.checkToShowTitle(
data.minY, data.maxY, rightTitles, rightInterval, verticalSeek)) {
var x = drawSize.width + getLeftOffsetDrawSize(holder);
var y = getPixelY(verticalSeek, drawSize, holder);

final text = rightTitles.getTitles(verticalSeek);

final span = TextSpan(
style: Utils().getThemeAwareTextStyle(
context, rightTitles.getTextStyles(context, verticalSeek)),
text: text,
);
final tp = TextPainter(
text: span,
textAlign: rightTitles.textAlign,
textDirection: rightTitles.textDirection,
textScaleFactor: holder.textScale,
);
tp.layout(
maxWidth: rightTitles.reservedSize,
minWidth: rightTitles.reservedSize,
);
x += rightTitles.margin;
y -= tp.height / 2;
x -= Utils()
.calculateRotationOffset(tp.size, rightTitles.rotateAngle)
.dx;
canvasWrapper.drawText(tp, Offset(x, y), rightTitles.rotateAngle);
}
if (data.maxY - verticalSeek < rightInterval &&
data.maxY != verticalSeek) {
verticalSeek = data.maxY;
} else {
verticalSeek += rightInterval;
}
}
}
Expand Down
6 changes: 0 additions & 6 deletions lib/src/chart/base/axis_chart/axis_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ abstract class AxisChartData extends BaseChartData with EquatableMixin {
/// Difference of [maxX] and [minX]
double get horizontalDiff => maxX - minX;

/// Returns true if [minX] and [maxX] both are zero
bool get isHorizontalMinMaxIsZero => minX == 0 && maxX == 0;

/// Returns true if [minY] and [maxY] both are zero
bool get isVerticalMinMaxIsZero => minY == 0 && maxY == 0;

AxisChartData({
FlGridData? gridData,
required FlAxisTitleData axisTitleData,
Expand Down
Loading

0 comments on commit ad76163

Please sign in to comment.