Skip to content

Commit

Permalink
Merge pull request #115 from juumixx/axis-titles
Browse files Browse the repository at this point in the history
added axis titles
  • Loading branch information
imaNNeo authored Dec 30, 2019
2 parents 09138aa + 4012978 commit 1cf6723
Show file tree
Hide file tree
Showing 17 changed files with 284 additions and 4 deletions.
15 changes: 13 additions & 2 deletions example/lib/line_chart/samples/line_chart_sample4.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class LineChartSample4 extends StatelessWidget {
@override
Widget build(BuildContext context) {
const cutOffYValue = 5.0;
const dateTextStyle = TextStyle(
fontSize: 10, color: Colors.purple, fontWeight: FontWeight.bold);

return SizedBox(
width: 300,
Expand Down Expand Up @@ -54,8 +56,8 @@ class LineChartSample4 extends StatelessWidget {
titlesData: FlTitlesData(
bottomTitles: SideTitles(
showTitles: true,
textStyle:
TextStyle(fontSize: 10, color: Colors.purple, fontWeight: FontWeight.bold),
reservedSize: 14,
textStyle: dateTextStyle,
getTitles: (value) {
switch (value.toInt()) {
case 0:
Expand Down Expand Up @@ -93,6 +95,15 @@ class LineChartSample4 extends StatelessWidget {
},
),
),
axisTitleData: const FlAxisTitleData(
leftTitle:
AxisTitle(showTitle: true, titleText: 'Value', margin: 4),
bottomTitle: AxisTitle(
showTitle: true,
margin: 0,
titleText: '2019',
textStyle: dateTextStyle,
textAlign: TextAlign.right)),
gridData: FlGridData(
show: true,
checkToShowHorizontalLine: (double value) {
Expand Down
7 changes: 7 additions & 0 deletions example/lib/line_chart/samples/line_chart_sample5.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ class LineChartSample5 extends StatelessWidget {
fontSize: 18,
)),
),
axisTitleData: const FlAxisTitleData(
rightTitle: AxisTitle(showTitle: true, titleText: 'count'),
leftTitle: AxisTitle(showTitle: true, titleText: 'count'),
topTitle: AxisTitle(
showTitle: true,
titleText: 'Wall clock',
textAlign: TextAlign.left)),
gridData: const FlGridData(show: false),
borderData: FlBorderData(
show: true,
Expand Down
6 changes: 6 additions & 0 deletions lib/src/chart/bar_chart/bar_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:flutter/material.dart';
/// This class is responsible to holds data to draw Bar Chart
/// [barGroups] holds list of bar groups to show together,
/// [groupsSpace] space between groups, it applies only when the [alignment] is [Alignment.center],
/// [axisTitleData] to show a description of each axis
/// [alignment] is the alignment of showing groups,
/// [titlesData] holds data about drawing left and bottom titles.
class BarChartData extends AxisChartData {
Expand All @@ -30,11 +31,13 @@ class BarChartData extends AxisChartData {
show: false,
),
FlBorderData borderData,
FlAxisTitleData axisTitleData = const FlAxisTitleData(),
double maxY,
Color backgroundColor,
}) : super(
gridData: gridData,
borderData: borderData,
axisTitleData: axisTitleData,
backgroundColor: backgroundColor,
touchData: barTouchData,
) {
Expand Down Expand Up @@ -91,6 +94,7 @@ class BarChartData extends AxisChartData {
double groupsSpace,
BarChartAlignment alignment,
FlTitlesData titlesData,
FlAxisTitleData axisTitleData,
BarTouchData barTouchData,
FlGridData gridData,
FlBorderData borderData,
Expand All @@ -102,6 +106,7 @@ class BarChartData extends AxisChartData {
groupsSpace: groupsSpace ?? this.groupsSpace,
alignment: alignment ?? this.alignment,
titlesData: titlesData ?? this.titlesData,
axisTitleData: axisTitleData ?? this.axisTitleData,
barTouchData: barTouchData ?? this.barTouchData,
gridData: gridData ?? this.gridData,
borderData: borderData ?? this.borderData,
Expand All @@ -118,6 +123,7 @@ class BarChartData extends AxisChartData {
groupsSpace: lerpDouble(a.groupsSpace, b.groupsSpace, t),
alignment: b.alignment,
titlesData: FlTitlesData.lerp(a.titlesData, b.titlesData, t),
axisTitleData: FlAxisTitleData.lerp(a.axisTitleData, b.axisTitleData, t),
barTouchData: b.barTouchData,
gridData: FlGridData.lerp(a.gridData, b.gridData, t),
borderData: FlBorderData.lerp(a.borderData, b.borderData, t),
Expand Down
1 change: 1 addition & 0 deletions lib/src/chart/bar_chart/bar_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class BarChartPainter extends AxisChartPainter<BarChartData> with TouchHandler<B
groupBarsPosition = calculateGroupAndBarsPosition(size, groupsX, data.barGroups);

drawBars(canvas, size, groupBarsPosition);
drawAxisTitles(canvas, size);
drawTitles(canvas, size, groupBarsPosition);

for (int i = 0; i < targetData.barGroups.length; i++) {
Expand Down
2 changes: 2 additions & 0 deletions lib/src/chart/base/axis_chart/axis_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
/// each child have to set it in their constructor.
abstract class AxisChartData extends BaseChartData {
final FlGridData gridData;
final FlAxisTitleData axisTitleData;

double minX, maxX;
double minY, maxY;
Expand All @@ -26,6 +27,7 @@ abstract class AxisChartData extends BaseChartData {
this.gridData = const FlGridData(),
FlBorderData borderData,
FlTouchData touchData,
this.axisTitleData,
this.minX,
this.maxX,
this.minY,
Expand Down
148 changes: 148 additions & 0 deletions lib/src/chart/base/axis_chart/axis_chart_painter.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:math' as math;

import 'package:fl_chart/src/chart/bar_chart/bar_chart_painter.dart';
import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart';
import 'package:fl_chart/src/chart/line_chart/line_chart_painter.dart';
Expand Down Expand Up @@ -28,6 +30,152 @@ abstract class AxisChartPainter<D extends AxisChartData> extends BaseChartPainte
drawGrid(canvas, size);
}


void drawAxisTitles(Canvas canvas, Size viewSize) {
if (!data.axisTitleData.show) {
return;
}
viewSize = getChartUsableDrawSize(viewSize);

final axisTitles = data.axisTitleData;

// Left Title
final leftTitle = axisTitles.leftTitle;
if (leftTitle.showTitle) {
final TextSpan span =
TextSpan(style: leftTitle.textStyle, text: leftTitle.titleText);
final TextPainter tp = TextPainter(
text: span,
textAlign: leftTitle.textAlign,
textDirection: TextDirection.ltr);
tp.layout(minWidth: viewSize.height);
canvas.save();
canvas.rotate(-math.pi * 0.5);
tp.paint(
canvas,
Offset(-viewSize.height - getTopOffsetDrawSize(),
leftTitle.reservedSize - tp.height));
canvas.restore();
}

// Top title
final topTitle = axisTitles.topTitle;
if (topTitle.showTitle) {
final TextSpan span =
TextSpan(style: topTitle.textStyle, text: topTitle.titleText);
final TextPainter tp = TextPainter(
text: span,
textAlign: topTitle.textAlign,
textDirection: TextDirection.ltr);
tp.layout(minWidth: viewSize.width);
tp.paint(canvas,
Offset(getLeftOffsetDrawSize(), topTitle.reservedSize - tp.height));
}

// Right Title
final rightTitle = axisTitles.rightTitle;
if (rightTitle.showTitle) {
final TextSpan span =
TextSpan(style: rightTitle.textStyle, text: rightTitle.titleText);
final TextPainter tp = TextPainter(
text: span,
textAlign: rightTitle.textAlign,
textDirection: TextDirection.ltr);
tp.layout(minWidth: viewSize.height);
canvas.save();
canvas.rotate(-math.pi * 0.5);
tp.paint(
canvas,
Offset(
-viewSize.height - getTopOffsetDrawSize(),
viewSize.width +
getExtraNeededHorizontalSpace() -
rightTitle.reservedSize));
canvas.restore();
}

// Bottom title
final bottomTitle = axisTitles.bottomTitle;
if (bottomTitle.showTitle) {
final TextSpan span =
TextSpan(style: bottomTitle.textStyle, text: bottomTitle.titleText);
final TextPainter tp = TextPainter(
text: span,
textAlign: bottomTitle.textAlign,
textDirection: TextDirection.ltr);
tp.layout(minWidth: viewSize.width);
tp.paint(
canvas,
Offset(
getLeftOffsetDrawSize(),
getExtraNeededVerticalSpace() -
bottomTitle.reservedSize +
viewSize.height));
}
}

@override
double getExtraNeededHorizontalSpace() {
double sum = super.getExtraNeededHorizontalSpace();

if (data.axisTitleData.show) {
final leftSide = data.axisTitleData.leftTitle;
if (leftSide.showTitle) {
sum += leftSide.reservedSize + leftSide.margin;
}

final rightSide = data.axisTitleData.rightTitle;
if (rightSide.showTitle) {
sum += rightSide.reservedSize + rightSide.margin;
}
}

return sum;
}

@override
double getExtraNeededVerticalSpace() {
double sum = super.getExtraNeededVerticalSpace();

if (data.axisTitleData.show) {
final topSide = data.axisTitleData.topTitle;
if (topSide.showTitle) {
sum += topSide.reservedSize + topSide.margin;
}

final bottomSide = data.axisTitleData.bottomTitle;
if (bottomSide.showTitle) {
sum += bottomSide.reservedSize + bottomSide.margin;
}
}

return sum;
}

@override
double getLeftOffsetDrawSize() {
var sum = super.getLeftOffsetDrawSize();

final leftAxisTitle = data.axisTitleData.leftTitle;
if (data.axisTitleData.show && leftAxisTitle.showTitle) {
sum += leftAxisTitle.reservedSize + leftAxisTitle.margin;
}

return sum;
}

@override
double getTopOffsetDrawSize() {
var sum = super.getTopOffsetDrawSize();

final topAxisTitle = data.axisTitleData.topTitle;
if (data.axisTitleData.show && topAxisTitle.showTitle) {
sum += topAxisTitle.reservedSize + topAxisTitle.margin;
}

return sum;
}

void drawGrid(Canvas canvas, Size viewSize) {
if (!data.gridData.show || data.gridData == null) {
return;
Expand Down
65 changes: 64 additions & 1 deletion lib/src/chart/base/base_chart/base_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class FlBorderData {
);
}


}

/***** TouchData *****/
Expand All @@ -72,6 +72,69 @@ class FlTouchData {
const FlTouchData(this.enabled, this.enableNormalTouch);
}

///***** AxisTitleData *****/
/// This class holds data about the description for each axis of the chart.
class FlAxisTitleData {
final bool show;

final AxisTitle leftTitle, topTitle, rightTitle, bottomTitle;

const FlAxisTitleData({
this.show = true,
this.leftTitle = const AxisTitle(reservedSize: 16),
this.topTitle = const AxisTitle(reservedSize: 16),
this.rightTitle = const AxisTitle(reservedSize: 16),
this.bottomTitle = const AxisTitle(reservedSize: 16),
});

static FlAxisTitleData lerp(FlAxisTitleData a, FlAxisTitleData b, double t) {
return FlAxisTitleData(
show: b.show,
leftTitle: AxisTitle.lerp(a.leftTitle, b.leftTitle, t),
rightTitle: AxisTitle.lerp(a.rightTitle, b.rightTitle, t),
bottomTitle: AxisTitle.lerp(a.bottomTitle, b.bottomTitle, t),
topTitle: AxisTitle.lerp(a.topTitle, b.topTitle, t),
);
}
}

/// specify each axis titles data
class AxisTitle {
final bool showTitle;
final double reservedSize;
final TextStyle textStyle;
final TextAlign textAlign;
final double margin;
final String titleText;

const AxisTitle({
this.showTitle = false,
this.titleText = '',
this.reservedSize = 14,
this.textStyle = const TextStyle(
color: Colors.black,
fontSize: 11,
),
this.textAlign = TextAlign.center,
this.margin = 4,
});

static AxisTitle lerp(AxisTitle a, AxisTitle b, double t) {
return AxisTitle(
showTitle: b.showTitle,
titleText: b.titleText,
reservedSize: lerpDouble(a.reservedSize, b.reservedSize, t),
textStyle: TextStyle.lerp(
a.textStyle.copyWith(fontSize: a.textStyle.fontSize),
b.textStyle.copyWith(fontSize: b.textStyle.fontSize),
t),
textAlign: b.textAlign,
margin: lerpDouble(a.margin, b.margin, t),
);
}
}

/***** TitlesData *****/

/// we use this typedef to determine which titles
Expand Down
Loading

0 comments on commit 1cf6723

Please sign in to comment.