Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rotate angle to chart #124

Merged
merged 8 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions example/lib/bar_chart/samples/bar_chart_sample5.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class BarChartSample5State extends State<BarChartSample5> {
showTitles: true,
textStyle: TextStyle(color: Colors.white, fontSize: 10),
margin: 10,
rotateAngle: 180,
getTitles: (double value) {
switch (value.toInt()) {
case 0:
Expand All @@ -65,6 +66,21 @@ class BarChartSample5State extends State<BarChartSample5> {
leftTitles: SideTitles(
showTitles: true,
textStyle: TextStyle(color: Colors.white, fontSize: 10),
rotateAngle: 45,
getTitles: (double value) {
if (value == 0) {
return '';
}
return '${value.toInt()}0k';
},
interval: 5,
margin: 8,
reservedSize: 30,
),
rightTitles: SideTitles(
showTitles: true,
textStyle: TextStyle(color: Colors.white, fontSize: 10),
rotateAngle: 90,
getTitles: (double value) {
if (value == 0) {
return '';
Expand Down
35 changes: 27 additions & 8 deletions lib/src/chart/bar_chart/bar_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

import '../../utils/utils.dart';

class BarChartPainter extends AxisChartPainter<BarChartData> with TouchHandler<BarTouchResponse> {
Paint barPaint, bgTouchTooltipPaint;
Paint clearPaint;
Expand Down Expand Up @@ -287,8 +289,14 @@ class BarChartPainter extends AxisChartPainter<BarChartData> with TouchHandler<B
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());
x -= tp.width + leftTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(leftTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(leftTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y -= translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += leftTitles.interval;
}
Expand All @@ -309,8 +317,14 @@ class BarChartPainter extends AxisChartPainter<BarChartData> with TouchHandler<B
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());
x += rightTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(rightTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(rightTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y += translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += rightTitles.interval;
}
Expand All @@ -323,16 +337,21 @@ class BarChartPainter extends AxisChartPainter<BarChartData> with TouchHandler<B
final GroupBarsPosition groupBarPos = groupBarsPosition[index];

final String text = bottomTitles.getTitles(index.toDouble());

final TextSpan span = TextSpan(style: bottomTitles.textStyle, text: text);
final TextPainter tp =
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout();

final double textX = groupBarPos.groupX - (tp.width / 2);
final double textY = drawSize.height + getTopOffsetDrawSize() + bottomTitles.margin;

tp.paint(canvas, Offset(textX, textY));
double x = groupBarPos.groupX;
double y = drawSize.height + getTopOffsetDrawSize() + bottomTitles.margin;

x -= getSideTitlesPosition(bottomTitles.alignment, tp.width);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(bottomTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
x += translateRotatedPosition(tp.width, bottomTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions lib/src/chart/base/base_chart/base_chart_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ class FlTitlesData {
}
}

/// this is mimic of [MainAxisAlignment] to aligning the [SideTitles]
enum SideTitlesAlignment {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need SideTitlesAlignment anymore?
Can you explain it's usage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default position of TextPainter is center of it's x-axis point.
I just add this alignment for whom wanna set this view for better rendering in special cases.
If you think it's an irrelevant parameter I can remove it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please let's remove it because it is not fully customizable, we can just customize the x-axis pivot, and for sure we should add customization for both axes.
We can add it in the future if it is needed.
Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good point, I just removed it.

start,
end,
center,
}

/// specify each side titles data
class SideTitles {
final bool showTitles;
Expand All @@ -119,6 +126,8 @@ class SideTitles {
final TextStyle textStyle;
final double margin;
final double interval;
final double rotateAngle;
final SideTitlesAlignment alignment;

const SideTitles({
this.showTitles = false,
Expand All @@ -130,6 +139,8 @@ class SideTitles {
),
this.margin = 6,
this.interval = 1.0,
this.rotateAngle = 0.0,
arefhosseini marked this conversation as resolved.
Show resolved Hide resolved
this.alignment = SideTitlesAlignment.center,
});

static SideTitles lerp(SideTitles a, SideTitles b, double t) {
Expand All @@ -140,6 +151,8 @@ class SideTitles {
textStyle: TextStyle.lerp(a.textStyle, b.textStyle, t),
margin: lerpDouble(a.margin, b.margin, t),
interval: lerpDouble(a.interval, b.interval, t),
rotateAngle: lerpDouble(a.rotateAngle, b.rotateAngle, t),
alignment: b.alignment,
);
}
}
Expand Down
15 changes: 15 additions & 0 deletions lib/src/chart/base/base_chart/base_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ abstract class BaseChartPainter<D extends BaseChartData> extends CustomPainter {
/// we should use this to offset our y axis when we drawing the chart,
/// and the height space we can use to draw chart is[getChartUsableDrawSize.height]
double getTopOffsetDrawSize() => 0;

/// calculate the position of text [SideTitles] base of its [SideTitlesAlignment]
/// like SideTitlesAlignment.start, center & end
double getSideTitlesPosition(SideTitlesAlignment alignment, double size) {
switch(alignment) {
case SideTitlesAlignment.start:
return size;
case SideTitlesAlignment.end:
return 0.0;
case SideTitlesAlignment.center:
return size / 2;
default:
return size / 2;
}
}
}

mixin TouchHandler<T extends BaseTouchResponse> {
Expand Down
38 changes: 30 additions & 8 deletions lib/src/chart/line_chart/line_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:fl_chart/src/chart/base/base_chart/touch_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

import '../../utils/utils.dart';
import 'line_chart_data.dart';

class LineChartPainter extends AxisChartPainter<LineChartData> with TouchHandler<LineTouchResponse> {
Expand Down Expand Up @@ -578,8 +579,14 @@ class LineChartPainter extends AxisChartPainter<LineChartData> with TouchHandler
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());
x -= tp.width + leftTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(leftTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(leftTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y -= translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += leftTitles.interval;
}
Expand All @@ -600,10 +607,15 @@ class LineChartPainter extends AxisChartPainter<LineChartData> with TouchHandler
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout();

x -= tp.width / 2;
x -= getSideTitlesPosition(topTitles.alignment, tp.width);
y -= topTitles.margin + tp.height;

canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(topTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
x -= translateRotatedPosition(tp.width, topTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

horizontalSeek += topTitles.interval;
}
Expand All @@ -623,9 +635,16 @@ class LineChartPainter extends AxisChartPainter<LineChartData> with TouchHandler
final TextPainter tp =
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());

x += rightTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(rightTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(rightTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y += translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += rightTitles.interval;
}
Expand All @@ -638,18 +657,21 @@ class LineChartPainter extends AxisChartPainter<LineChartData> with TouchHandler
while (horizontalSeek <= data.maxX) {
double x = getPixelX(horizontalSeek, viewSize);
double y = viewSize.height + getTopOffsetDrawSize();

final String text = bottomTitles.getTitles(horizontalSeek);

final TextSpan span = TextSpan(style: bottomTitles.textStyle, text: text);
final TextPainter tp =
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout();

x -= tp.width / 2;
x -= getSideTitlesPosition(bottomTitles.alignment, tp.width);
y += bottomTitles.margin;

canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(bottomTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
x += translateRotatedPosition(tp.width, bottomTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

horizontalSeek += bottomTitles.interval;
}
Expand Down
36 changes: 30 additions & 6 deletions lib/src/chart/scatter_chart/scatter_chart_painter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:fl_chart/src/chart/base/base_chart/touch_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

import '../../utils/utils.dart';
import 'scatter_chart_data.dart';

class ScatterChartPainter extends AxisChartPainter<ScatterChartData> with TouchHandler<ScatterTouchResponse> {
Expand Down Expand Up @@ -65,8 +66,14 @@ class ScatterChartPainter extends AxisChartPainter<ScatterChartData> with TouchH
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());
x -= tp.width + leftTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(leftTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(leftTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y -= translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += leftTitles.interval;
}
Expand All @@ -87,10 +94,15 @@ class ScatterChartPainter extends AxisChartPainter<ScatterChartData> with TouchH
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout();

x -= tp.width / 2;
x -= getSideTitlesPosition(topTitles.alignment, tp.width);
y -= topTitles.margin + tp.height;

canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(topTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
x -= translateRotatedPosition(tp.width, topTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

horizontalSeek += topTitles.interval;
}
Expand All @@ -110,9 +122,16 @@ class ScatterChartPainter extends AxisChartPainter<ScatterChartData> with TouchH
final TextPainter tp =
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout(maxWidth: getExtraNeededHorizontalSpace());

x += rightTitles.margin;
y -= tp.height / 2;
y -= getSideTitlesPosition(rightTitles.alignment, tp.height);
canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(rightTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
y += translateRotatedPosition(tp.width, leftTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

verticalSeek += rightTitles.interval;
}
Expand All @@ -133,10 +152,15 @@ class ScatterChartPainter extends AxisChartPainter<ScatterChartData> with TouchH
TextPainter(text: span, textAlign: TextAlign.center, textDirection: TextDirection.ltr);
tp.layout();

x -= tp.width / 2;
x -= getSideTitlesPosition(bottomTitles.alignment, tp.width);
y += bottomTitles.margin;

canvas.save();
canvas.translate(x + tp.width / 2, y + tp.height / 2);
canvas.rotate(radians(bottomTitles.rotateAngle));
canvas.translate(-(x + tp.width / 2), -(y + tp.height / 2));
x += translateRotatedPosition(tp.width, bottomTitles.rotateAngle);
tp.paint(canvas, Offset(x, y));
canvas.restore();

horizontalSeek += bottomTitles.interval;
}
Expand Down
5 changes: 5 additions & 0 deletions lib/src/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ Size getDefaultSize(BuildContext context) {
size *= 0.7;
return size;
}

/// forward the view base on its degree
double translateRotatedPosition(double size, double degree) {
return (size / 4) * math.sin(radians(degree.abs()));
}