Crash fix - Create small clip paths (#1895)
With large data sets, the Path object created was sufficiently large as to cause an OutOfMemory error. This is resolved by only pathing a limited number of points on the chart at a time, then clearing the path and resuming. Stress testing with 1500 entries.
This commit is contained in:
parent
87758604d3
commit
b5da8dcdb5
3 changed files with 64 additions and 30 deletions
|
@ -18,7 +18,7 @@
|
|||
android:layout_margin="8dp"
|
||||
android:layout_toLeftOf="@+id/tvYMax"
|
||||
android:layout_marginRight="5dp"
|
||||
android:max="200"
|
||||
android:max="150"
|
||||
android:paddingBottom="12dp" />
|
||||
|
||||
<SeekBar
|
||||
|
@ -30,7 +30,7 @@
|
|||
android:layout_marginBottom="35dp"
|
||||
android:layout_toLeftOf="@+id/tvXMax"
|
||||
android:layout_marginRight="5dp"
|
||||
android:max="500"
|
||||
android:max="1500"
|
||||
android:paddingBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -111,7 +111,7 @@ public class LineChartActivity1 extends DemoBase implements OnSeekBarChangeListe
|
|||
|
||||
Typeface tf = Typeface.createFromAsset(getAssets(), "OpenSans-Regular.ttf");
|
||||
|
||||
LimitLine ll1 = new LimitLine(130f, "Upper Limit");
|
||||
LimitLine ll1 = new LimitLine(150f, "Upper Limit");
|
||||
ll1.setLineWidth(4f);
|
||||
ll1.enableDashedLine(10f, 10f, 0f);
|
||||
ll1.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
|
||||
|
@ -129,7 +129,7 @@ public class LineChartActivity1 extends DemoBase implements OnSeekBarChangeListe
|
|||
leftAxis.removeAllLimitLines(); // reset all limit lines to avoid overlapping lines
|
||||
leftAxis.addLimitLine(ll1);
|
||||
leftAxis.addLimitLine(ll2);
|
||||
leftAxis.setAxisMaxValue(220f);
|
||||
leftAxis.setAxisMaxValue(200f);
|
||||
leftAxis.setAxisMinValue(-50f);
|
||||
//leftAxis.setYOffset(20f);
|
||||
leftAxis.enableGridDashedLine(10f, 10f, 0f);
|
||||
|
|
|
@ -449,6 +449,8 @@ public class LineChartRenderer extends LineRadarRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
protected Path mGenerateFilledPathBuffer = new Path();
|
||||
|
||||
/**
|
||||
* Draws a filled linear path on the canvas.
|
||||
*
|
||||
|
@ -459,60 +461,92 @@ public class LineChartRenderer extends LineRadarRenderer {
|
|||
*/
|
||||
protected void drawLinearFill(Canvas c, ILineDataSet dataSet, Transformer trans, XBounds bounds) {
|
||||
|
||||
Path filled = generateFilledPath(dataSet, bounds);
|
||||
final Path filled = mGenerateFilledPathBuffer;
|
||||
|
||||
trans.pathValueToPixel(filled);
|
||||
final int startingIndex = bounds.min;
|
||||
final int endingIndex = bounds.range + bounds.min;
|
||||
final int indexInterval = 128;
|
||||
|
||||
final Drawable drawable = dataSet.getFillDrawable();
|
||||
if (drawable != null) {
|
||||
int currentStartIndex = 0;
|
||||
int currentEndIndex = indexInterval;
|
||||
int iterations = 0;
|
||||
|
||||
drawFilledPath(c, filled, drawable);
|
||||
} else {
|
||||
// Doing this iteratively in order to avoid OutOfMemory errors that can happen on large bounds sets.
|
||||
do{
|
||||
currentStartIndex = startingIndex + (iterations * indexInterval);
|
||||
currentEndIndex = currentStartIndex + indexInterval;
|
||||
currentEndIndex = currentEndIndex > endingIndex ? endingIndex : currentEndIndex;
|
||||
|
||||
if(currentStartIndex <= currentEndIndex) {
|
||||
generateFilledPath(dataSet, currentStartIndex, currentEndIndex, filled);
|
||||
|
||||
|
||||
|
||||
trans.pathValueToPixel(filled);
|
||||
|
||||
final Drawable drawable = dataSet.getFillDrawable();
|
||||
if (drawable != null) {
|
||||
|
||||
drawFilledPath(c, filled, drawable);
|
||||
} else {
|
||||
|
||||
drawFilledPath(c, filled, dataSet.getFillColor(), dataSet.getFillAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
iterations++;
|
||||
|
||||
}while(currentStartIndex <= currentEndIndex);
|
||||
|
||||
drawFilledPath(c, filled, dataSet.getFillColor(), dataSet.getFillAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
protected Path mGenerateFilledPathBuffer = new Path();
|
||||
/**
|
||||
* Generates the path that is used for filled drawing.
|
||||
* Generates a path that is used for filled drawing.
|
||||
*
|
||||
* @param dataSet The dataset from which to read the entries.
|
||||
* @param startIndex The index from which to start reading the dataset
|
||||
* @param endIndex The index from which to stop reading the dataset
|
||||
* @param outputPath The path object that will be assigned the chart data.
|
||||
*
|
||||
* @param dataSet
|
||||
* @return
|
||||
*/
|
||||
private Path generateFilledPath(ILineDataSet dataSet, XBounds bounds) {
|
||||
private void generateFilledPath(final ILineDataSet dataSet, final int startIndex, final int endIndex, final Path outputPath) {
|
||||
|
||||
float fillMin = dataSet.getFillFormatter().getFillLinePosition(dataSet, mChart);
|
||||
float phaseY = mAnimator.getPhaseY();
|
||||
final float fillMin = dataSet.getFillFormatter().getFillLinePosition(dataSet, mChart);
|
||||
final float phaseY = mAnimator.getPhaseY();
|
||||
final boolean isDrawSteppedEnabled = dataSet.getMode() == LineDataSet.Mode.STEPPED;
|
||||
|
||||
Path filled = mGenerateFilledPathBuffer;
|
||||
final Path filled = outputPath;
|
||||
filled.reset();
|
||||
Entry entry = dataSet.getEntryForIndex(bounds.min);
|
||||
|
||||
final Entry entry = dataSet.getEntryForIndex(startIndex);
|
||||
|
||||
filled.moveTo(entry.getX(), fillMin);
|
||||
filled.lineTo(entry.getX(), entry.getY() * phaseY);
|
||||
|
||||
// create a new path
|
||||
for (int x = bounds.min + 1; x <= bounds.range + bounds.min; x++) {
|
||||
Entry currentEntry = null;
|
||||
Entry previousEntry = null;
|
||||
for (int x = startIndex + 1 ; x <= endIndex ; x++) {
|
||||
|
||||
Entry e = dataSet.getEntryForIndex(x);
|
||||
currentEntry = dataSet.getEntryForIndex(x);
|
||||
|
||||
if (isDrawSteppedEnabled) {
|
||||
final Entry ePrev = dataSet.getEntryForIndex(x - 1);
|
||||
if (ePrev == null) continue;
|
||||
|
||||
filled.lineTo(e.getX(), ePrev.getY() * phaseY);
|
||||
if (isDrawSteppedEnabled && previousEntry != null) {
|
||||
filled.lineTo(currentEntry.getX(), previousEntry.getY() * phaseY);
|
||||
}
|
||||
|
||||
filled.lineTo(e.getX(), e.getY() * phaseY);
|
||||
filled.lineTo(currentEntry.getX(), currentEntry.getY() * phaseY);
|
||||
|
||||
previousEntry = currentEntry;
|
||||
}
|
||||
|
||||
// close up
|
||||
filled.lineTo(dataSet.getEntryForIndex(bounds.range + bounds.min).getX(), fillMin);
|
||||
if(currentEntry != null) {
|
||||
filled.lineTo(currentEntry.getX(), fillMin);
|
||||
}
|
||||
|
||||
filled.close();
|
||||
|
||||
return filled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue