When calling animateY
on a barChart
the entire chart is redrawn, animating the bars from y-zero to y-new.
barChart.invalidate();
barChart.animateY(1000);
Is it possible to restrict the animation to the value change. Thus allowing the user to see how the chart grows from y-old (e.g. 100) to y-new (e.g. 120)?
I was facing the same problem and couldn't find a solution. So, I've created a class that can be called to handle this kind of task.
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.data.Entry;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import android.os.Handler;
public class AnimateDataSetChanged {
private int duration;
private long startTime;
private int fps = 30;
private Handler timerHandler;
private Chart chart;
private List<Entry> oldData;
private List<Entry> newData;
private Interpolator interpolator;
public AnimateDataSetChanged(int duration, Chart chart, List<Entry> oldData, List<Entry> newData){
this.duration = duration;
this.chart = chart;
this.oldData = new ArrayList<>(oldData);
this.newData = new ArrayList<>(newData);
interpolator = new LinearInterpolator();
}
public void setInterpolator(Interpolator interpolator){
this.interpolator = interpolator;
}
public void run(int fps){
this.fps = fps;
run();
}
public void run(){
startTime = Calendar.getInstance().getTimeInMillis();
timerHandler = new Handler();
Runner runner = new Runner();
runner.run();
}
private class Runner implements Runnable{
@Override
public void run() {
float increment = (Calendar.getInstance().getTimeInMillis() - startTime) / (float)duration;
increment = interpolator.getInterpolation(increment < 0f ? 0f : increment > 1f ? 1f :increment);
chart.getData().getDataSetByIndex(0).clear();
for(int i = 0; i < newData.size(); i++){
float oldY = oldData.size() > i ? oldData.get(i).getY() : newData.get(i).getY();
float oldX = oldData.size() > i ? oldData.get(i).getX() : newData.get(i).getX();
float newX = newData.get(i).getX();
float newY = newData.get(i).getY();
Entry e = new Entry(oldX + (newX - oldX) * increment, oldY + (newY - oldY) * increment);
chart.getData().getDataSetByIndex(0).addEntry(e);
}
chart.getXAxis().resetAxisMaximum();
chart.getXAxis().resetAxisMinimum();
chart.notifyDataSetChanged();
chart.refreshDrawableState();
chart.invalidate();
if(chart instanceof BarLineChartBase){
((BarLineChartBase)chart).setAutoScaleMinMaxEnabled(true);
}
if(increment < 1f){
timerHandler.postDelayed(this, 1000/fps);
}
}
}
}
You can call the class like so:
List<Entry> oldEntries = ...
List<Entry> newEntries = ...
AnimateDataSetChanged changer = new AnimateDataSetChanged(600, mChart, oldEntries, currentDataEntries);
changer.setInterpolator(new AccelerateInterpolator()); // optionally set the Interpolator
changer.run();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With