Skip to content

Commit f71f85f

Browse files
committed
Merge pull request PhilJay#1155 from danielgindi/x-axis-label-rotation
Implemented support for rotated labels on the x-axis
2 parents 024cbbe + 8490f80 commit f71f85f

10 files changed

Lines changed: 235 additions & 54 deletions

File tree

MPChartLib/src/com/github/mikephil/charting/charts/BarLineChartBase.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ public void calculateOffsets() {
489489

490490
if (mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled()) {
491491

492-
float xlabelheight = mXAxis.mLabelHeight * 2f;
492+
float xlabelheight = mXAxis.mLabelRotatedHeight + mXAxis.getYOffset();
493493

494494
// offsets for x-labels
495495
if (mXAxis.getPosition() == XAxisPosition.BOTTOM) {
@@ -545,14 +545,16 @@ protected void calcModulus() {
545545
mViewPortHandler.getMatrixTouch().getValues(values);
546546

547547
mXAxis.mAxisLabelModulus = (int) Math
548-
.ceil((mData.getXValCount() * mXAxis.mLabelWidth)
548+
.ceil((mData.getXValCount() * mXAxis.mLabelRotatedWidth)
549549
/ (mViewPortHandler.contentWidth() * values[Matrix.MSCALE_X]));
550550

551551
}
552552

553553
if (mLogEnabled)
554-
Log.i(LOG_TAG, "X-Axis modulus: " + mXAxis.mAxisLabelModulus + ", x-axis label width: "
555-
+ mXAxis.mLabelWidth + ", content width: " + mViewPortHandler.contentWidth());
554+
Log.i(LOG_TAG, "X-Axis modulus: " + mXAxis.mAxisLabelModulus +
555+
", x-axis label width: " + mXAxis.mLabelWidth +
556+
", x-axis label rotated width: " + mXAxis.mLabelRotatedWidth +
557+
", content width: " + mViewPortHandler.contentWidth());
556558

557559
if (mXAxis.mAxisLabelModulus < 1)
558560
mXAxis.mAxisLabelModulus = 1;

MPChartLib/src/com/github/mikephil/charting/charts/HorizontalBarChart.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public void calculateOffsets() {
108108
offsetBottom += mAxisRight.getRequiredHeightSpace(mAxisRendererRight.getPaintAxisLabels());
109109
}
110110

111-
float xlabelwidth = mXAxis.mLabelWidth;
111+
float xlabelwidth = mXAxis.mLabelRotatedWidth;
112112

113113
if (mXAxis.isEnabled()) {
114114

@@ -162,7 +162,8 @@ protected void calcModulus() {
162162
float[] values = new float[9];
163163
mViewPortHandler.getMatrixTouch().getValues(values);
164164

165-
mXAxis.mAxisLabelModulus = (int) Math.ceil((mData.getXValCount() * mXAxis.mLabelHeight)
165+
mXAxis.mAxisLabelModulus =
166+
(int) Math.ceil((mData.getXValCount() * mXAxis.mLabelRotatedHeight)
166167
/ (mViewPortHandler.contentHeight() * values[Matrix.MSCALE_Y]));
167168

168169
if (mXAxis.mAxisLabelModulus < 1)

MPChartLib/src/com/github/mikephil/charting/charts/PieRadarChartBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public void calculateOffsets() {
218218
XAxis x = ((RadarChart) this).getXAxis();
219219

220220
if (x.isEnabled() && x.isDrawLabelsEnabled()) {
221-
minOffset = Math.max(minOffset, x.mLabelWidth);
221+
minOffset = Math.max(minOffset, x.mLabelRotatedWidth);
222222
}
223223
}
224224

MPChartLib/src/com/github/mikephil/charting/charts/RadarChart.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,9 @@ protected float getRequiredLegendOffset() {
377377

378378
@Override
379379
protected float getRequiredBaseOffset() {
380-
return mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled() ? mXAxis.mLabelWidth : Utils.convertDpToPixel(10f);
380+
return mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled() ?
381+
mXAxis.mLabelRotatedWidth :
382+
Utils.convertDpToPixel(10f);
381383
}
382384

383385
@Override

MPChartLib/src/com/github/mikephil/charting/components/XAxis.java

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import com.github.mikephil.charting.formatter.DefaultXAxisValueFormatter;
55
import com.github.mikephil.charting.formatter.XAxisValueFormatter;
6+
import com.github.mikephil.charting.utils.Utils;
67

78
import java.util.ArrayList;
89
import java.util.List;
@@ -20,17 +21,34 @@ public class XAxis extends AxisBase {
2021
protected List<String> mValues = new ArrayList<String>();
2122

2223
/**
23-
* width of the x-axis labels in pixels - this is calculated by the
24-
* calcTextWidth() method of the utils
24+
* width of the x-axis labels in pixels - this is automatically
25+
* calculated by the computeAxis() methods in the renderers
2526
*/
2627
public int mLabelWidth = 1;
2728

2829
/**
29-
* height of the x-axis labels in pixels - this is calculated by the
30-
* calcTextHeight() method of the utils
30+
* height of the x-axis labels in pixels - this is automatically
31+
* calculated by the computeAxis() methods in the renderers
3132
*/
3233
public int mLabelHeight = 1;
3334

35+
/**
36+
* width of the (rotated) x-axis labels in pixels - this is automatically
37+
* calculated by the computeAxis() methods in the renderers
38+
*/
39+
public int mLabelRotatedWidth = 1;
40+
41+
/**
42+
* height of the (rotated) x-axis labels in pixels - this is automatically
43+
* calculated by the computeAxis() methods in the renderers
44+
*/
45+
public int mLabelRotatedHeight = 1;
46+
47+
/**
48+
* This is the angle for drawing the X axis labels (in degrees)
49+
*/
50+
protected float mLabelRotationAngle = 0.f;
51+
3452
/**
3553
* the space that should be left out (in characters) between the x-axis
3654
* labels
@@ -78,6 +96,8 @@ public enum XAxisPosition {
7896

7997
public XAxis() {
8098
super();
99+
100+
mYOffset = Utils.convertDpToPixel(4.f);
81101
}
82102

83103
/**
@@ -96,6 +116,22 @@ public void setPosition(XAxisPosition pos) {
96116
mPosition = pos;
97117
}
98118

119+
/**
120+
* returns the angle for drawing the X axis labels (in degrees)
121+
*/
122+
public float getLabelRotationAngle() {
123+
return mLabelRotationAngle;
124+
}
125+
126+
/**
127+
* sets the angle for drawing the X axis labels (in degrees)
128+
*
129+
* @param angle the angle in degrees
130+
*/
131+
public void setLabelRotationAngle(float angle) {
132+
mLabelRotationAngle = angle;
133+
}
134+
99135
/**
100136
* Sets the space (in characters) that should be left out between the x-axis
101137
* labels, default 4. This only applies if the number of labels that will be

MPChartLib/src/com/github/mikephil/charting/renderer/XAxisRenderer.java

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
import android.graphics.Paint;
77
import android.graphics.Paint.Align;
88
import android.graphics.Path;
9+
import android.graphics.PointF;
10+
import android.util.Size;
911

1012
import com.github.mikephil.charting.components.LimitLine;
1113
import com.github.mikephil.charting.components.XAxis;
1214
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
15+
import com.github.mikephil.charting.utils.FSize;
1316
import com.github.mikephil.charting.utils.Transformer;
1417
import com.github.mikephil.charting.utils.Utils;
1518
import com.github.mikephil.charting.utils.ViewPortHandler;
@@ -35,17 +38,30 @@ public void computeAxis(float xValAverageLength, List<String> xValues) {
3538
mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
3639
mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
3740

38-
StringBuffer a = new StringBuffer();
41+
StringBuilder widthText = new StringBuilder();
3942

40-
int max = (int) Math.round(xValAverageLength
43+
int max = Math.round(xValAverageLength
4144
+ mXAxis.getSpaceBetweenLabels());
4245

4346
for (int i = 0; i < max; i++) {
44-
a.append('h');
47+
widthText.append('h');
4548
}
4649

47-
mXAxis.mLabelWidth = Utils.calcTextWidth(mAxisLabelPaint, a.toString());
48-
mXAxis.mLabelHeight = Utils.calcTextHeight(mAxisLabelPaint, "Q");
50+
final FSize labelSize = Utils.calcTextSize(mAxisLabelPaint, widthText.toString());
51+
52+
final float labelWidth = labelSize.width;
53+
final float labelHeight = Utils.calcTextHeight(mAxisLabelPaint, "Q");
54+
55+
final FSize labelRotatedSize = Utils.getSizeOfRotatedRectangleByDegrees(
56+
labelWidth,
57+
labelHeight,
58+
mXAxis.getLabelRotationAngle());
59+
60+
mXAxis.mLabelWidth = Math.round(labelWidth);
61+
mXAxis.mLabelHeight = Math.round(labelHeight);
62+
mXAxis.mLabelRotatedWidth = Math.round(labelRotatedSize.width);
63+
mXAxis.mLabelRotatedHeight = Math.round(labelRotatedSize.height);
64+
4965
mXAxis.setValues(xValues);
5066
}
5167

@@ -55,32 +71,38 @@ public void renderAxisLabels(Canvas c) {
5571
if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled())
5672
return;
5773

58-
float yoffset = Utils.convertDpToPixel(4f);
74+
float yoffset = mXAxis.getYOffset();
5975

6076
mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
6177
mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
6278
mAxisLabelPaint.setColor(mXAxis.getTextColor());
6379

6480
if (mXAxis.getPosition() == XAxisPosition.TOP) {
6581

66-
drawLabels(c, mViewPortHandler.offsetTop() - yoffset);
82+
drawLabels(c, mViewPortHandler.contentTop() - yoffset,
83+
new PointF(0.5f, 1.0f));
6784

68-
} else if (mXAxis.getPosition() == XAxisPosition.BOTTOM) {
85+
} else if (mXAxis.getPosition() == XAxisPosition.TOP_INSIDE) {
6986

70-
drawLabels(c, mViewPortHandler.contentBottom() + mXAxis.mLabelHeight + yoffset * 1.5f);
87+
drawLabels(c, mViewPortHandler.contentTop() + yoffset + mXAxis.mLabelRotatedHeight,
88+
new PointF(0.5f, 1.0f));
7189

72-
} else if (mXAxis.getPosition() == XAxisPosition.BOTTOM_INSIDE) {
90+
} else if (mXAxis.getPosition() == XAxisPosition.BOTTOM) {
7391

74-
drawLabels(c, mViewPortHandler.contentBottom() - yoffset);
92+
drawLabels(c, mViewPortHandler.contentBottom() + yoffset,
93+
new PointF(0.5f, 0.0f));
7594

76-
} else if (mXAxis.getPosition() == XAxisPosition.TOP_INSIDE) {
95+
} else if (mXAxis.getPosition() == XAxisPosition.BOTTOM_INSIDE) {
7796

78-
drawLabels(c, mViewPortHandler.offsetTop() + yoffset + mXAxis.mLabelHeight);
97+
drawLabels(c, mViewPortHandler.contentBottom() - yoffset - mXAxis.mLabelRotatedHeight,
98+
new PointF(0.5f, 0.0f));
7999

80100
} else { // BOTH SIDED
81101

82-
drawLabels(c, mViewPortHandler.offsetTop() - yoffset);
83-
drawLabels(c, mViewPortHandler.contentBottom() + mXAxis.mLabelHeight + yoffset * 1.6f);
102+
drawLabels(c, mViewPortHandler.contentTop() - yoffset,
103+
new PointF(0.5f, 1.0f));
104+
drawLabels(c, mViewPortHandler.contentBottom() + yoffset,
105+
new PointF(0.5f, 0.0f));
84106
}
85107
}
86108

@@ -115,7 +137,9 @@ public void renderAxisLine(Canvas c) {
115137
*
116138
* @param pos
117139
*/
118-
protected void drawLabels(Canvas c, float pos) {
140+
protected void drawLabels(Canvas c, float pos, PointF anchor) {
141+
142+
final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
119143

120144
// pre allocate to save performance (dont allocate in loop)
121145
float[] position = new float[] {
@@ -150,14 +174,14 @@ protected void drawLabels(Canvas c, float pos) {
150174
}
151175
}
152176

153-
drawLabel(c, label, i, position[0], pos);
177+
drawLabel(c, label, i, position[0], pos, anchor, labelRotationAngleDegrees);
154178
}
155179
}
156180
}
157181

158-
protected void drawLabel(Canvas c, String label, int xIndex, float x, float y) {
182+
protected void drawLabel(Canvas c, String label, int xIndex, float x, float y, PointF anchor, float angleDegrees) {
159183
String formattedLabel = mXAxis.getValueFormatter().getXValue(label, xIndex, mViewPortHandler);
160-
c.drawText(formattedLabel, x, y, mAxisLabelPaint);
184+
Utils.drawText(c, formattedLabel, x, y, mAxisLabelPaint, anchor, angleDegrees);
161185
}
162186

163187
@Override

MPChartLib/src/com/github/mikephil/charting/renderer/XAxisRendererBarChart.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package com.github.mikephil.charting.renderer;
33

44
import android.graphics.Canvas;
5+
import android.graphics.PointF;
56

67
import com.github.mikephil.charting.charts.BarChart;
78
import com.github.mikephil.charting.components.XAxis;
@@ -27,7 +28,9 @@ public XAxisRendererBarChart(ViewPortHandler viewPortHandler, XAxis xAxis, Trans
2728
* @param pos
2829
*/
2930
@Override
30-
protected void drawLabels(Canvas c, float pos) {
31+
protected void drawLabels(Canvas c, float pos, PointF anchor) {
32+
33+
final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
3134

3235
// pre allocate to save performance (dont allocate in loop)
3336
float[] position = new float[] {
@@ -73,7 +76,7 @@ protected void drawLabels(Canvas c, float pos) {
7376
}
7477
}
7578

76-
drawLabel(c, label, i, position[0], pos);
79+
drawLabel(c, label, i, position[0], pos, anchor, labelRotationAngleDegrees);
7780
}
7881
}
7982
}

0 commit comments

Comments
 (0)