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

Fix x-axis labels overlapping #5243

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -47,6 +47,11 @@ public class XAxis extends AxisBase {
*/
private boolean mAvoidFirstLastClipping = false;

/**
* minimum spacing between labels in pixels
*/
protected float mSpaceBetweenLabelsMin = 0;

/**
* the position of the x-labels relative to the chart
*/
Expand All @@ -65,6 +70,19 @@ public XAxis() {
mYOffset = Utils.convertDpToPixel(4.f); // -3
}

/**
* Returns minimum spacing between labels in pixels
*/
public float getSpaceBetweenLabelsMin() { return mSpaceBetweenLabelsMin; }

/**
* Sets minimum spacing between labels in pixels
*/
public void setSpaceBetweenLabelsMin(float space)
{
mSpaceBetweenLabelsMin = space;
}

/**
* returns the position of the x-labels
*/
Expand Down
Expand Up @@ -7,7 +7,6 @@
import android.graphics.Paint.Style;

import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.utils.MPPointD;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
Expand Down Expand Up @@ -115,73 +114,26 @@ public Transformer getTransformer() {
* @param min - the minimum value in the data object for this axis
* @param max - the maximum value in the data object for this axis
*/
public void computeAxis(float min, float max, boolean inverted) {
public abstract void computeAxis(float min, float max, boolean inverted);

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

MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom());

if (!inverted) {

min = (float) p2.y;
max = (float) p1.y;
} else {

min = (float) p1.y;
max = (float) p2.y;
}

MPPointD.recycleInstance(p1);
MPPointD.recycleInstance(p2);
}

computeAxisValues(min, max);
}

/**
* Sets up the axis values. Computes the desired number of labels between the two given extremes.
*
* @return
* Compute axis interval and desired number of labels between the two given extremes
* @param min
* @param max
*/
protected void computeAxisValues(float min, float max) {

float yMin = min;
float yMax = max;

int labelCount = mAxis.getLabelCount();
double range = Math.abs(yMax - yMin);

if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
mAxis.mEntries = new float[]{};
mAxis.mCenteredEntries = new float[]{};
mAxis.mEntryCount = 0;
return;
}

// Find out how much spacing (in y value space) between axis values
double rawInterval = range / labelCount;
double interval = Utils.roundToNextSignificant(rawInterval);

// If granularity is enabled, then do not allow the interval to go below specified granularity.
// This is used to avoid repeated values when rounding values for display.
if (mAxis.isGranularityEnabled())
interval = interval < mAxis.getGranularity() ? mAxis.getGranularity() : interval;

// Normalize interval
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
// if it's 0.0 after floor(), we use the old value
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
? interval
: Math.floor(10.0 * intervalMagnitude);

}
protected abstract void computeAxisInterval(float min, float max);

/**
* Setup axis entries and decimals based on the previously computed interval and labels count
* @param min
* @param max
* @param labelCount
* @param range
* @param interval
*/
protected void computeAxisValues(float min, float max, int labelCount, double range, double interval) {

int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;

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

double first = interval == 0.0 ? 0.0 : Math.ceil(yMin / interval) * interval;
double first = interval == 0.0 ? 0.0 : Math.ceil(min / interval) * interval;
if(mAxis.isCenterAxisLabelsEnabled()) {
first -= interval;
}

double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(yMax / interval) * interval);
double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(max / interval) * interval);

double f;
int i;
Expand Down Expand Up @@ -262,7 +214,7 @@ else if (last == first && n == 0) {
}
}
}

/**
* Draws the axis labels to the screen.
*
Expand Down
Expand Up @@ -45,7 +45,7 @@ public void computeAxis(float min, float max, boolean inverted) {

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

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

computeAxisValues(min, max);
computeAxisInterval(min, max);
}

@Override
protected void computeAxisValues(float min, float max) {
super.computeAxisValues(min, max);
protected void computeAxisInterval(float min, float max) {

// Compute the longest label width first
computeSize();

int labelCount = mXAxis.getLabelCount();
double range = Math.abs(max - min);

if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
mXAxis.mEntries = new float[]{};
mXAxis.mCenteredEntries = new float[]{};
mXAxis.mEntryCount = 0;
return;
}

// Find out how much spacing (in x value space) between axis values
double rawInterval = range / labelCount;
double interval = Utils.roundToNextSignificant(rawInterval);

// Do not allow the interval go below the label width with spacing.
double labelMaxWidth = (mXAxis.mLabelRotatedWidth + mXAxis.getSpaceBetweenLabelsMin()) * range / mViewPortHandler.contentWidth();
if (interval < labelMaxWidth)
interval = labelMaxWidth;

// If granularity is enabled, then do not allow the interval to go below specified granularity.
// This is used to avoid repeated values when rounding values for display.
if (mXAxis.isGranularityEnabled())
interval = interval < mXAxis.getGranularity() ? mXAxis.getGranularity() : interval;

// Perform rounding once again after interval was probably adjusted by label width and/or granularity checks.
rawInterval = interval;
interval = Utils.roundToNextSignificant(rawInterval);

// Normalize interval
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
// if it's 0.0 after floor(), we use the old value
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
? interval
: Math.floor(10.0 * intervalMagnitude);

// If rounded down to current significant, round up to avoid label overlapping
} else if (interval < rawInterval) {
interval = (intervalSigDigit + 1) * intervalMagnitude;
}

computeAxisValues(min, max, labelCount, range, interval);
}

protected void computeSize() {
Expand All @@ -91,7 +136,6 @@ protected void computeSize() {
labelHeight,
mXAxis.getLabelRotationAngle());


mXAxis.mLabelWidth = Math.round(labelWidth);
mXAxis.mLabelHeight = Math.round(labelHeight);
mXAxis.mLabelRotatedWidth = Math.round(labelRotatedSize.width);
Expand Down
Expand Up @@ -55,7 +55,7 @@ public void computeAxis(float min, float max, boolean inverted) {
MPPointD.recycleInstance(p2);
}

computeAxisValues(min, max);
computeAxisInterval(min, max);
}

@Override
Expand Down
Expand Up @@ -41,6 +41,69 @@ public YAxisRenderer(ViewPortHandler viewPortHandler, YAxis yAxis, Transformer t
}
}

@Override
public void computeAxis(float min, float max, boolean inverted) {

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

MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom());

if (!inverted) {

min = (float) p2.y;
max = (float) p1.y;
} else {

min = (float) p1.y;
max = (float) p2.y;
}

MPPointD.recycleInstance(p1);
MPPointD.recycleInstance(p2);
}

computeAxisInterval(min, max);
}

@Override
protected void computeAxisInterval(float min, float max) {

int labelCount = mYAxis.getLabelCount();
double range = Math.abs(max - min);

if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
mYAxis.mEntries = new float[]{};
mYAxis.mCenteredEntries = new float[]{};
mYAxis.mEntryCount = 0;
return;
}

// Find out how much spacing (in y value space) between axis values
double rawInterval = range / labelCount;
double interval = Utils.roundToNextSignificant(rawInterval);

// If granularity is enabled, then do not allow the interval to go below specified granularity.
// This is used to avoid repeated values when rounding values for display.
if (mYAxis.isGranularityEnabled())
interval = interval < mYAxis.getGranularity() ? mYAxis.getGranularity() : interval;

// Normalize interval
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
// if it's 0.0 after floor(), we use the old value
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
? interval
: Math.floor(10.0 * intervalMagnitude);
}

computeAxisValues(min, max, labelCount, range, interval);
}

/**
* draws the y-axis labels to the screen
*/
Expand Down
Expand Up @@ -57,7 +57,7 @@ public void computeAxis(float yMin, float yMax, boolean inverted) {
MPPointD.recycleInstance(p2);
}

computeAxisValues(yMin, yMax);
computeAxisInterval(yMin, yMax);
}

/**
Expand Down