2016-11-17 15:17:02 +01:00
|
|
|
package info.nightscout.androidaps;
|
|
|
|
|
|
|
|
import android.content.Context;
|
2016-11-18 01:01:42 +01:00
|
|
|
import android.graphics.DashPathEffect;
|
2016-11-20 02:31:15 +01:00
|
|
|
import android.preference.PreferenceManager;
|
2016-11-26 06:03:07 +01:00
|
|
|
import android.support.v4.content.ContextCompat;
|
2016-11-17 15:17:02 +01:00
|
|
|
import android.text.format.DateFormat;
|
|
|
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Calendar;
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.GregorianCalendar;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.TimeZone;
|
|
|
|
|
|
|
|
import lecho.lib.hellocharts.model.Axis;
|
|
|
|
import lecho.lib.hellocharts.model.AxisValue;
|
|
|
|
import lecho.lib.hellocharts.model.Line;
|
|
|
|
import lecho.lib.hellocharts.model.LineChartData;
|
|
|
|
import lecho.lib.hellocharts.model.PointValue;
|
|
|
|
import lecho.lib.hellocharts.model.Viewport;
|
|
|
|
|
|
|
|
/**
|
2016-11-22 17:23:46 +01:00
|
|
|
* Created by emmablack on 11/15/14.
|
2016-11-17 15:17:02 +01:00
|
|
|
*/
|
|
|
|
public class BgGraphBuilder {
|
2016-11-18 02:31:29 +01:00
|
|
|
private ArrayList<BasalWatchData> basalWatchDataList;
|
2016-11-18 01:01:42 +01:00
|
|
|
public List<TempWatchData> tempWatchDataList;
|
2016-11-17 15:17:02 +01:00
|
|
|
private int timespan;
|
|
|
|
public double end_time;
|
|
|
|
public double start_time;
|
|
|
|
public double fuzzyTimeDenom = (1000 * 60 * 1);
|
|
|
|
public Context context;
|
|
|
|
public double highMark;
|
|
|
|
public double lowMark;
|
|
|
|
public List<BgWatchData> bgDataList = new ArrayList<BgWatchData>();
|
|
|
|
|
|
|
|
public int pointSize;
|
|
|
|
public int highColor;
|
|
|
|
public int lowColor;
|
|
|
|
public int midColor;
|
2016-11-27 03:48:03 +01:00
|
|
|
public int gridColour;
|
2016-11-27 04:14:46 +01:00
|
|
|
public int basalCenterColor;
|
|
|
|
public int basalBackgroundColor;
|
2016-11-17 15:17:02 +01:00
|
|
|
public boolean singleLine = false;
|
|
|
|
|
|
|
|
private double endHour;
|
|
|
|
private List<PointValue> inRangeValues = new ArrayList<PointValue>();
|
|
|
|
private List<PointValue> highValues = new ArrayList<PointValue>();
|
|
|
|
private List<PointValue> lowValues = new ArrayList<PointValue>();
|
|
|
|
public Viewport viewport;
|
|
|
|
|
2016-11-26 20:53:00 +01:00
|
|
|
|
2016-11-27 06:12:20 +01:00
|
|
|
//used for low resolution screen.
|
2016-11-27 04:14:46 +01:00
|
|
|
public BgGraphBuilder(Context context, List<BgWatchData> aBgList, List<TempWatchData> tempWatchDataList, ArrayList<BasalWatchData> basalWatchDataList, int aPointSize, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int timespan) {
|
2016-11-17 15:17:02 +01:00
|
|
|
end_time = new Date().getTime() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
|
|
|
|
start_time = new Date().getTime() - (1000 * 60 * 60 * timespan); //timespan hours ago
|
|
|
|
this.bgDataList = aBgList;
|
|
|
|
this.context = context;
|
|
|
|
this.highMark = aBgList.get(aBgList.size() - 1).high;
|
|
|
|
this.lowMark = aBgList.get(aBgList.size() - 1).low;
|
|
|
|
this.pointSize = aPointSize;
|
|
|
|
this.singleLine = true;
|
|
|
|
this.midColor = aMidColor;
|
|
|
|
this.lowColor = aMidColor;
|
|
|
|
this.highColor = aMidColor;
|
|
|
|
this.timespan = timespan;
|
2016-11-18 01:01:42 +01:00
|
|
|
this.tempWatchDataList = tempWatchDataList;
|
2016-11-18 02:31:29 +01:00
|
|
|
this.basalWatchDataList = basalWatchDataList;
|
2016-11-27 03:48:03 +01:00
|
|
|
this.gridColour = gridColour;
|
2016-11-27 04:14:46 +01:00
|
|
|
this.basalCenterColor = basalCenterColor;
|
|
|
|
this.basalBackgroundColor = basalBackgroundColor;
|
2016-11-17 15:17:02 +01:00
|
|
|
}
|
|
|
|
|
2016-11-27 04:14:46 +01:00
|
|
|
public BgGraphBuilder(Context context, List<BgWatchData> aBgList, List<TempWatchData> tempWatchDataList, ArrayList<BasalWatchData> basalWatchDataList, int aPointSize, int aHighColor, int aLowColor, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int timespan) {
|
2016-11-17 15:17:02 +01:00
|
|
|
end_time = new Date().getTime() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
|
|
|
|
start_time = new Date().getTime() - (1000 * 60 * 60 * timespan); //timespan hours ago
|
|
|
|
this.bgDataList = aBgList;
|
|
|
|
this.context = context;
|
|
|
|
this.highMark = aBgList.get(aBgList.size() - 1).high;
|
|
|
|
this.lowMark = aBgList.get(aBgList.size() - 1).low;
|
|
|
|
this.pointSize = aPointSize;
|
|
|
|
this.highColor = aHighColor;
|
|
|
|
this.lowColor = aLowColor;
|
|
|
|
this.midColor = aMidColor;
|
|
|
|
this.timespan = timespan;
|
2016-11-18 01:01:42 +01:00
|
|
|
this.tempWatchDataList = tempWatchDataList;
|
2016-11-18 02:31:29 +01:00
|
|
|
this.basalWatchDataList = basalWatchDataList;
|
2016-11-27 03:48:03 +01:00
|
|
|
this.gridColour = gridColour;
|
2016-11-27 04:14:46 +01:00
|
|
|
this.basalCenterColor = basalCenterColor;
|
|
|
|
this.basalBackgroundColor = basalBackgroundColor;
|
2016-11-17 15:17:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public LineChartData lineData() {
|
|
|
|
LineChartData lineData = new LineChartData(defaultLines());
|
|
|
|
lineData.setAxisYLeft(yAxis());
|
|
|
|
lineData.setAxisXBottom(xAxis());
|
|
|
|
return lineData;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Line> defaultLines() {
|
|
|
|
addBgReadingValues();
|
|
|
|
List<Line> lines = new ArrayList<Line>();
|
|
|
|
lines.add(highLine());
|
|
|
|
lines.add(lowLine());
|
|
|
|
lines.add(inRangeValuesLine());
|
|
|
|
lines.add(lowValuesLine());
|
|
|
|
lines.add(highValuesLine());
|
2016-11-18 01:01:42 +01:00
|
|
|
|
|
|
|
double minChart = lowMark;
|
|
|
|
double maxChart = highMark;
|
|
|
|
|
|
|
|
for ( BgWatchData bgd:bgDataList) {
|
|
|
|
if(bgd.sgv > maxChart){
|
|
|
|
maxChart = bgd.sgv;
|
|
|
|
}
|
|
|
|
if(bgd.sgv < minChart){
|
|
|
|
minChart = bgd.sgv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 02:31:29 +01:00
|
|
|
double maxBasal = 0.1;
|
|
|
|
for (BasalWatchData bwd: basalWatchDataList) {
|
|
|
|
if(bwd.amount > maxBasal){
|
|
|
|
maxBasal = bwd.amount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 01:01:42 +01:00
|
|
|
double maxTemp = maxBasal;
|
|
|
|
for (TempWatchData twd: tempWatchDataList) {
|
|
|
|
if(twd.amount > maxTemp){
|
|
|
|
maxTemp = twd.amount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double factor = (maxChart-minChart)/maxTemp;
|
|
|
|
// in case basal is the highest, don't paint it totally at the top.
|
2016-11-18 03:21:38 +01:00
|
|
|
factor = Math.min(factor, ((maxChart-minChart)/maxBasal)*(2/3d));
|
2016-11-20 02:31:15 +01:00
|
|
|
|
|
|
|
boolean highlight = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(context)
|
|
|
|
.getBoolean("highlight_basals", false);
|
|
|
|
|
2016-11-18 01:35:46 +01:00
|
|
|
for (TempWatchData twd: tempWatchDataList) {
|
|
|
|
if(twd.endTime > start_time) {
|
2016-11-20 02:31:15 +01:00
|
|
|
lines.add(tempValuesLine(twd, (float) minChart, factor, false, highlight?3:2));
|
|
|
|
if(highlight){
|
|
|
|
lines.add(tempValuesLine(twd, (float) minChart, factor, true, 1));
|
|
|
|
}
|
2016-11-18 01:35:46 +01:00
|
|
|
}
|
|
|
|
}
|
2016-11-18 01:01:42 +01:00
|
|
|
|
2016-11-20 02:31:15 +01:00
|
|
|
lines.add(basalLine((float) minChart, factor, highlight));
|
2016-11-18 02:31:29 +01:00
|
|
|
|
2016-11-17 15:17:02 +01:00
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
2016-11-20 02:31:15 +01:00
|
|
|
private Line basalLine(float offset, double factor, boolean highlight) {
|
2016-11-18 02:31:29 +01:00
|
|
|
|
|
|
|
List<PointValue> pointValues = new ArrayList<PointValue>();
|
|
|
|
|
|
|
|
for (BasalWatchData bwd: basalWatchDataList) {
|
|
|
|
if(bwd.endTime > start_time) {
|
|
|
|
long begin = (long) Math.max(start_time, bwd.startTime);
|
|
|
|
pointValues.add(new PointValue(fuzz(begin), offset + (float) (factor * bwd.amount)));
|
|
|
|
pointValues.add(new PointValue(fuzz(bwd.endTime), offset + (float) (factor * bwd.amount)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Line basalLine = new Line(pointValues);
|
|
|
|
basalLine.setHasPoints(false);
|
2016-11-27 04:14:46 +01:00
|
|
|
basalLine.setColor(basalCenterColor);
|
2016-11-18 02:31:29 +01:00
|
|
|
basalLine.setPathEffect(new DashPathEffect(new float[]{4f, 3f}, 4f));
|
2016-11-20 02:31:15 +01:00
|
|
|
basalLine.setStrokeWidth(highlight?2:1);
|
2016-11-18 02:31:29 +01:00
|
|
|
return basalLine;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-11-17 15:17:02 +01:00
|
|
|
public Line highValuesLine() {
|
|
|
|
Line highValuesLine = new Line(highValues);
|
|
|
|
highValuesLine.setColor(highColor);
|
|
|
|
highValuesLine.setHasLines(false);
|
|
|
|
highValuesLine.setPointRadius(pointSize);
|
|
|
|
highValuesLine.setHasPoints(true);
|
|
|
|
return highValuesLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Line lowValuesLine() {
|
|
|
|
Line lowValuesLine = new Line(lowValues);
|
|
|
|
lowValuesLine.setColor(lowColor);
|
|
|
|
lowValuesLine.setHasLines(false);
|
|
|
|
lowValuesLine.setPointRadius(pointSize);
|
|
|
|
lowValuesLine.setHasPoints(true);
|
|
|
|
return lowValuesLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Line inRangeValuesLine() {
|
|
|
|
Line inRangeValuesLine = new Line(inRangeValues);
|
|
|
|
inRangeValuesLine.setColor(midColor);
|
|
|
|
if(singleLine) {
|
|
|
|
inRangeValuesLine.setHasLines(true);
|
|
|
|
inRangeValuesLine.setHasPoints(false);
|
|
|
|
inRangeValuesLine.setStrokeWidth(pointSize);
|
|
|
|
} else {
|
|
|
|
inRangeValuesLine.setPointRadius(pointSize);
|
|
|
|
inRangeValuesLine.setHasPoints(true);
|
|
|
|
inRangeValuesLine.setHasLines(false);
|
|
|
|
}
|
|
|
|
return inRangeValuesLine;
|
|
|
|
}
|
|
|
|
|
2016-11-18 01:01:42 +01:00
|
|
|
|
2016-11-20 02:31:15 +01:00
|
|
|
public Line tempValuesLine(TempWatchData twd, float offset, double factor, boolean isHighlightLine, int strokeWidth) {
|
2016-11-18 01:01:42 +01:00
|
|
|
List<PointValue> lineValues = new ArrayList<PointValue>();
|
2016-11-18 02:31:29 +01:00
|
|
|
long begin = (long) Math.max(start_time, twd.startTime);
|
|
|
|
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.startBasal)));
|
|
|
|
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.amount)));
|
|
|
|
lineValues.add(new PointValue(fuzz(twd.endTime), offset + (float) (factor * twd.amount)));
|
|
|
|
lineValues.add(new PointValue(fuzz(twd.endTime), offset + (float) (factor * twd.endBasal)));
|
2016-11-18 01:01:42 +01:00
|
|
|
Line valueLine = new Line(lineValues);
|
|
|
|
valueLine.setHasPoints(false);
|
2016-11-20 02:31:15 +01:00
|
|
|
if (isHighlightLine){
|
2016-11-27 04:14:46 +01:00
|
|
|
valueLine.setColor(basalCenterColor);
|
2016-11-20 02:31:15 +01:00
|
|
|
valueLine.setStrokeWidth(1);
|
|
|
|
}else {
|
2016-11-27 04:14:46 +01:00
|
|
|
valueLine.setColor(basalBackgroundColor);
|
2016-11-20 02:31:15 +01:00
|
|
|
valueLine.setStrokeWidth(strokeWidth);
|
|
|
|
}
|
2016-11-18 01:01:42 +01:00
|
|
|
return valueLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-11-17 15:17:02 +01:00
|
|
|
private void addBgReadingValues() {
|
|
|
|
if(singleLine) {
|
|
|
|
for (BgWatchData bgReading : bgDataList) {
|
|
|
|
if(bgReading.timestamp > start_time) {
|
|
|
|
if (bgReading.sgv >= 400) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 400));
|
|
|
|
} else if (bgReading.sgv >= highMark) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= lowMark) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= 40) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= 11) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 40));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (BgWatchData bgReading : bgDataList) {
|
|
|
|
if (bgReading.timestamp > start_time) {
|
|
|
|
if (bgReading.sgv >= 400) {
|
|
|
|
highValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 400));
|
|
|
|
} else if (bgReading.sgv >= highMark) {
|
|
|
|
highValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= lowMark) {
|
|
|
|
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= 40) {
|
|
|
|
lowValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
|
|
|
|
} else if (bgReading.sgv >= 11) {
|
|
|
|
lowValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 40));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Line highLine() {
|
|
|
|
List<PointValue> highLineValues = new ArrayList<PointValue>();
|
|
|
|
highLineValues.add(new PointValue(fuzz(start_time), (float) highMark));
|
|
|
|
highLineValues.add(new PointValue(fuzz(end_time), (float) highMark));
|
|
|
|
Line highLine = new Line(highLineValues);
|
|
|
|
highLine.setHasPoints(false);
|
|
|
|
highLine.setStrokeWidth(1);
|
|
|
|
highLine.setColor(highColor);
|
|
|
|
return highLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Line lowLine() {
|
|
|
|
List<PointValue> lowLineValues = new ArrayList<PointValue>();
|
|
|
|
lowLineValues.add(new PointValue(fuzz(start_time), (float) lowMark));
|
|
|
|
lowLineValues.add(new PointValue(fuzz(end_time), (float) lowMark));
|
|
|
|
Line lowLine = new Line(lowLineValues);
|
|
|
|
lowLine.setHasPoints(false);
|
|
|
|
lowLine.setColor(lowColor);
|
|
|
|
lowLine.setStrokeWidth(1);
|
|
|
|
return lowLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////AXIS RELATED//////////////
|
2016-11-26 20:53:00 +01:00
|
|
|
|
|
|
|
|
2016-11-17 15:17:02 +01:00
|
|
|
public Axis yAxis() {
|
|
|
|
Axis yAxis = new Axis();
|
|
|
|
yAxis.setAutoGenerated(true);
|
|
|
|
List<AxisValue> axisValues = new ArrayList<AxisValue>();
|
|
|
|
yAxis.setValues(axisValues);
|
|
|
|
yAxis.setHasLines(false);
|
2016-11-27 03:48:03 +01:00
|
|
|
yAxis.setLineColor(gridColour);
|
2016-11-17 15:17:02 +01:00
|
|
|
return yAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Axis xAxis() {
|
|
|
|
final boolean is24 = DateFormat.is24HourFormat(context);
|
|
|
|
Axis xAxis = new Axis();
|
|
|
|
xAxis.setAutoGenerated(false);
|
|
|
|
List<AxisValue> xAxisValues = new ArrayList<AxisValue>();
|
|
|
|
GregorianCalendar now = new GregorianCalendar();
|
|
|
|
GregorianCalendar today = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
|
|
|
|
SimpleDateFormat timeFormat = new SimpleDateFormat(is24? "HH" : "h a");
|
|
|
|
timeFormat.setTimeZone(TimeZone.getDefault());
|
|
|
|
double start_hour = today.getTime().getTime();
|
|
|
|
double timeNow = new Date().getTime();
|
|
|
|
for (int l = 0; l <= 24; l++) {
|
|
|
|
if ((start_hour + (60000 * 60 * (l))) < timeNow) {
|
|
|
|
if ((start_hour + (60000 * 60 * (l + 1))) >= timeNow) {
|
|
|
|
endHour = start_hour + (60000 * 60 * (l));
|
|
|
|
l = 25;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Display current time on the graph
|
|
|
|
SimpleDateFormat longTimeFormat = new SimpleDateFormat(is24? "HH:mm" : "h:mm a");
|
|
|
|
xAxisValues.add(new AxisValue(fuzz(timeNow), (longTimeFormat.format(timeNow)).toCharArray()));
|
|
|
|
|
2016-11-18 01:01:42 +01:00
|
|
|
//Add whole hours endTime the axis (as long as they are more than 15 mins away from the current time)
|
2016-11-17 15:17:02 +01:00
|
|
|
for (int l = 0; l <= 24; l++) {
|
|
|
|
double timestamp = endHour - (60000 * 60 * l);
|
|
|
|
if((timestamp - timeNow < 0) && (timestamp > start_time)) {
|
|
|
|
if(Math.abs(timestamp - timeNow) > (1000 * 60 * 8 * timespan)){
|
|
|
|
xAxisValues.add(new AxisValue(fuzz(timestamp), (timeFormat.format(timestamp)).toCharArray()));
|
|
|
|
}else {
|
|
|
|
xAxisValues.add(new AxisValue(fuzz(timestamp), "".toCharArray()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xAxis.setValues(xAxisValues);
|
|
|
|
xAxis.setTextSize(10);
|
|
|
|
xAxis.setHasLines(true);
|
2016-11-27 03:48:03 +01:00
|
|
|
xAxis.setLineColor(gridColour);
|
|
|
|
xAxis.setTextColor(gridColour);
|
|
|
|
|
2016-11-17 15:17:02 +01:00
|
|
|
return xAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float fuzz(double value) {
|
|
|
|
return (float) Math.round(value / fuzzyTimeDenom);
|
|
|
|
}
|
|
|
|
}
|