Skip to content

Commit bc20a75

Browse files
committed
Fix x-axis labels overlapping
1 parent 0550d3f commit bc20a75

File tree

7 files changed

+153
-189
lines changed

7 files changed

+153
-189
lines changed

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

+18
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public class XAxis extends AxisBase {
4747
*/
4848
private boolean mAvoidFirstLastClipping = false;
4949

50+
/**
51+
* minimum spacing between labels in pixels
52+
*/
53+
protected float mSpaceBetweenLabelsMin = 0;
54+
5055
/**
5156
* the position of the x-labels relative to the chart
5257
*/
@@ -65,6 +70,19 @@ public XAxis() {
6570
mYOffset = Utils.convertDpToPixel(4.f); // -3
6671
}
6772

73+
/**
74+
* Returns minimum spacing between labels in pixels
75+
*/
76+
public float getSpaceBetweenLabelsMin() { return mSpaceBetweenLabelsMin; }
77+
78+
/**
79+
* Sets minimum spacing between labels in pixels
80+
*/
81+
public void setSpaceBetweenLabelsMin(float space)
82+
{
83+
mSpaceBetweenLabelsMin = space;
84+
}
85+
6886
/**
6987
* returns the position of the x-labels
7088
*/

MPChartLib/src/main/java/com/github/mikephil/charting/renderer/AxisRenderer.java

+18-66
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import android.graphics.Paint.Style;
88

99
import com.github.mikephil.charting.components.AxisBase;
10-
import com.github.mikephil.charting.utils.MPPointD;
1110
import com.github.mikephil.charting.utils.Transformer;
1211
import com.github.mikephil.charting.utils.Utils;
1312
import com.github.mikephil.charting.utils.ViewPortHandler;
@@ -115,73 +114,26 @@ public Transformer getTransformer() {
115114
* @param min - the minimum value in the data object for this axis
116115
* @param max - the maximum value in the data object for this axis
117116
*/
118-
public void computeAxis(float min, float max, boolean inverted) {
117+
public abstract void computeAxis(float min, float max, boolean inverted);
119118

120-
// calculate the starting and entry point of the y-labels (depending on
121-
// zoom / contentrect bounds)
122-
if (mViewPortHandler != null && mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutY()) {
123-
124-
MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
125-
MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom());
126-
127-
if (!inverted) {
128-
129-
min = (float) p2.y;
130-
max = (float) p1.y;
131-
} else {
132-
133-
min = (float) p1.y;
134-
max = (float) p2.y;
135-
}
136-
137-
MPPointD.recycleInstance(p1);
138-
MPPointD.recycleInstance(p2);
139-
}
140-
141-
computeAxisValues(min, max);
142-
}
143119

144120
/**
145-
* Sets up the axis values. Computes the desired number of labels between the two given extremes.
146-
*
147-
* @return
121+
* Compute axis interval and desired number of labels between the two given extremes
122+
* @param min
123+
* @param max
148124
*/
149-
protected void computeAxisValues(float min, float max) {
150-
151-
float yMin = min;
152-
float yMax = max;
153-
154-
int labelCount = mAxis.getLabelCount();
155-
double range = Math.abs(yMax - yMin);
156-
157-
if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
158-
mAxis.mEntries = new float[]{};
159-
mAxis.mCenteredEntries = new float[]{};
160-
mAxis.mEntryCount = 0;
161-
return;
162-
}
163-
164-
// Find out how much spacing (in y value space) between axis values
165-
double rawInterval = range / labelCount;
166-
double interval = Utils.roundToNextSignificant(rawInterval);
167-
168-
// If granularity is enabled, then do not allow the interval to go below specified granularity.
169-
// This is used to avoid repeated values when rounding values for display.
170-
if (mAxis.isGranularityEnabled())
171-
interval = interval < mAxis.getGranularity() ? mAxis.getGranularity() : interval;
172-
173-
// Normalize interval
174-
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
175-
int intervalSigDigit = (int) (interval / intervalMagnitude);
176-
if (intervalSigDigit > 5) {
177-
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
178-
// if it's 0.0 after floor(), we use the old value
179-
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
180-
? interval
181-
: Math.floor(10.0 * intervalMagnitude);
182-
183-
}
125+
protected abstract void computeAxisInterval(float min, float max);
184126

127+
/**
128+
* Setup axis entries and decimals based on the previously computed interval and labels count
129+
* @param min
130+
* @param max
131+
* @param labelCount
132+
* @param range
133+
* @param interval
134+
*/
135+
protected void computeAxisValues(float min, float max, int labelCount, double range, double interval) {
136+
185137
int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;
186138

187139
// force label count
@@ -207,12 +159,12 @@ protected void computeAxisValues(float min, float max) {
207159
// no forced count
208160
} else {
209161

210-
double first = interval == 0.0 ? 0.0 : Math.ceil(yMin / interval) * interval;
162+
double first = interval == 0.0 ? 0.0 : Math.ceil(min / interval) * interval;
211163
if(mAxis.isCenterAxisLabelsEnabled()) {
212164
first -= interval;
213165
}
214166

215-
double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(yMax / interval) * interval);
167+
double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(max / interval) * interval);
216168

217169
double f;
218170
int i;
@@ -262,7 +214,7 @@ else if (last == first && n == 0) {
262214
}
263215
}
264216
}
265-
217+
266218
/**
267219
* Draws the axis labels to the screen.
268220
*

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

+49-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void computeAxis(float min, float max, boolean inverted) {
4545

4646
// calculate the starting and entry point of the y-labels (depending on
4747
// zoom / contentrect bounds)
48-
if (mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutX()) {
48+
if (mViewPortHandler != null && mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutX()) {
4949

5050
MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
5151
MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentRight(), mViewPortHandler.contentTop());
@@ -64,14 +64,59 @@ public void computeAxis(float min, float max, boolean inverted) {
6464
MPPointD.recycleInstance(p2);
6565
}
6666

67-
computeAxisValues(min, max);
67+
computeAxisInterval(min, max);
6868
}
6969

7070
@Override
71-
protected void computeAxisValues(float min, float max) {
72-
super.computeAxisValues(min, max);
71+
protected void computeAxisInterval(float min, float max) {
7372

73+
// Compute the longest label width first
7474
computeSize();
75+
76+
int labelCount = mXAxis.getLabelCount();
77+
double range = Math.abs(max - min);
78+
79+
if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
80+
mXAxis.mEntries = new float[]{};
81+
mXAxis.mCenteredEntries = new float[]{};
82+
mXAxis.mEntryCount = 0;
83+
return;
84+
}
85+
86+
// Find out how much spacing (in x value space) between axis values
87+
double rawInterval = range / labelCount;
88+
double interval = Utils.roundToNextSignificant(rawInterval);
89+
90+
// Do not allow the interval go below the label width with spacing.
91+
double labelMaxWidth = (mXAxis.mLabelRotatedWidth + mXAxis.getSpaceBetweenLabelsMin()) * range / mViewPortHandler.contentWidth();
92+
if (interval < labelMaxWidth)
93+
interval = labelMaxWidth;
94+
95+
// If granularity is enabled, then do not allow the interval to go below specified granularity.
96+
// This is used to avoid repeated values when rounding values for display.
97+
if (mXAxis.isGranularityEnabled())
98+
interval = interval < mXAxis.getGranularity() ? mXAxis.getGranularity() : interval;
99+
100+
// Perform rounding once again after interval was probably adjusted by label width and/or granularity checks.
101+
rawInterval = interval;
102+
interval = Utils.roundToNextSignificant(rawInterval);
103+
104+
// Normalize interval
105+
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
106+
int intervalSigDigit = (int) (interval / intervalMagnitude);
107+
if (intervalSigDigit > 5) {
108+
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
109+
// if it's 0.0 after floor(), we use the old value
110+
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
111+
? interval
112+
: Math.floor(10.0 * intervalMagnitude);
113+
114+
// If rounded down to current significant, round up to avoid label overlapping
115+
} else if (interval < rawInterval) {
116+
interval = (intervalSigDigit + 1) * intervalMagnitude;
117+
}
118+
119+
computeAxisValues(min, max, labelCount, range, interval);
75120
}
76121

77122
protected void computeSize() {
@@ -91,7 +136,6 @@ protected void computeSize() {
91136
labelHeight,
92137
mXAxis.getLabelRotationAngle());
93138

94-
95139
mXAxis.mLabelWidth = Math.round(labelWidth);
96140
mXAxis.mLabelHeight = Math.round(labelHeight);
97141
mXAxis.mLabelRotatedWidth = Math.round(labelRotatedSize.width);

MPChartLib/src/main/java/com/github/mikephil/charting/renderer/XAxisRendererHorizontalBarChart.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void computeAxis(float min, float max, boolean inverted) {
5555
MPPointD.recycleInstance(p2);
5656
}
5757

58-
computeAxisValues(min, max);
58+
computeAxisInterval(min, max);
5959
}
6060

6161
@Override

MPChartLib/src/main/java/com/github/mikephil/charting/renderer/YAxisRenderer.java

+63
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,69 @@ public YAxisRenderer(ViewPortHandler viewPortHandler, YAxis yAxis, Transformer t
4141
}
4242
}
4343

44+
@Override
45+
public void computeAxis(float min, float max, boolean inverted) {
46+
47+
// calculate the starting and entry point of the y-labels (depending on
48+
// zoom / contentrect bounds)
49+
if (mViewPortHandler != null && mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutY()) {
50+
51+
MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
52+
MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom());
53+
54+
if (!inverted) {
55+
56+
min = (float) p2.y;
57+
max = (float) p1.y;
58+
} else {
59+
60+
min = (float) p1.y;
61+
max = (float) p2.y;
62+
}
63+
64+
MPPointD.recycleInstance(p1);
65+
MPPointD.recycleInstance(p2);
66+
}
67+
68+
computeAxisInterval(min, max);
69+
}
70+
71+
@Override
72+
protected void computeAxisInterval(float min, float max) {
73+
74+
int labelCount = mYAxis.getLabelCount();
75+
double range = Math.abs(max - min);
76+
77+
if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
78+
mYAxis.mEntries = new float[]{};
79+
mYAxis.mCenteredEntries = new float[]{};
80+
mYAxis.mEntryCount = 0;
81+
return;
82+
}
83+
84+
// Find out how much spacing (in y value space) between axis values
85+
double rawInterval = range / labelCount;
86+
double interval = Utils.roundToNextSignificant(rawInterval);
87+
88+
// If granularity is enabled, then do not allow the interval to go below specified granularity.
89+
// This is used to avoid repeated values when rounding values for display.
90+
if (mYAxis.isGranularityEnabled())
91+
interval = interval < mYAxis.getGranularity() ? mYAxis.getGranularity() : interval;
92+
93+
// Normalize interval
94+
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
95+
int intervalSigDigit = (int) (interval / intervalMagnitude);
96+
if (intervalSigDigit > 5) {
97+
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
98+
// if it's 0.0 after floor(), we use the old value
99+
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
100+
? interval
101+
: Math.floor(10.0 * intervalMagnitude);
102+
}
103+
104+
computeAxisValues(min, max, labelCount, range, interval);
105+
}
106+
44107
/**
45108
* draws the y-axis labels to the screen
46109
*/

MPChartLib/src/main/java/com/github/mikephil/charting/renderer/YAxisRendererHorizontalBarChart.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void computeAxis(float yMin, float yMax, boolean inverted) {
5757
MPPointD.recycleInstance(p2);
5858
}
5959

60-
computeAxisValues(yMin, yMax);
60+
computeAxisInterval(yMin, yMax);
6161
}
6262

6363
/**

0 commit comments

Comments
 (0)