Android SimpleGraph issues with labeling and automatic x-axis scroll - android

I am working on an Android app and I have a graph of sensor readings: temp/humidity/wind plotted on Y axis, and then time/date on the X-axis. I am using the SimpleGraph library. For the most part everything works great. However, there are a 2-3 issues I've gotten stuck on.
If I specify a number for labels, such as 3 for my main screen, It won't scroll to the end, or which would be preferably, it doesn't just show 3 labels and all the data for the time specified. Instead it shows me the first three labels and cuts the data. If I try graph.getViewport().scrollToEnd(); nothing changes.
On my 'FullGraphActivity' I am still missing the last couple of hours of data...sometimes. Othertimes, it will show.
So I know I am getting the correct data points because my logs show them. I am pretty sure they are being plotted out of view. What I'd really like is to figure out how to get the data and labels to correctly plot based on my time selection. Such as day / week / month. I've included the two main classes, and an example call for the 3 labeled call.
I'm probably missing something simple. Appreciate any suggestions, comments.
Thanks!
Call from main screen with label count specified:
graphTemp = (GraphView) findViewById(R.id.graphTemp);
try {
GraphUtility gu = new GraphUtility(1,1,3,true,false, this,celsius);
gu.grapher( this,graphTemp, gu.seriesBuilder(
gu.getTempData(gu.getSixHours())));
This is where I am setting up the simple graph:
public class GraphUtility {
public int focus;
public Activity activity;
public MainActivity mainActivity;
public Context context;
Constants constants;
private final static int graphColor
Color.parseColor("#6a0c05");
private double maxYBound = 0;
private double minYBound = 999;
private int time = 0;
private int labelCount = 0;
private boolean maxy = true;
private boolean miny = true;
private boolean celsius;
public GraphUtility(int focus, int time, int labelCount,boolean maxy, boolean miny, MainActivity mainActivity, boolean celsius) {
this.focus = focus;
this.time = time;
this.labelCount = labelCount;
context = mainActivity;
this.mainActivity = mainActivity;
this.miny = miny;
this.maxy = maxy;
this.celsius = celsius;
}
public void grapher(Context context, GraphView graph, LineGraphSeries[] seriesArray){
try{
graph.removeAllSeries();
LineGraphSeries series = new LineGraphSeries();
series.clearReference(graph);
if(focus==0){
for(int i = 0; i<seriesArray.length; i++){
// series = new LineGraphSeries();
series = seriesArray[i];
series.setDrawBackground(true);
if(i == 0) {
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#8d1007"));
}
if(i == 1) {
series.setColor(Color.parseColor("#551a8b"));
series.setBackgroundColor(Color.parseColor("#551a8b"));
}
if(i == 2) {
series.setColor(Color.parseColor("#FF0008F0"));
series.setBackgroundColor(Color.parseColor("#FF0008F0"));
}
series.setDataPointsRadius(2);
series.setThickness(2);
graph.addSeries(series);
}
}
if(focus == 1){
series = seriesArray[0];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#8d1007"));
}
if(focus == 2){
series = seriesArray[1];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#8d1007"));
}
if(focus == 3){
series = seriesArray[2];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#8d1007"));
}
series.setDataPointsRadius(2);
series.setThickness(2);
graph.addSeries(series);
//graph.addSeries(series);
graph.getGridLabelRenderer().setGridColor(graphColor);
graph.getGridLabelRenderer().setHorizontalLabelsColor(graphColor);
graph.getGridLabelRenderer().setVerticalLabelsColor(graphColor);
graph.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.BOTH);
graph.getViewport().scrollToEnd();
//Add 5 percent for easier readability
if(maxy) {
graph.getViewport().setYAxisBoundsManual(true);
maxYBound = maxYBound + (maxYBound* .05);
maxYBound= 5*(Math.ceil(Math.abs(maxYBound/5)));
if(maxYBound ==0){
maxYBound=1;
}
graph.getViewport().setMaxY(maxYBound);
}
//Minus 5 percent
if(minYBound !=0) {
if(miny) {
graph.getViewport().setYAxisBoundsManual(true);
minYBound = minYBound - (minYBound * .05);
minYBound= 5*(Math.floor(Math.abs(minYBound/5)));
Log.d("BTWeather-minYval", String.valueOf(minYBound));
//TODO Empty sensors causes crash.
graph.getViewport().setMinY(minYBound);
}
}
if(labelCount > 0){
graph.getGridLabelRenderer().setNumHorizontalLabels(labelCount);
}
graph.getGridLabelRenderer().setHumanRounding(true);
// graph.getGridLabelRenderer().setTextSize(35);
graph.getGridLabelRenderer().reloadStyles();
java.text.DateFormat dateTimeFormatter = DateFormat.getTimeFormat(context);
if(time==1) {
graph.getGridLabelRenderer().setLabelFormatter(
new DateAsXAxisLabelFormatter(graph.getContext(),
dateTimeFormatter));
}else{
graph.getGridLabelRenderer().setLabelFormatter(
new DateAsXAxisLabelFormatter(graph.getContext()));
}
//
}catch(Exception e){
Log.d("BTWeather-error21", e.toString());
}
}
// TODO Graphs not advancing again showing hours behind instead of latest sensor
public LineGraphSeries[] seriesBuilder(List<Sensors> sensorsList){
LineGraphSeries[] seriesArray = new LineGraphSeries[3];
try{
DataPoint d = null;
DataPoint[] dataPoints = new DataPoint[sensorsList.size()];
DataPoint[] dataPointsH = new DataPoint[sensorsList.size()];
DataPoint[] dataPointsW = new DataPoint[sensorsList.size()];
Date date1 = new Date();
int i = 0;
Log.d("BTWeather-seriesbuilder",
" Length of sensorlist: " + String.valueOf(sensorsList.size()));
if(sensorsList.size()==0){
minYBound = 0;
}
try{
for(Sensors sensor: sensorsList){
findMaxY(sensor);
findMinY(sensor);
try {
date1 = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss").parse(sensor.getmDate());
//Log.d("BTWeather-sensorlistFG",
// String.valueOf(date1)+" - " + String.valueOf(sensor.getmTemp()) );
} catch (ParseException e) {
e.printStackTrace();
}
if( isCelsius()){
d = new DataPoint(date1, Double.valueOf(sensor.getmTemp()));
}else{
double tmp = mainActivity.cToF(Double.valueOf(sensor.getmTemp()));
// Log.d("BTWeather-seriesdump",String.valueOf(tmp));
d = new DataPoint(date1, tmp);
}
dataPoints[i]= d;
d = new DataPoint(date1, Double.valueOf(sensor.getmHumidity()));
dataPointsH[i]=d;
d = new DataPoint(date1, Double.valueOf(sensor.getmWind()));
dataPointsW[i]=d;
i++;
}
seriesArray[0] = new LineGraphSeries<>(dataPoints);
seriesArray[1] = new LineGraphSeries<>(dataPointsH);
seriesArray[2] = new LineGraphSeries<>(dataPointsW);
}catch(Exception e){
Log.d("BTWeather-error20", e.toString());
}
}catch (Exception e){
Log.d("BTWeather-error22", e.toString());
}
return seriesArray;
}
//TODO min / max not resetting propperly for days/weeks etc
public void findMaxY (Sensors sensor){
try{
//Focus passed from main activity on graph click
if(focus ==1){
if( isCelsius()) {
if (Double.valueOf(sensor.getmTemp()) > maxYBound) {
maxYBound = Double.valueOf(sensor.getmTemp());
}
}else if(mainActivity.cToF(Double.valueOf(sensor.getmTemp()))>maxYBound){
maxYBound=mainActivity.cToF(Double.valueOf(sensor.getmTemp()));
}
}
else if(focus == 2){
if( Double.valueOf(sensor.getmHumidity())> maxYBound){
maxYBound = Double.valueOf(sensor.getmHumidity());
}
}
else if(focus == 3){
if(Double.valueOf(sensor.getmWind())> maxYBound){
maxYBound = Double.valueOf(sensor.getmWind());
}
}}
catch (Exception e){
Log.d("BTWeather-error19", e.toString());
}
}
public void findMinY (Sensors sensor){
if(sensor != null) {
try {
//Focus passed from main activity on graph click
if (focus == 1) {
if (isCelsius()) {
if (Double.valueOf(sensor.getmTemp()) < minYBound) {
minYBound = Double.valueOf(sensor.getmTemp());
}
} else if (mainActivity.cToF(Double.valueOf(sensor.getmTemp())) < minYBound) {
minYBound = mainActivity.cToF(Double.valueOf(sensor.getmTemp()));
}
} else if (focus == 2) {
if (Double.valueOf(sensor.getmHumidity()) < minYBound) {
minYBound = Double.valueOf(sensor.getmHumidity());
}
} else if (focus == 3) {
if (Double.valueOf(sensor.getmWind()) < minYBound) {
minYBound = Double.valueOf(sensor.getmWind());
}
}
} catch (Exception e) {
Log.d("BTWeather-error18", e.toString());
}
}else{
minYBound=0;
}
}
//Database
public static String getYesterday(){
//return new Date(System.currentTimeMillis()-24*60*60*1000);
long day = TimeUnit.DAYS.toMillis(1);
String start= DateFormat.format("MM-dd-yyyy HH:mm:ss",
new Date(System.currentTimeMillis() - day)).toString();
return start;
}
public static String getSixHours(){
//return new Date(System.currentTimeMillis()-24*60*60*1000);
long day = TimeUnit.HOURS.toMillis(6);
String start= DateFormat.format("MM-dd-yyyy HH:mm:ss",
new Date(System.currentTimeMillis() - day)).toString();
return start;
}
public static String getWeek(){
//return new Date(System.currentTimeMillis()-24*60*60*1000);
long week = TimeUnit.DAYS.toMillis(7);
String start= DateFormat.format("MM-dd-yyyy HH:mm:ss",
new Date(System.currentTimeMillis() - week)).toString();
return start;
}
public static String getMonth(){
//return new Date(System.currentTimeMillis()-24*60*60*1000);
long month = TimeUnit.DAYS.toMillis(30);
String start= DateFormat.format("MM-dd-yyyy HH:mm:ss",
new Date(System.currentTimeMillis() - month)).toString();
return start;
}
public static Date getMeTomorrow(){
return new Date(System.currentTimeMillis());
}
public List<Sensors> getTempData(String start){
SensorsDatabase sDb = SensorsDatabase.getSensorsDatabase(context);
List<Sensors> dataPoints = null;
Date date1 = new Date();
try {
dataPoints = sDb.sensorsDao().findTempByDate(
start,
DateFormat.format("MM-dd-yyyy HH:mm:ss", getMeTomorrow()).toString());
} catch (Exception e) {
Log.d("BTWeather-error8", String.valueOf(e));
}
return dataPoints;
}
public boolean isCelsius() {
return celsius;
}
}
This activity is for full view of the graph. Here it's mostly working. However, as said above, sometimes the last couple of hours worth of data is being cut off. Say its 2:30, I'll see data & labels up to 12:30
public class FullGraphActivity extends AppCompatActivity {
GraphView graph;
private TextView mTextMessage;
private final static int graphColor = Color.parseColor("#6a0c05");
private MainActivity mainActivity;
private int focus =0;
private int time = 0;
GraphUtility gu;
private boolean celsius;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.graph_hour:
time=1;
if(focus ==1 )
mTextMessage.setText(R.string.graph_hour_temp);
if(focus ==2 )
mTextMessage.setText(R.string.graph_hour_humid);
if(focus ==3 )
mTextMessage.setText(R.string.graph_hour_wind);
try{
gu = new GraphUtility(focus,time,0,true,true,mainActivity,celsius);
gu.grapher(getApplicationContext(),graph,gu.seriesBuilder(gu.getTempData(gu.getYesterday())));
}catch(Exception e){
Log.d("BTWeather-error15", e.toString());
}
return true;
case R.id.graph_day:
time=2;
if(focus ==1 )
mTextMessage.setText(R.string.graph_day_temp);
if(focus ==2 )
mTextMessage.setText(R.string.graph_day_humid);
if(focus ==3 )
mTextMessage.setText(R.string.graph_day_wind);
try{
gu = new GraphUtility(focus,time,0,true,true,mainActivity,celsius );
gu.grapher(getApplicationContext(),graph,gu.seriesBuilder(gu.getTempData(gu.getWeek())));
}catch(Exception e){
Log.d("BTWeather-error15", e.toString());
}
return true;
case R.id.graph_week:
time=3;
if(focus ==1 )
mTextMessage.setText(R.string.graph_week_temp);
if(focus ==2 )
mTextMessage.setText(R.string.graph_week_humid);
if(focus ==3 )
mTextMessage.setText(R.string.graph_week_wind);
try{
gu = new GraphUtility(focus,time,0,true,true,mainActivity,celsius );
gu.grapher(getApplicationContext(),graph,gu.seriesBuilder(gu.getTempData(gu.getMonth())));
}catch(Exception e){
Log.d("BTWeather-error15", e.toString());
}
return true;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full_graph);
Intent mIntent = getIntent();
focus = mIntent.getIntExtra("focus", 0);
celsius = mIntent.getBooleanExtra("celsius", false);
mTextMessage = (TextView) findViewById(R.id.message);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.graphMenu);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
mainActivity = new MainActivity() ;
graph = (GraphView) findViewById(R.id.fullGraph);
// Setting the very 1st item as home screen.
navigation.setSelectedItemId(R.id.graph_hour);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home){
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Hopefully this isn't too much info. Again, any comments greatly appreciated. Full code repo if it helps.

Ok, so as usual, after deciding to post I was able to work out a solution with the help of the examples on simplegraphs doc. I thought I mirrored the date example from the doc but I had left out a key section:
// set manual x bounds to have nice steps
graph.getViewport().setMinX(start);
graph.getViewport().setMaxX(System.currentTimeMillis());
graph.getViewport().setXAxisBoundsManual(true);
For some reason I wasn't able to clear each graphs style/data correctly despite using the clear/resets provided in the API. Rather than waste too much time on it I decided to create three graphviews in my layout then hide the ones not in use. This isn't the best method, but it seems to not impact performance. See below for the code changes. Note some changes are made for style reasons.
I changed my grapher method to include the double start which is the time to start from:
Class GraphUtility
public void grapher(Context context, GraphView graph, LineGraphSeries[] seriesArray, Double start){
try{
graph.removeAllSeries();
graph.getGridLabelRenderer().resetStyles();
LineGraphSeries series = new LineGraphSeries();
series.clearReference(graph);
if(focus==0) {
for (int i = 0; i < seriesArray.length; i++) {
// series = new LineGraphSeries();
series = seriesArray[i];
series.setDrawBackground(true);
if (i == 0) {
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#4D6a0c05"));
}
if (i == 1) {
series.setColor(Color.parseColor("#00004C"));
series.setBackgroundColor(Color.parseColor("#4D00004C"));
}
if (i == 2) {
series.setColor(Color.parseColor("#006600"));
series.setBackgroundColor(Color.parseColor("#4D006600"));
}
series.setDataPointsRadius(4);
series.setThickness(4);
graph.getGridLabelRenderer().setGridColor(graphColor);
graph.getGridLabelRenderer().setHorizontalLabelsColor(graphColor);
graph.getGridLabelRenderer().setVerticalLabelsColor(graphColor);
graph.addSeries(series);
}
}
if(focus == 1){
series = seriesArray[0];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#8d1007"));
series.setBackgroundColor(Color.parseColor("#4D6a0c05"));
graph.getGridLabelRenderer().setGridColor(Color.parseColor("#8d1007"));
graph.getGridLabelRenderer().setHorizontalLabelsColor(Color.parseColor("#8d1007"));
graph.getGridLabelRenderer().setVerticalLabelsColor(Color.parseColor("#8d1007"));
series.setDataPointsRadius(2);
series.setThickness(2);
graph.addSeries(series);
}
if(focus == 2){
series = seriesArray[1];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#00004C"));
series.setBackgroundColor(Color.parseColor("#4D00004C"));
graph.getGridLabelRenderer().setGridColor(Color.parseColor("#00004C"));
graph.getGridLabelRenderer().setHorizontalLabelsColor(Color.parseColor("#00004C"));
graph.getGridLabelRenderer().setVerticalLabelsColor(Color.parseColor("#00004C"));
series.setDataPointsRadius(2);
series.setThickness(2);
graph.addSeries(series);
}
if(focus == 3){
series = seriesArray[2];
series.setDrawBackground(true);
series.setColor(Color.parseColor("#006600"));
series.setBackgroundColor(Color.parseColor("#4D006600"));
graph.getGridLabelRenderer().setGridColor(Color.parseColor("#006600"));
graph.getGridLabelRenderer().setHorizontalLabelsColor(Color.parseColor("#006600"));
graph.getGridLabelRenderer().setVerticalLabelsColor(Color.parseColor("#006600"));
series.setDataPointsRadius(2);
series.setThickness(2);
graph.addSeries(series);
}
graph.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.BOTH);
//Add 5 percent for easier readability
Log.d(Constants.LOG_TAG,"MaxY" + String.valueOf(maxYBound));
if(maxy) {
graph.getViewport().setYAxisBoundsManual(true);
maxYBound = maxYBound + (maxYBound* .05);
maxYBound= 5*(Math.ceil(Math.abs(maxYBound/5)));
if(maxYBound ==0){
maxYBound=1;
}
graph.getViewport().setMaxY(maxYBound);
}
//Minus 5 percent
Log.d(Constants.LOG_TAG,"MinY" + String.valueOf(minYBound));
if(minYBound !=0) {
if(miny) {
graph.getViewport().setYAxisBoundsManual(true);
minYBound = minYBound - (minYBound * .05);
minYBound= 5*(Math.floor(Math.abs(minYBound/5)));
Log.d("BTWeather-minYval", String.valueOf(minYBound));
graph.getViewport().setMinY(minYBound);
}
}else{
graph.getViewport().setMinY(minYBound);
}
if(labelCount > 0){
graph.getGridLabelRenderer().setNumHorizontalLabels(labelCount);
}
if(time==1) {
java.text.DateFormat dateTimeFormatter = DateFormat.getTimeFormat(context);
graph.getGridLabelRenderer().setLabelFormatter(
new DateAsXAxisLabelFormatter(graph.getContext(),
dateTimeFormatter));
}else{
graph.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(context));
}
//graph.getGridLabelRenderer().setNumHorizontalLabels(labelCount); // only 4 because of the space
// set manual x bounds to have nice steps
graph.getViewport().setMinX(start);
graph.getViewport().setMaxX(System.currentTimeMillis());
graph.getViewport().setXAxisBoundsManual(true);
// as we use dates as labels, the human rounding to nice readable numbers
// is not necessary
graph.getGridLabelRenderer().setHumanRounding(false);
//graph.getGridLabelRenderer().reloadStyles();
}catch(Exception e){
Log.d("BTWeather-error21", e.toString());
}
}
Class FullGraphActivity: Only changes needed were for the grapher call and for hiding/showing the correct view depending on the time call.
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.graph_hour:
time=1;
if(focus==0) {
getSupportActionBar().setTitle(R.string.AllHourly);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph2);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph3);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph);
graph.setVisibility(View.VISIBLE);
gu = new GraphUtility(focus, time, 6, true, true, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getYesterday())),gu.getYesterdayDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}else {
if (focus == 1)
getSupportActionBar().setTitle(R.string.graph_hour_temp);
if (focus == 2)
getSupportActionBar().setTitle(R.string.graph_hour_humid);
if (focus == 3)
getSupportActionBar().setTitle(R.string.graph_hour_wind);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph2);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph3);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph);
graph.setVisibility(View.VISIBLE);
graph.getGridLabelRenderer().resetStyles();
graph.removeAllSeries();
gu = new GraphUtility(focus, time, 6, true, true, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getYesterday())),gu.getYesterdayDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}
return true;
case R.id.graph_day:
time=2;
if(focus==0){
getSupportActionBar().setTitle(R.string.AllDaily);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph3);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph2);
graph.setVisibility(View.VISIBLE);
graph.getGridLabelRenderer().resetStyles();
graph.removeAllSeries();
gu = new GraphUtility(focus, time, 7, true, true, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getWeek())),gu.getWeekDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}else {
if (focus == 1)
getSupportActionBar().setTitle(R.string.graph_day_temp);
if (focus == 2)
getSupportActionBar().setTitle(R.string.graph_day_humid);
if (focus == 3)
getSupportActionBar().setTitle(R.string.graph_day_wind);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph3);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph2);
graph.setVisibility(View.VISIBLE);
graph.getGridLabelRenderer().resetStyles();
graph.removeAllSeries();
gu = new GraphUtility(focus, time, 7, true, true, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getWeek())),gu.getWeekDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}
return true;
case R.id.graph_week:
time=3;
if(focus==0){
getSupportActionBar().setTitle(R.string.AllWeekly);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph2);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph3);
graph.setVisibility(View.VISIBLE);
graph.getGridLabelRenderer().resetStyles();
graph.removeAllSeries();
gu = new GraphUtility(focus, time, 8, false, false, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getMonth())),gu.getMonthDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}else {
if (focus == 1)
getSupportActionBar().setTitle(R.string.graph_week_temp);
if (focus == 2)
getSupportActionBar().setTitle(R.string.graph_week_humid);
if (focus == 3)
getSupportActionBar().setTitle(R.string.graph_week_wind);
try {
GraphView graph2;
graph2 = (GraphView) findViewById(R.id.fullGraph);
graph2.setVisibility(View.INVISIBLE);
graph2 = (GraphView) findViewById(R.id.fullGraph2);
graph2.setVisibility(View.INVISIBLE);
GraphView graph;
graph = (GraphView) findViewById(R.id.fullGraph3);
graph.getGridLabelRenderer().resetStyles();
graph.removeAllSeries();
graph.setVisibility(View.VISIBLE);
gu = new GraphUtility(focus, time, 8, true, true, mainActivity, celsius);
gu.grapher(getApplicationContext(), graph, gu.seriesBuilder(gu.getTempData(gu.getMonth())),gu.getMonthDouble());
} catch (Exception e) {
Log.d("BTWeather-error15", e.toString());
}
}
return true;
}
return false;
}
};
If I find a solution to the multiple views I'll edit this post in case it's useful for someone in the future.
Best,
James

Related

How to get entries to match xAxis values MP line chart, Android

I am struggling to get a line chart correctly. I have data in Firestore database and from there I am trying to display temperature readings in a line chart. I am using the latest version of Mp line chart. I am trying to get the temperature values in Celsius to YAxis and the time in HH:mm format to the xAxis. I have tried this in mane ways and googled different ways to do this and I just can't get it right. Either the values don't show at all or the values show but in the wrong spot of the xAxis. also I can't get the yAxis showing correctly. Someone has asked about that here already and the answer was to put the ofset "60, 0 50, 60" but that don't work for me.
For the main issue I am currently trying to use the HourAxisValueFormatter which was instructed in GitHub. There is documentation of it but I can't understand how to get it working. I am new to Android an To Mp library so that is why it is difficult.
Below my activity code and the HourAxisValueFormatter
public class TempHistoryActivity extends AppCompatActivity {
private LineChart mChart;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private ArrayList<Integer> tempItemList;
private ArrayList<Long> timeList, convertedTimes;
private ArrayList<Date> dateList;
private Long reference;
private CollectionReference collectionReference = db.collection("whtitem");
private Toolbar toolbar;
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener authStateListener;
private FirebaseUser user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temp_history);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
firebaseAuth = FirebaseAuth.getInstance();
user = firebaseAuth.getCurrentUser();
tempItemList = new ArrayList<>();
timeList = new ArrayList<>();
dateList = new ArrayList<>();
convertedTimes = new ArrayList<>();
mChart = findViewById(R.id.tempLineChart);
mChart.setTouchEnabled(true);
mChart.setPinchZoom(true);
Marker mv = new Marker(getApplicationContext(), R.layout.custom_marker_view);
mv.setChartView(mChart);
mChart.setMarker(mv);
mChart.setViewPortOffsets(60, 0, 50, 90);
mChart.setExtraLeftOffset(40);
retrieveDayDataFromDatabase();
}
private void retrieveDayDataFromDatabase() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date currentDate = calendar.getTime();
Calendar cals = Calendar.getInstance();
cals.add(Calendar.DAY_OF_YEAR, +1);
Date tomorrow = cals.getTime();
collectionReference.whereEqualTo("userId", WhtApi.getInstance()
.getUserId())
.orderBy("date", Query.Direction.ASCENDING)
.startAt(currentDate)
.endAt(tomorrow)
.get()
.addOnSuccessListener(queryDocumentSnapshots -> {
if (!queryDocumentSnapshots.isEmpty()){
dateList.clear();
tempItemList.clear();
for (QueryDocumentSnapshot whtitems : queryDocumentSnapshots) {
WhtItem whtItem = whtitems.toObject(WhtItem.class);
dateList.add(whtItem.getDate());
tempItemList.add(whtItem.getTemperature());
Log.d("temps", "retrieveDayDataFromDatabase: " + tempItemList);
}
Calendar cal = Calendar.getInstance();
for (int i = 0; i < dateList.size(); i++){
Date date = dateList.get(i);
Long time = Long.valueOf(date.getTime());
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
//String time = DateFormat.format("HH:mm", dateList.get(i)).toString();
/* cal.setTime(dateList.get(i));
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
String t = hour +":"+minute+0;
Log.d("st", "retrieveDayDataFromDatabase: " + t);
DecimalFormatSymbols symbol = new DecimalFormatSymbols();
symbol.setDecimalSeparator(':');
DecimalFormat decimalFormat = new DecimalFormat("0.##");
NumberFormat format = NumberFormat.getInstance(Locale.US);
format.setMaximumFractionDigits(3);
format.setMinimumFractionDigits(3);
float time = 0;
try {
time = decimalFormat.parse(t).floatValue();
Log.d("timef", "retrieveDayDataFromDatabase: " + time);
} catch (ParseException e) {
e.printStackTrace();
}
Float newValue = new Float(format.format(time));
BigDecimal decimal = new BigDecimal(t).setScale(2);
Log.d("decimal", "retrieveDayDataFromDatabase: " + decimal);*/
timeList.add(time);
}
renderDayData();
}else {
Toast.makeText(TempHistoryActivity.this, "Ei lämpötilakirjauksia vielä", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(e -> Toast.makeText(TempHistoryActivity.this, "Tapahtui virhe dataa haettaessa", Toast.LENGTH_SHORT).show());
}
public void renderDayData() {
Collections.sort(timeList);
for (int i = 0; i<timeList.size(); i++){
reference = timeList.get(0);
Long Xnew = (timeList.get(1)) - reference;
convertedTimes.add(Xnew);
Log.d("converted", "renderDayData: "+ convertedTimes);
}
LimitLine llXAxis = new LimitLine(10f, "Index 10");
llXAxis.setLineWidth(4f);
llXAxis.enableDashedLine(10f, 10f, 0f);
llXAxis.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);
llXAxis.setTextSize(10f);
XAxis xAxis = mChart.getXAxis();
xAxis.setValueFormatter(new HourAxisValueFormatter(reference));
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.enableGridDashedLine(10f, 10f, 0f);
xAxis.setAxisMinimum(0f);
xAxis.setAxisMaximum(10f);
xAxis.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
xAxis.setGranularity(1f);
xAxis.setDrawLimitLinesBehindData(true);
LimitLine ll1 = new LimitLine(33f, "Lämpöraja 33°C");
ll1.setLineWidth(4f);
ll1.enableDashedLine(10f, 10f, 0f);
ll1.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);
ll1.setTextSize(15f);
ll1.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.setValueFormatter(new IndexAxisValueFormatter(getTemperature()));
leftAxis.enableGridDashedLine(10f, 10f, 0f);
leftAxis.removeAllLimitLines();
leftAxis.addLimitLine(ll1);
leftAxis.setDrawZeroLine(false);
leftAxis.setAxisMinimum(0f);
leftAxis.setAxisMaximum(100f);
leftAxis.setDrawLimitLinesBehindData(false);
leftAxis.setDrawGridLines(true);
leftAxis.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
mChart.getAxisRight().setEnabled(false);
mChart.invalidate();
setDayData();
}
public ArrayList<String> getDate(){
ArrayList<String> label = new ArrayList<>();
for(int i=0; i<dateList.size(); i++){
String date = DateFormat.format("dd.MM.", dateList.get(i)).toString();
label.add(date);
}return label;
}
public ArrayList<String> getTime(){
ArrayList<String> times = new ArrayList<>();
for(int i=0; i<values.length; i++){
times.add( values[i]);
}return times;
}
public ArrayList<String> getTemperature(){
ArrayList<String> temps = new ArrayList<>();
for(int i=0; i < tempItemList.size(); i++){
String temp = tempItemList.get(i) + "°C";
temps.add(temp);
Log.d("templist", "getTemperature: " + temps);
}return temps;
}
private void setDayData() {
ArrayList<Entry> values = new ArrayList<>();
values.clear();
for (int i =0 ; i < timeList.size(); i++){
values.add(new Entry(i, tempItemList.get(i)));
Log.d("list", "setDayData: " + timeList.get(i));
Log.d("values", "setData: " + values);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Collections.sort(values, new EntryXComparator());
}
LineDataSet set1;
if (mChart.getData() != null &&
mChart.getData().getDataSetCount() > 0) {
set1 = (LineDataSet) mChart.getData().getDataSetByIndex(0);
set1.setValues(values);
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
} else {
set1 = new LineDataSet(values, "Lämpötiladata");
set1.setDrawIcons(false);
set1.enableDashedLine(10f, 5f, 0f);
set1.enableDashedHighlightLine(10f, 5f, 0f);
set1.setColor(ContextCompat.getColor(this, R.color.colorPrimary));
set1.setCircleColor(ContextCompat.getColor(this, R.color.colorPrimary));
set1.setLineWidth(1f);
set1.setCircleRadius(3f);
set1.setDrawCircleHole(false);
set1.setValueTextSize(9f);
set1.setDrawFilled(true);
set1.setFormLineWidth(1f);
set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
set1.setFormSize(15.f);
if (Utils.getSDKInt() >= 18) {
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.gradient);
set1.setFillDrawable(drawable);
} else {
set1.setFillColor(ContextCompat.getColor(this, R.color.colorPrimary));
}
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
LineData data = new LineData(dataSets);
mChart.setData(data);
Description description = new Description();
description.setText("");
mChart.setDescription(description);
mChart.invalidate();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.profile:
if (user != null && firebaseAuth != null) {
startActivity(new Intent(TempHistoryActivity.this, ProfileActivity.class));
//finish();
}
break;
case R.id.mainpage:
if (user != null && firebaseAuth != null) {
startActivity(new Intent(TempHistoryActivity.this, MainPageActivity.class));
//finish();
}
break;
case R.id.temp_history:
if (user != null && firebaseAuth != null) {
startActivity(new Intent(TempHistoryActivity.this, TempHistoryActivity.class));
//finish();
}
break;
case R.id.pulse_history:
if (user != null && firebaseAuth!=null) {
startActivity(new Intent(TempHistoryActivity.this, PulseHistoryActivity.class));
//finish();
}
break;
case R.id.time_in_temp_history:
if (user != null && firebaseAuth != null) {
startActivity(new Intent(TempHistoryActivity.this, TimeTempActivity.class));
//finish();
}
break;
case R.id.action_signout:
//signout
if (user != null && firebaseAuth != null) {
firebaseAuth.signOut();
startActivity(new Intent(TempHistoryActivity.this, MainActivity.class));
//finish();
}
break;
}
return super.onOptionsItemSelected(item);
}
}
public class HourAxisValueFormatter extends ValueFormatter
{
private long referenceTimestamp; // minimum timestamp in your data set
private DateFormat mDataFormat;
private Date mDate;
public HourAxisValueFormatter(long referenceTimestamp) {
this.referenceTimestamp = referenceTimestamp;
this.mDataFormat = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
this.mDate = new Date();
}
#Override
public String getFormattedValue(float value){
// convertedTimestamp = originalTimestamp - referenceTimestamp
long convertedTimestamp = (int) value;
// Retrieve original timestamp
long originalTimestamp = referenceTimestamp + convertedTimestamp;
// Convert timestamp to hour:minute
return getHour(originalTimestamp);
}
public int getDecimalDigits()
{
return 0;
}
private String getHour(long timestamp){
try{
mDate.setTime(timestamp*1000);
return mDataFormat.format(mDate);
}
catch(Exception ex){
return "xx";
}
}
}
Here is my output atm
output
and this is what I am trying to get
enter image description here
I want the xAxis values to be "07:00, 08:00, 09:00, 10:00, 11:00, 12:00, 13:00, 14:00, 15:00, 16:00, 17:00"

android Animating markers every x sec

I am moving markers every 1 Seconds on map and this works (I am getting CarList every 1 sec from API call)
//Inside CarList there is carname which serves as id
void updateCarsLocation(final List<GeoPosition> CarList) {
//Remove old markers
if (carMarkers != null){
for (Marker marker : carMarkers) {
marker.remove();
}
}
carMarkers.clear();
if (CarList != null) {
for (GeoPosition car : CarList) {
//Rotate Car
Bitmap myImg = BitmapFactory.decodeResource(getResources(), R.drawable.car);
Matrix matrix = new Matrix();
matrix.postRotate(car.bearing);
Bitmap rotated = Bitmap.createBitmap(myImg, 0, 0, myImg.getWidth(), myImg.getHeight(),
matrix, true);
//From Bitmap
MarkerOptions markerOptions = new MarkerOptions();
LatLng latLng = new LatLng(car.lat, car.lng);
markerOptions.position(latLng);
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(rotated));
Marker cMarker = mMap.addMarker(markerOptions);
carMarkers.add(cMarker);
}
}
}
But i would like this movements to be animated (smooth) i have searched SO for some help and found couple links
Animate markers 1
Animate markers 2
But i just can't figure out how to do this, I taught about putting Markers + Cars in Hashmap<Marker, GeoPosition> and check new GeoPosition with Old by carname (id) then use animate, but i haven't still managed to get that working.
I have implemented this from a long time i will post my solution but make sure you read and understand what i am doing
private Emitter.Listener onNewDriversOnMap = new Emitter.Listener() {
#Override
public void call(final Object... args) {
final JSONObject receivedDrivers = (JSONObject) args[0];
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (!BusyParsingDrivers) {
BusyParsingDrivers = true;
new Parse_NearbyDrivers_Task(receivedDrivers).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Log.e("receivedDrivers", receivedDrivers.toString());
}
}
});
}
};
private ArrayList<Marker> existingMapMarkers = new ArrayList<>();
private boolean noNearby = false;
private boolean BusyParsingDrivers = false;
private List<Driver> driverList = new ArrayList<>();
private GoogleMap map;
/**
* Parse the new drivers list
**/
public class Parse_NearbyDrivers_Task extends AsyncTask<Void, Void, Integer>
{
JSONObject receivedDrivers;
List<Driver> newDrivers = new ArrayList<>();
List<Driver> oldDriversMoved = new ArrayList<>();
List<Driver> removedDrivers = new ArrayList<>();
public Parse_NearbyDrivers_Task(JSONObject receivedDrivers)
{
this.receivedDrivers = receivedDrivers;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... params)
{
try
{
//Get the status object from the received JSONObject
JSONObject status = receivedDrivers.getJSONObject("Status");
//Get the status code
int status_code = Integer.parseInt(status.getString("Status"));
//Here we define a switch to handle the values of the status code and return an integer after some work to filter the drivers
switch (status_code) {
case 0: //The list is not empty
{
JSONArray nearbyDrivers = receivedDrivers.getJSONArray("NearbyDrivers");
if (driverList.isEmpty()) //If the driversList is empty
{
//Iterate over all the new drivers and add them to the driverList and return 0
for (int i = 0; i < nearbyDrivers.length(); ++i) {
Driver tempDriver = new Driver();
tempDriver.id = Integer.parseInt(nearbyDrivers.getJSONObject(i).getString("pkDriverId"));
tempDriver.longitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Longitude"));
tempDriver.latitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Latitude"));
tempDriver.altitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Altitude"));
tempDriver.angle = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Angle"));
tempDriver.speed = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Speed"));
tempDriver.accuracy = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Accuracy"));
tempDriver.distanceCovered = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("DistanceCovered"));
tempDriver.carType = Integer.parseInt(nearbyDrivers.getJSONObject(i).getString("CarTypeCode"));
driverList.add(tempDriver);
}
return 0;
} else //If the driversList is not empty
{
//Iterate over the received list and if the list contain a new driver then add it to the newDrivers
// but if it contain an already added driver but with different coordinates then add this driver to
// the oldDriversMoved to later move this driver to the new coordinates
for (int i = 0; i < nearbyDrivers.length(); i++) {
Driver tempDriver = new Driver();
tempDriver.id = Integer.parseInt(nearbyDrivers.getJSONObject(i).getString("pkDriverId"));
tempDriver.longitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Longitude"));
tempDriver.latitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Latitude"));
tempDriver.altitude = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Altitude"));
tempDriver.angle = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Angle"));
tempDriver.speed = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Speed"));
tempDriver.accuracy = Float.parseFloat(nearbyDrivers.getJSONObject(i).getString("Accuracy"));
tempDriver.distanceCovered = Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("DistanceCovered"));
tempDriver.carType = Integer.parseInt(nearbyDrivers.getJSONObject(i).getString("CarTypeCode"));
if (!isDriverAlreadyExists(driverList, nearbyDrivers.getJSONObject(i).getInt("pkDriverId"))) {
newDrivers.add(tempDriver);
} else {
for (int j = 0; j < driverList.size(); ++j) {
if (nearbyDrivers.getJSONObject(i).getInt("pkDriverId") == driverList.get(j).id) {
if (Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Longitude")) != driverList.get(j).longitude || Double.parseDouble(nearbyDrivers.getJSONObject(i).getString("Latitude")) != driverList.get(j).latitude) {
oldDriversMoved.add(tempDriver);
}
}
}
}
}
//If a driver is no more existing then add it to the removedDrivers List
for (int j = 0; j < driverList.size(); j++) {
if (!isDriverAlreadyExists(nearbyDrivers, driverList.get(j).id)) {
removedDrivers.add(driverList.get(j));
}
}
//return 1 to be handled in the onPostExecute
return 1;
}
}
case 1: //The list is empty
case 500: //The list is empty
return 2;
default: //Some error
return -1;
}
} catch (JSONException e) {
return -2;
}
}
#Override
protected void onPostExecute(Integer status)
{
super.onPostExecute(status);
try {
//According to what is received from the doInBackground make some actions that will affect the markers of the drivers
switch (status) {
case 0:
noNearby = false;
Plant_NearbyDrivers();
//helper_methods.Debug("Arrays sizes","DriverList:"+driverList.size()+" Existing map markers: "+existingMapMarkers.size());
break;
case 1:
noNearby = false;
Add_Remove_Move_Drivers(removedDrivers, oldDriversMoved, newDrivers);
break;
case 2:
Remove_AllDriverFromMap();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
BusyParsingDrivers = false;
}
}
/**
* This method is called after receiving the drivers list and filtering this list according to new,removed,moved drivers to handle these actions
**/
private void Add_Remove_Move_Drivers(List<Driver> removedDrivers, List<Driver> oldDriversMoved, List<Driver> newDrivers)
{
//Get the icon that will be used to add the new drivers
BitmapDescriptor icon = getCarIcon();
ArrayList<ObjectAnimator> objectAnimatorsArray = new ArrayList<>();
ObjectAnimator[] objectAnimators;
TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
#Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
return new LatLngInterpolator.Spherical().interpolate(fraction, startValue, endValue);
}
};
//Iterate the removedDrivers list to see the matching drivers in the driversList and remove it
for (int i = 0; i < removedDrivers.size(); ++i) {
for (int j = 0; j < driverList.size(); ++j) {
//When Ids match then remove from the existingMapMarkers list and driversList
if (removedDrivers.get(i).id == driverList.get(j).id) {
driverList.remove(j);
existingMapMarkers.get(j).remove();
existingMapMarkers.remove(j);
}
}
}
//Iterate the oldDriversMoved List to get the matching in the driversList and update it and move it according to the new coordinates
for (int i = 0; i < oldDriversMoved.size(); ++i) {
for (int j = 0; j < driverList.size(); ++j) {
//When we get the match update the driver in driversList and move it to the new LatLang
if (oldDriversMoved.get(i).id == driverList.get(j).id) {
LatLng newDriverLatLng = new LatLng(oldDriversMoved.get(i).latitude, oldDriversMoved.get(i).longitude);
float desiredRotation = oldDriversMoved.get(i).angle;
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(existingMapMarkers.get(j), "rotation", existingMapMarkers.get(j).getRotation(), desiredRotation);
rotationAnimator.setDuration(1500);
objectAnimatorsArray.add(rotationAnimator);
Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
ObjectAnimator directionAnimator = ObjectAnimator.ofObject(existingMapMarkers.get(j), property, typeEvaluator, newDriverLatLng);
directionAnimator.setDuration(3000);
objectAnimatorsArray.add(directionAnimator);
objectAnimators = objectAnimatorsArray.toArray(new ObjectAnimator[objectAnimatorsArray.size()]);
AnimatorSet animDrivers = new AnimatorSet();
animDrivers.playTogether(objectAnimators);
animDrivers.start();
int position = driverList.indexOf(driverList.get(j));
driverList.remove(position);
driverList.add(position, oldDriversMoved.get(i));
}
}
}
//Iterate the newDrivers List to add them as markers and to the driversList
for (int i = 0; i < newDrivers.size(); ++i) {
LatLng newDriverLatLng = new LatLng(newDrivers.get(i).latitude, newDrivers.get(i).longitude);
driverList.add(newDrivers.get(i));
existingMapMarkers.add(map.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(newDriverLatLng).icon(icon)));
}
}
/**
* Remove all the drivers from the map
**/
public void Remove_AllDriverFromMap()
{
//Iterate all the drivers markers and remove them
for (int i = 0; i < existingMapMarkers.size(); ++i) {
existingMapMarkers.get(i).remove();
}
//Clear the arrays and set noNearby to true
noNearby = true;
driverList.clear();
existingMapMarkers.clear();
}
/**
* This method is called when there is no drivers visible on the map and we receive a list of drivers so we plant them right away
**/
private void Plant_NearbyDrivers()
{
try {
BitmapDescriptor icon = getCarIcon();
for (int i = 0; i < driverList.size(); i++) {
LatLng newDriverLatLng = new LatLng(driverList.get(i).latitude, driverList.get(i).longitude);
existingMapMarkers.add(map.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(newDriverLatLng).icon(icon)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Called to compare if the new drivers received is contained in the old driver list
**/
public boolean isDriverAlreadyExists(List<Driver> array, int driverId)
{
for (int c = 0; c < array.size(); c++) {
Driver current = array.get(c);
if (current.id == driverId)
return true;
}
return false;
}
/**
* Called to compare if the old drivers list is contained in the new drivers list
**/
public boolean isDriverAlreadyExists(JSONArray nearbyDrivers, int driverId)
{
for (int c = 0; c < nearbyDrivers.length(); c++) {
try {
JSONObject current = nearbyDrivers.getJSONObject(c);
if (current.getInt("pkDriverId") == driverId)
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* Get the icon of the car to be displayed according to the selected filter
**/
public BitmapDescriptor getCarIcon()
{
BitmapDescriptor icon = null;
//make the icon as you want
return icon;
}
add this to your build
compile 'com.nineoldandroids:library:2.4.0'

Using AlertDialog.Builder to build custom AlertDialog class

I have a Class FoodDialog that extends AlertDialog that I have customized to how I would like it to look.
I am now wanting to edit the positive/negative buttons using an AlertDialog.Builder, however, when I attempt to build an instance of FoodDialog using a builder, I am facing an 'Incompatible types' error where the builder is asking for AlertDialog instead I am providing it with an extension of AlertDialog - is there a way around this?
If not, is there a way I can edit the positive/negative buttons of my custom AlertDialog class FoodDialog?
Below is my FoodDialog class. The yes/no buttons I have there are ones I have created myself, but I would like the ones that are part of the AlertDialog.Builder to appear instead as these buttons get pushed out of sight when the soft keyboard appears:
public class FoodDialog extends AlertDialog implements OnClickListener {
private TextView foodNameTextView, foodDescTextView, foodPortionTextView, catTextView, qtyText, cal, fat, sFat, carb, sug, prot, salt, imageTxt,
measureText;
private EditText foodQty;
private ImageView foodImage;
private ImageButton yesBtn, noBtn;
private int foodID, totalCal;
private Bitmap image;
private String user, portionType, foodName, foodDesc, cat, totalCalString, totalFatString,
totalSFatString, totalCarbString, totalSugString, totalProtString, totalSaltString, portionBaseString;
private double totalFat, totalSFat, totalCarb, totalSug, totalProt, totalSalt, portionBase;
private Food food;
private Portion portion;
private Nutrients nutrients;
private PortionType pType;
private DBHandler db;
public FoodDialog(Context context){
super(context);
}
public FoodDialog(Context context, int foodID, String imgLocation, final String user) {
super(context, android.R.style.Theme_Holo_Light_Dialog);
this.setTitle("Confirm?");
setContentView(R.layout.dialog_layout);
this.foodID = foodID;
this.user = user;
db = new DBHandler(context);
food = db.getFoodByID(foodID, user);
portion = db.getPortionByFoodID(foodID);
nutrients = db.getNutrientsByFoodIDAndPortionType(foodID, portion.getPortionType());
pType = db.getPortionTypeByName(portion.getPortionType());
//getting object attributes
portionType = portion.getPortionType();
portionBase = portion.getPortionBase();
//food
foodName = food.getName();
foodDesc = food.getDesc();
cat = food.getCat();
//nutrients
totalCal = nutrients.getCal();
totalFat = nutrients.getFat();
totalSFat = nutrients.getSFat();
totalCarb = nutrients.getCarb();
totalSug = nutrients.getSug();
totalProt = nutrients.getProt();
totalSalt = nutrients.getSalt();
//converting to string
totalCalString = String.valueOf(totalCal);
if (totalFat % 1 == 0) {
totalFatString = String.format("%.0f", totalFat);
} else {
totalFatString = String.valueOf(totalFat);
}
if (totalSFat % 1 == 0) {
totalSFatString = String.format("%.0f", totalSFat);
} else {
totalSFatString = String.valueOf(totalSFat);
}
if (totalCarb % 1 == 0) {
totalCarbString = String.format("%.0f", totalCarb);
} else {
totalCarbString = String.valueOf(totalCarb);
}
if (totalSug % 1 == 0) {
totalSugString = String.format("%.0f", totalSug);
} else {
totalSugString = String.valueOf(totalSug);
}
if (totalProt % 1 == 0) {
totalProtString = String.format("%.0f", totalProt);
} else {
totalProtString = String.valueOf(totalProt);
}
if (totalSalt % 1 == 0) {
totalSaltString = String.format("%.0f", totalSalt);
} else {
totalSaltString = String.valueOf(totalSalt);
}
if (portionBase % 1 == 0) {
portionBaseString = String.format("%.0f", portionBase);
} else {
portionBaseString = String.valueOf(portionBase);
}
//textviews
foodNameTextView = (TextView) findViewById(R.id.dialogName);
foodNameTextView.setText(foodName);
foodDescTextView = (TextView) findViewById(R.id.dialogDesc);
foodDescTextView.setText(foodDesc);
foodPortionTextView = (TextView) findViewById(R.id.dialogPortion);
foodPortionTextView.setText("Values based per " + portionBase + " " + portionType);
catTextView = (TextView) findViewById(R.id.dialogCat);
catTextView.setText(cat);
measureText = (TextView) findViewById(R.id.dialogMeasure);
measureText.setText(portionType);
qtyText = (TextView) findViewById(R.id.dialogQtyText);
imageTxt = (TextView) findViewById(R.id.dialogImageText);
cal = (TextView) findViewById(R.id.dialogCal);
cal.setText(totalCalString);
fat = (TextView) findViewById(R.id.dialogFat);
fat.setText(totalFatString + "g");
sFat = (TextView) findViewById(R.id.dialogSFat);
sFat.setText(totalSFatString + "g");
carb = (TextView) findViewById(R.id.dialogCarb);
carb.setText(totalCarbString + "g");
sug = (TextView) findViewById(R.id.dialogSug);
sug.setText(totalSugString + "g");
prot = (TextView) findViewById(R.id.dialogProt);
prot.setText(totalProtString + "g");
salt = (TextView) findViewById(R.id.dialogSalt);
salt.setText(totalSaltString + "g");
//img
foodImage = (ImageView) findViewById(R.id.dialogImage);
imgLocation = food.getImgURL();
image = BitmapFactory.decodeFile(imgLocation);
foodImage.setImageBitmap(image);
if (imgLocation.equals("nourl")) {
imageTxt.setText("No Image");
}
//edit tex
foodQty = (EditText) findViewById(R.id.dialogQty);
//adjusting edittext
foodQty.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
foodQty.setFilters(new InputFilter[]{
new DigitsKeyListener(Boolean.FALSE, Boolean.TRUE) {
int beforeDecimal = 4, afterDecimal = 3;
#Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
String temp = foodQty.getText() + source.toString();
if (temp.equals(".")) {
return "0.";
} else if (temp.toString().indexOf(".") == -1) {
// no decimal point placed yet
if (temp.length() > beforeDecimal) {
return "";
}
} else {
temp = temp.substring(temp.indexOf(".") + 1);
if (temp.length() > afterDecimal) {
return "";
}
}
return super.filter(source, start, end, dest, dstart, dend);
}
}
});
foodQty.setText(portionBaseString);
//btns
yesBtn = (ImageButton) findViewById(R.id.yesBtn);
noBtn = (ImageButton) findViewById(R.id.noBtn);
Bitmap tick = BitmapFactory.decodeResource(context.getResources(),
R.drawable.png_tick);
Bitmap cross = BitmapFactory.decodeResource(context.getResources(),
R.drawable.png_cross);
yesBtn.setImageBitmap(tick);
noBtn.setImageBitmap(cross);
yesBtn.setOnClickListener(this);
noBtn.setOnClickListener(this);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
#Override
public void onClick(View v) {
if (v == yesBtn) {
SimpleDateFormat currentDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat currentTime = new SimpleDateFormat("HH:mm:ss");
String date = currentDate.format(new Date());
String time = currentTime.format(new Date());
double qty = 0;
//get quantity amount
// if (portionMeasure.equals("singles")) {
//qty = foodQty.getValue();
// } else {
if (foodQty.getText().length() != 0) {
qty = Double.valueOf(foodQty.getText().toString());
} else {
qty = 0;
}
// }
if (qty == 0 || String.valueOf(qty) == "") {
Toast.makeText(getContext(), "Please enter an amount", Toast.LENGTH_SHORT).show();
} else {
//create new intake
Intake intake = new Intake(0, foodID, portionType, qty, date, time);
//record it and increment food used value
db.recordIntake(intake, user);
db.incrementUsedCount(intake.getFoodID(), 1);
db.close();
cancel();
Toast.makeText(getContext(), foodName + " recorded", Toast.LENGTH_SHORT).show();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("What next?");
builder.setItems(new CharSequence[]
{"Record another food intake..", "Main Menu..", "View Stats.."},
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// The 'which' argument contains the index position
// of the selected item
switch (which) {
case 0:
cancel();
break;
case 1:
Intent main = new Intent(getContext(), ProfileActivity.class);
getContext().startActivity(main);
break;
case 2:
Intent stats = new Intent(getContext(), StatsActivity.class);
getContext().startActivity(stats);
break;
}
}
});
AlertDialog choose = builder.create();
choose.show();
}
} else if (v == noBtn) {
cancel();
}
}
}
You can catch your buttons click listener as follows:
yesBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//yes button click code here
}
});
noBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//no button click code here
}
});
You can use the logcat to see if your listener are being fired.

AndroidPieChart will not show

This is my XML :
<net.kenyang.piechart.PieChart
android:id="#+id/pieChart"
android:layout_below="#id/id_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
This is the code that I use for the piechart to be initialised:
ArrayList<PieChartData> alPercentage = new ArrayList<PieChartData>();
alPercentage.add(new PieChartData(55.0f, "1"));
alPercentage.add(new PieChartData(45.0f, "2"));
try {
// setting data
pieChart.setAdapter(alPercentage);
// setting a listener
pieChart.setOnSelectedListener(new PieChart.OnSelectedLisenter() {
#Override
public void onSelected(int iSelectedIndex) {
Toast.makeText(PSTravelStatisticsActivity.this, "Select index:" + iSelectedIndex, Toast.LENGTH_SHORT).show();
}
});
pieChart.setVisibility(View.VISIBLE);
pieChart.invalidate();
} catch (Exception e) {
Log.i("","error is : " + e.getMessage());
if (e.getMessage().equals(PieChart.ERROR_NOT_EQUAL_TO_100)){
Log.e("kenyang", "percentage is not equal to 100");
}
}
Now it doesn't give me an error
If I try making it in such a way that the percentage is less than 100, but then it throws an exception. So that means that with this logic, it should work, it does send me 2 logs, but thats it:
10-08 16:10:11.556 12591-12591/nl.hgrams.passenger I/net.kenyang.piechart.PieChart﹕ PieChart init
10-08 16:10:11.626 12591-12591/nl.hgrams.passenger I/net.kenyang.piechart.PieChart﹕ onDraw
Did it like this and it worked then:
final PieRenderer pieRenderer = pieChart.getRenderer(PieRenderer.class);
pieRenderer.setDonutSize((float) 75 / 100, PieRenderer.DonutMode.PERCENT);
selectDataType();
pieChart.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(pieRenderer.getContainingSegment(new PointF(event.getX(), event.getY())) == bikeS){
segment = 0;
selectSegment(segment, true);
}
if(pieRenderer.getContainingSegment(new PointF(event.getX(), event.getY())) == carS){
segment = 1;
selectSegment(segment, true);
}
if(pieRenderer.getContainingSegment(new PointF(event.getX(), event.getY())) == transitS){
segment = 2;
selectSegment(segment, true);
}
if(pieRenderer.getContainingSegment(new PointF(event.getX(), event.getY())) == walkS){
segment = 3;
selectSegment(segment, true);
}
return false;
}
});
pieChart.removeSegment(carS);
pieChart.removeSegment(walkS);
pieChart.removeSegment(transitS);
pieChart.removeSegment(bikeS);
bikeS = new Segment("", tm.getBicycling());
carS = new Segment("", tm.getDriving());
transitS = new Segment("", tm.getTransit());
walkS = new Segment("", tm.getWalking());
pieChart.addSeries(bikeS, new SegmentFormatter(bikeCP, bikeCP, bikeCP, bikeCP));
pieChart.addSeries(carS, new SegmentFormatter(carC, carC, carC, carC));
pieChart.addSeries(transitS, new SegmentFormatter(transitC, transitC, transitC, transitC));
pieChart.addSeries(walkS, new SegmentFormatter(walkC, walkC, walkC, walkC));
typeText.setText(getString(R.string.bike));
typePercent.setTextColor(getResources().getColor(R.color.bike_color));
typeImage.setImageResource(R.drawable.profile_travel_mode_pie_bicycling);
pieChart.invalidate();

Battery graph in android using GraphView library?

i found i great library to draw graphs. I want to create one that displays in the x axis the time and in y the battery percentage. My goal is create a graph like this:
You can see the percentage on the left and the date/time on bottom. Starting from this example code : https://github.com/jjoe64/GraphView-Demos/blob/master/src/com/jjoe64/graphviewdemos/CustomLabelFormatterActivity.java i want insert the correct data but i never used graphs. This is the activity
public class CustomLabelFormatterActivity extends Activity {
/** Called when the activity is first created. */
#SuppressLint("SimpleDateFormat")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.graphs);
// init example series data
Random rand = new Random();
int size = 20;
GraphViewData[] data = new GraphViewData[size];
for (int i=0; i<size; i++) {
data[i] = new GraphViewData(i, rand.nextInt(20));
}
GraphViewSeries exampleSeries = new GraphViewSeries(data);
GraphView graphView;
if (getIntent().getStringExtra("type").equals("bar")) {
graphView = new BarGraphView(
this // context
, "GraphViewDemo" // heading
);
} else {
graphView = new LineGraphView(
this // context
, "GraphViewDemo" // heading
);
}
graphView.addSeries(exampleSeries); // data
graphView.setCustomLabelFormatter(new CustomLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
if (value < 5) {
return "small";
} else if (value < 15) {
return "middle";
} else {
return "big";
}
}
return null; // let graphview generate Y-axis label for us
}
});
LinearLayout layout = (LinearLayout) findViewById(R.id.graph1);
layout.addView(graphView);
/*
* use Date as x axis label
*/
long now = new Date().getTime();
data = new GraphViewData[size];
for (int i=0; i<size; i++) {
data[i] = new GraphViewData(now+(i*60*60*24*1000), rand.nextInt(20)); // next day
}
exampleSeries = new GraphViewSeries(data);
if (getIntent().getStringExtra("type").equals("bar")) {
graphView = new BarGraphView(
this
, "GraphViewDemo"
);
} else {
graphView = new LineGraphView(
this
, "GraphViewDemo"
);
((LineGraphView) graphView).setDrawBackground(true);
}
graphView.addSeries(exampleSeries); // data
/*
* date as label formatter
*/
final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d h.mm");
graphView.setCustomLabelFormatter(new CustomLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
Date d = new Date((long) value);
return dateFormat.format(d);
}
return null; // let graphview generate Y-axis label for us
}
});
layout = (LinearLayout) findViewById(R.id.graph2);
layout.addView(graphView);
}
}
What have i to change?How can i create what i want?Anyone can help me? Thank you.

Categories

Resources