simplify graph series

This commit is contained in:
Milos Kozak 2017-06-05 00:50:31 +02:00
parent 8934d2d6b9
commit dd7e777a24
9 changed files with 282 additions and 555 deletions

View file

@ -2,20 +2,24 @@ package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import com.jjoe64.graphview.series.DataPointInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS)
public class BgReading implements DataPointInterface {
public class BgReading implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(BgReading.class);
@DatabaseField(id = true)
@ -39,6 +43,8 @@ public class BgReading implements DataPointInterface {
public static String units = Constants.MGDL;
public boolean isPrediction = false; // true when drawing predictions as bg points
public BgReading() {}
public BgReading(NSSgv sgv) {
@ -106,6 +112,7 @@ public class BgReading implements DataPointInterface {
'}';
}
// ------------------ DataPointWithLabelInterface ------------------
@Override
public double getX() {
return date;
@ -116,4 +123,51 @@ public class BgReading implements DataPointInterface {
return valueToUnits(units);
}
@Override
public void setY(double y) {
}
@Override
public String getLabel() {
return null;
}
@Override
public long getDuration() {
return 0;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.POINT;
}
@Override
public float getSize() {
boolean isTablet = MainApp.sResources.getBoolean(R.bool.isTablet);
return isTablet ? 8 : 5;
}
@Override
public int getColor() {
Double lowLine = SP.getDouble("low_mark", 0d);
Double highLine = SP.getDouble("high_mark", 0d);
if (lowLine < 1) {
lowLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units);
}
if (highLine < 1) {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
}
String units = MainApp.getConfigBuilder().getProfile().getUnits();
int color = MainApp.sResources.getColor(R.color.inrange);
if (isPrediction)
color = MainApp.sResources.getColor(R.color.prediction);
else if (valueToUnits(units) < lowLine)
color = MainApp.sResources.getColor(R.color.low);
else if (valueToUnits(units) > highLine)
color = MainApp.sResources.getColor(R.color.high);
return color;
}
}

View file

@ -4,6 +4,8 @@ package info.nightscout.androidaps.db;
* Created by mike on 21.05.2017.
*/
import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@ -20,6 +22,8 @@ import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round;
@ -29,7 +33,7 @@ import info.nightscout.utils.Round;
*/
@DatabaseTable(tableName = DatabaseHelper.DATABASE_EXTENDEDBOLUSES)
public class ExtendedBolus implements Interval {
public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(ExtendedBolus.class);
@DatabaseField(id = true)
@ -196,4 +200,49 @@ public class ExtendedBolus implements Interval {
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h ("
+ getRealDuration() + "/" + durationInMinutes + ") ";
}
// -------- DataPointWithLabelInterface --------
@Override
public double getX() {
return date;
}
// default when no sgv around available
private double yValue = 0;
@Override
public double getY() {
return yValue;
}
@Override
public void setY(double y) {
yValue = y;
}
@Override
public String getLabel() {
return toStringMedium();
}
@Override
public long getDuration() {
return durationInMinutes * 60 * 1000L;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS;
}
@Override
public float getSize() {
return 10;
}
@Override
public int getColor() {
return Color.CYAN;
}
}

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.db;
import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@ -10,6 +12,7 @@ import java.util.Date;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_PROFILESWITCHES)
@ -118,11 +121,36 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
return yValue;
}
@Override
public void setY(double y) {
yValue = y;
}
@Override
public String getLabel() {
return profileName;
}
@Override
public long getDuration() {
return 0;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.PROFILE;
}
@Override
public float getSize() {
return 10;
}
@Override
public int getColor() {
return Color.CYAN;
}
public String log() {
return "ProfileSwitch{" +
"date=" + date +

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.db;
import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@ -16,6 +18,7 @@ import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
@ -103,14 +106,29 @@ public class Treatment implements DataPointWithLabelInterface {
return label;
}
public void setYValue(List<BgReading> bgReadingsArray) {
Profile profile = MainApp.getConfigBuilder().getProfile();
for (int r = bgReadingsArray.size() - 1; r >= 0; r--) {
BgReading reading = bgReadingsArray.get(r);
if (reading.date > date) continue;
yValue = Profile.fromMgdlToUnits(reading.value, profile.getUnits());
break;
}
@Override
public long getDuration() {
return 0;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.BOLUS;
}
@Override
public float getSize() {
return 10;
}
@Override
public int getColor() {
return Color.CYAN;
}
@Override
public void setY(double y) {
yValue = y;
}
// ----------------- DataPointInterface end --------------------

View file

@ -100,6 +100,7 @@ public class DetermineBasalResultAMA extends APSResult {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isPrediction = true;
array.add(bg);
}
}
@ -109,6 +110,7 @@ public class DetermineBasalResultAMA extends APSResult {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isPrediction = true;
array.add(bg);
}
}
@ -118,6 +120,7 @@ public class DetermineBasalResultAMA extends APSResult {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isPrediction = true;
array.add(bg);
}
}

View file

@ -40,7 +40,6 @@ import com.jjoe64.graphview.Viewport;
import com.jjoe64.graphview.series.BarGraphSeries;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.jjoe64.graphview.series.PointsGraphSeries;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
@ -61,7 +60,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
@ -109,11 +107,11 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.AreaGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DoubleDataPoint;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.FixedLineGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.TimeAsXAxisLabelFormatter;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.VerticalTextsGraphSeries;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin;
import info.nightscout.utils.BolusWizard;
import info.nightscout.utils.DateUtil;
@ -189,8 +187,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledUpdate = null;
final Handler timeHandler = new Handler();
public OverviewFragment() {
super();
if (sHandlerThread == null) {
@ -337,7 +333,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop();
final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop();
if (activeloop == null)
return;
menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop));
@ -620,8 +616,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
NSUpload.uploadDeviceStatus();
ObjectivesPlugin objectivesPlugin = (ObjectivesPlugin) MainApp.getSpecificPlugin(ObjectivesPlugin.class);
if (objectivesPlugin != null) {
objectivesPlugin.manualEnacts++;
objectivesPlugin.saveProgress();
ObjectivesPlugin.manualEnacts++;
ObjectivesPlugin.saveProgress();
}
}
scheduleUpdateGUI("onClickAcceptTemp");
@ -643,7 +639,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
QuickWizard.QuickWizardEntry quickWizardEntry = getPlugin().quickWizard.getActive();
if (quickWizardEntry != null && actualBg != null) {
quickWizardButton.setVisibility(View.VISIBLE);
String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText();
BolusWizard wizard = new BolusWizard();
wizard.doCalc(profile, quickWizardEntry.carbs(), 0d, actualBg.valueToUnits(profile.getUnits()), 0d, true, true, false, false);
@ -679,7 +674,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
confirmMessage += "\n" + getString(R.string.bolus) + ": " + formatNumber2decimalplaces.format(insulinAfterConstraints) + "U";
confirmMessage += "\n" + getString(R.string.carbs) + ": " + carbsAfterConstraints + "g";
if (insulinAfterConstraints - wizard.calculatedTotalInsulin != 0 || carbsAfterConstraints != quickWizardEntry.carbs()) {
if (!insulinAfterConstraints.equals(wizard.calculatedTotalInsulin) || !carbsAfterConstraints.equals(quickWizardEntry.carbs())) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(MainApp.sResources.getString(R.string.treatmentdeliveryerror));
builder.setMessage(getString(R.string.constraints_violation) + "\n" + getString(R.string.changeyourinput));
@ -921,7 +916,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
apsModeView.setVisibility(View.VISIBLE);
apsModeView.setBackgroundColor(MainApp.sResources.getColor(R.color.loopenabled));
apsModeView.setTextColor(Color.BLACK);
final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop();
final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop();
if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuperBolus()) {
apsModeView.setBackgroundColor(MainApp.sResources.getColor(R.color.looppumpsuspended));
apsModeView.setText(String.format(MainApp.sResources.getString(R.string.loopsuperbolusfor), activeloop.minutesToEndOfSuspend()));
@ -959,7 +954,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
tempTargetView.setText(Profile.toUnitsString(tempTarget.low, Profile.fromMgdlToUnits(tempTarget.low, profile.getUnits()), profile.getUnits()));
else
tempTargetView.setText(Profile.toUnitsString(tempTarget.low, Profile.fromMgdlToUnits(tempTarget.low, profile.getUnits()), profile.getUnits()) + " - " + Profile.toUnitsString(tempTarget.high, Profile.fromMgdlToUnits(tempTarget.high, profile.getUnits()), profile.getUnits()));
} if (Config.NSCLIENT) {
}
if (Config.NSCLIENT) {
tempTargetView.setVisibility(View.GONE);
} else {
@ -1173,7 +1169,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
int predHours = (int) (Math.ceil(((DetermineBasalResultAMA) finalLastRun.constraintsProcessed).getLatestPredictionsTime() - new Date().getTime()) / (60 * 60 * 1000));
predHours = Math.min(2, predHours);
predHours = Math.max(0, predHours);
hoursToFetch = (int) (rangeToDisplay - predHours);
hoursToFetch = rangeToDisplay - predHours;
toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding
fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
endTime = toTime + predHours * 60 * 60 * 1000L;
@ -1189,12 +1185,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
LineGraphSeries<DataPoint> tempBasalsSeries = null;
AreaGraphSeries<DoubleDataPoint> areaSeries;
LineGraphSeries<DataPoint> seriesNow, seriesNow2;
PointsGraphSeries<BgReading> seriesInRage;
PointsGraphSeries<BgReading> seriesLow;
PointsGraphSeries<BgReading> seriesHigh;
PointsGraphSeries<BgReading> predSeries;
PointsWithLabelGraphSeries<Treatment> seriesTreatments;
VerticalTextsGraphSeries<ProfileSwitch> seriesProfileSwitch;
// **** TEMP BASALS graph ****
Double maxBasalValueFound = 0d;
@ -1406,9 +1396,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// **** BG graph ****
List<BgReading> bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true);
List<BgReading> inRangeArray = new ArrayList<>();
List<BgReading> lowArray = new ArrayList<>();
List<BgReading> highArray = new ArrayList<>();
List<DataPointWithLabelInterface> bgListArray = new ArrayList<>();
if (bgReadingsArray.size() == 0)
return;
@ -1418,59 +1406,28 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
while (it.hasNext()) {
BgReading bg = it.next();
if (bg.value > maxBgValue) maxBgValue = bg.value;
if (bg.valueToUnits(units) < lowLine)
lowArray.add(bg);
else if (bg.valueToUnits(units) > highLine)
highArray.add(bg);
else
inRangeArray.add(bg);
bgListArray.add(bg);
}
if (showPrediction) {
DetermineBasalResultAMA amaResult = (DetermineBasalResultAMA) finalLastRun.constraintsProcessed;
List<BgReading> predArray = amaResult.getPredictions();
Iterator<BgReading> itPred = predArray.iterator();
while (itPred.hasNext()) {
BgReading bg = it.next();
bgListArray.add(bg);
}
}
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units);
maxBgValue = units.equals(Constants.MGDL) ? Round.roundTo(maxBgValue, 40d) + 80 : Round.roundTo(maxBgValue, 2d) + 4;
if (highLine > maxBgValue) maxBgValue = highLine;
Integer numOfHorizLines = units.equals(Constants.MGDL) ? (int) (maxBgValue / 40 + 1) : (int) (maxBgValue / 2 + 1);
BgReading[] inRange = new BgReading[inRangeArray.size()];
BgReading[] low = new BgReading[lowArray.size()];
BgReading[] high = new BgReading[highArray.size()];
inRange = inRangeArray.toArray(inRange);
low = lowArray.toArray(low);
high = highArray.toArray(high);
DataPointWithLabelInterface[] bg = new DataPointWithLabelInterface[bgListArray.size()];
bg = bgListArray.toArray(bg);
boolean isTablet = MainApp.sResources.getBoolean(R.bool.isTablet);
if (inRange.length > 0) {
bgGraph.addSeries(seriesInRage = new PointsGraphSeries<>(inRange));
seriesInRage.setShape(PointsGraphSeries.Shape.POINT);
seriesInRage.setSize(isTablet ? 8 : 5);
seriesInRage.setColor(MainApp.sResources.getColor(R.color.inrange));
}
if (low.length > 0) {
bgGraph.addSeries(seriesLow = new PointsGraphSeries<>(low));
seriesLow.setShape(PointsGraphSeries.Shape.POINT);
seriesLow.setSize(isTablet ? 8 : 5);
seriesLow.setColor(MainApp.sResources.getColor(R.color.low));
}
if (high.length > 0) {
bgGraph.addSeries(seriesHigh = new PointsGraphSeries<>(high));
seriesHigh.setShape(PointsGraphSeries.Shape.POINT);
seriesHigh.setSize(isTablet ? 8 : 5);
seriesHigh.setColor(MainApp.sResources.getColor(R.color.high));
}
if (showPrediction) {
DetermineBasalResultAMA amaResult = (DetermineBasalResultAMA) finalLastRun.constraintsProcessed;
List<BgReading> predArray = amaResult.getPredictions();
BgReading[] pred = new BgReading[predArray.size()];
pred = predArray.toArray(pred);
if (pred.length > 0) {
bgGraph.addSeries(predSeries = new PointsGraphSeries<BgReading>(pred));
predSeries.setShape(PointsGraphSeries.Shape.POINT);
predSeries.setSize(4);
predSeries.setColor(MainApp.sResources.getColor(R.color.prediction));
}
if (bg.length > 0) {
bgGraph.addSeries(new PointsWithLabelGraphSeries<>(bg));
}
// **** NOW line ****
@ -1498,40 +1455,30 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// Treatments
List<DataPointWithLabelInterface> filteredTreatments = new ArrayList<>();
List<Treatment> treatments = MainApp.getConfigBuilder().getTreatmentsFromHistory();
List<Treatment> filteredTreatments = new ArrayList<Treatment>();
for (int tx = 0; tx < treatments.size(); tx++) {
Treatment t = treatments.get(tx);
if (t.date < fromTime || t.date > endTime) continue;
t.setYValue(bgReadingsArray);
DataPointWithLabelInterface t = treatments.get(tx);
if (t.getX() < fromTime || t.getX() > endTime) continue;
t.setY(getNearestBg((long) t.getX(), bgReadingsArray));
filteredTreatments.add(t);
}
Treatment[] treatmentsArray = new Treatment[filteredTreatments.size()];
treatmentsArray = filteredTreatments.toArray(treatmentsArray);
if (treatmentsArray.length > 0) {
bgGraph.addSeries(seriesTreatments = new PointsWithLabelGraphSeries<Treatment>(treatmentsArray));
seriesTreatments.setShape(PointsWithLabelGraphSeries.Shape.TRIANGLE);
seriesTreatments.setSize(10);
seriesTreatments.setColor(Color.CYAN);
}
// ProfileSwitch
List<ProfileSwitch> profileSwitches = MainApp.getConfigBuilder().getProfileSwitchesFromHistory().getList();
List<ProfileSwitch> filteredProfileSwitches = new ArrayList<ProfileSwitch>();
for (int tx = 0; tx < profileSwitches.size(); tx++) {
ProfileSwitch t = profileSwitches.get(tx);
if (t.date < fromTime || t.date > endTime) continue;
filteredProfileSwitches.add(t);
DataPointWithLabelInterface t = profileSwitches.get(tx);
if (t.getX() < fromTime || t.getX() > endTime) continue;
filteredTreatments.add(t);
}
ProfileSwitch[] profileSwitchArray = new ProfileSwitch[filteredProfileSwitches.size()];
profileSwitchArray = filteredProfileSwitches.toArray(profileSwitchArray);
if (profileSwitchArray.length > 0) {
bgGraph.addSeries(seriesProfileSwitch = new VerticalTextsGraphSeries<ProfileSwitch>(profileSwitchArray));
//seriesProfileSwitch.setShape(PointsWithLabelGraphSeries.Shape.TRIANGLE);
seriesProfileSwitch.setSize(10);
seriesProfileSwitch.setColor(Color.CYAN);
DataPointWithLabelInterface[] treatmentsArray = new DataPointWithLabelInterface[filteredTreatments.size()];
treatmentsArray = filteredTreatments.toArray(treatmentsArray);
if (treatmentsArray.length > 0) {
bgGraph.addSeries(new PointsWithLabelGraphSeries<>(treatmentsArray));
}
// set manual y bounds to have nice steps
@ -1560,9 +1507,21 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
}
});
}
public double getNearestBg(long date, List<BgReading> bgReadingsArray) {
double bg = 0;
Profile profile = MainApp.getConfigBuilder().getProfile();
for (int r = bgReadingsArray.size() - 1; r >= 0; r--) {
BgReading reading = bgReadingsArray.get(r);
if (reading.date > date) continue;
bg = Profile.fromMgdlToUnits(reading.value, profile.getUnits());
break;
}
return bg;
}
//Notifications
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.NotificationsViewHolder> {

View file

@ -38,15 +38,21 @@ public interface DataPointWithLabelInterface extends DataPointInterface{
/**
* @return the x value
*/
public double getX();
double getX();
/**
* @return the y value
*/
public double getY();
double getY();
void setY(double y);
/**
* @return the label value
*/
public String getLabel();
String getLabel();
long getDuration();
PointsWithLabelGraphSeries.Shape getShape();
float getSize();
int getColor();
}

View file

@ -28,6 +28,8 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.BaseSeries;
@ -42,26 +44,6 @@ import java.util.Iterator;
* @author jjoe64
*/
public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> extends BaseSeries<E> {
/**
* interface to implement a custom
* drawing for the data points.
*/
public static interface CustomShape {
/**
* called when drawing a single data point.
* use the x and y coordinates to render your
* drawing at this point.
*
* @param canvas canvas to draw on
* @param paint internal paint object. this has the correct color.
* But you can use your own paint.
* @param x x-coordinate the point has to be drawn to
* @param y y-coordinate the point has to be drawn to
* @param dataPoint the related data point
*/
void draw(Canvas canvas, Paint paint, float x, float y, DataPointWithLabelInterface dataPoint);
}
/**
* choose a predefined shape to render for
* each data point.
@ -77,45 +59,17 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
* draws a triangle
*/
TRIANGLE,
/**
* draws a rectangle
*/
RECTANGLE
RECTANGLE,
BOLUS,
EXTENDEDBOLUS,
PROFILE
}
/**
* wrapped styles for this series
*/
private final class Styles {
/**
* this is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*/
float size;
/**
* the shape that will be drawn for each point.
*/
Shape shape;
}
/**
* wrapped styles
*/
private Styles mStyles;
/**
* internal paint object
*/
private Paint mPaint;
/**
* handler to use a custom drawing
*/
private CustomShape mCustomShape;
/**
* creates the series without data
*/
@ -138,11 +92,8 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
* set the defaults
*/
protected void init() {
mStyles = new Styles();
mStyles.size = 20f;
mPaint = new Paint();
mPaint.setStrokeCap(Paint.Cap.ROUND);
setShape(Shape.POINT);
}
/**
@ -177,7 +128,6 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
double lastEndX = 0;
// draw data
mPaint.setColor(getColor());
double diffY = maxY - minY;
double diffX = maxX - minX;
@ -194,6 +144,8 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
while (values.hasNext()) {
E value = values.next();
mPaint.setColor(value.getColor());
double valY = value.getY() - minY;
double ratY = valY / diffY;
double y = graphHeight * ratY;
@ -227,30 +179,57 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
// draw data point
if (!overdraw) {
if (mCustomShape != null) {
mCustomShape.draw(canvas, mPaint, endX, endY, value);
} else if (mStyles.shape == Shape.POINT) {
canvas.drawCircle(endX, endY, mStyles.size, mPaint);
} else if (mStyles.shape == Shape.RECTANGLE) {
canvas.drawRect(endX-mStyles.size, endY-mStyles.size, endX+mStyles.size, endY+mStyles.size, mPaint);
} else if (mStyles.shape == Shape.TRIANGLE) {
if (value.getShape() == Shape.POINT) {
canvas.drawCircle(endX, endY, value.getSize(), mPaint);
} else if (value.getShape() == Shape.RECTANGLE) {
canvas.drawRect(endX-value.getSize(), endY-value.getSize(), endX+value.getSize(), endY+value.getSize(), mPaint);
} else if (value.getShape() == Shape.TRIANGLE) {
Point[] points = new Point[3];
points[0] = new Point((int)endX, (int)(endY-getSize()));
points[1] = new Point((int)(endX+getSize()), (int)(endY+getSize()*0.67));
points[2] = new Point((int)(endX-getSize()), (int)(endY+getSize()*0.67));
points[0] = new Point((int)endX, (int)(endY-value.getSize()));
points[1] = new Point((int)(endX+value.getSize()), (int)(endY+value.getSize()*0.67));
points[2] = new Point((int)(endX-value.getSize()), (int)(endY+value.getSize()*0.67));
drawArrows(points, canvas, mPaint);
} else if (value.getShape() == Shape.BOLUS) {
Point[] points = new Point[3];
points[0] = new Point((int)endX, (int)(endY-value.getSize()));
points[1] = new Point((int)(endX+value.getSize()), (int)(endY+value.getSize()*0.67));
points[2] = new Point((int)(endX-value.getSize()), (int)(endY+value.getSize()*0.67));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawArrows(points, canvas, mPaint);
if (value.getLabel() != null) {
float px = endX;
float py = endY - (int) (value.getSize());
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (value.getSize() * 2.5));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + value.getSize(), py, mPaint);
canvas.restore();
}
} else if (value.getShape() == Shape.EXTENDEDBOLUS) {
Point[] points = new Point[3];
points[0] = new Point((int)endX, (int)(endY-value.getSize()));
points[1] = new Point((int)(endX+value.getSize()), (int)(endY+value.getSize()*0.67));
points[2] = new Point((int)(endX-value.getSize()), (int)(endY+value.getSize()*0.67));
drawArrows(points, canvas, mPaint);
} else if (value.getShape() == Shape.PROFILE) {
if (value.getLabel() != null) {
mPaint.setTextSize((int) (value.getSize() * 3));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
Rect bounds = new Rect();
mPaint.getTextBounds(value.getLabel(), 0, value.getLabel().length(), bounds);
mPaint.setStyle(Paint.Style.STROKE);
float px = endX + bounds.height() / 2;
float py = (float) (graphHeight * ratY + bounds.width() + 10);
canvas.save();
canvas.rotate(-90, px, py);
canvas.drawText(value.getLabel(), px, py, mPaint);
canvas.drawRect(px - 3, bounds.top + py - 3, bounds.right + px + 3, bounds.bottom + py + 3, mPaint);
canvas.restore();
}
}
// set values above point
if (value.getLabel() != null) {
float px = endX;
float py = endY - (int) (getSize());
canvas.save();
canvas.rotate(-45, px, py);
mPaint.setTextSize((int) (getSize() * 2.5));
mPaint.setFakeBoldText(true);
canvas.drawText(value.getLabel(), px + getSize(), py, mPaint);
canvas.restore();
}
}
i++;
@ -276,57 +255,14 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
points[6] = point[0].x;
points[7] = point[0].y;
canvas.save();
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x , point[0].y);
path.lineTo(point[1].x,point[1].y);
path.lineTo(point[2].x,point[2].y);
canvas.drawPath(path,paint);
canvas.restore();
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @return the size of the shape
*/
public float getSize() {
return mStyles.size;
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @param radius the size of the shape
*/
public void setSize(float radius) {
mStyles.size = radius;
}
/**
* @return the shape that will be drawn for each point
*/
public Shape getShape() {
return mStyles.shape;
}
/**
* @param s the shape that will be drawn for each point
*/
public void setShape(Shape s) {
mStyles.shape = s;
}
/**
* Use a custom handler to render your own
* drawing for each data point.
*
* @param shape handler to use a custom drawing
*/
public void setCustomShape(CustomShape shape) {
mCustomShape = shape;
}
}

View file

@ -1,326 +0,0 @@
package info.nightscout.androidaps.plugins.Overview.graphExtensions;
/**
* GraphView
* Copyright (C) 2014 Jonas Gehring
* <p>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License,
* with the "Linking Exception", which can be found at the license.txt
* file in this program.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* with the "Linking Exception" along with this program; if not,
* write to the author Jonas Gehring <g.jjoe64@gmail.com>.
* <p>
* Added by mike
*/
/**
* Added by mike
*/
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.BaseSeries;
import java.util.Iterator;
/**
* Series that plots the data as points.
* The points can be different shapes or a
* complete custom drawing.
*
* @author jjoe64
*/
public class VerticalTextsGraphSeries<E extends DataPointWithLabelInterface> extends BaseSeries<E> {
/**
* interface to implement a custom
* drawing for the data points.
*/
public static interface CustomShape {
/**
* called when drawing a single data point.
* use the x and y coordinates to render your
* drawing at this point.
*
* @param canvas canvas to draw on
* @param paint internal paint object. this has the correct color.
* But you can use your own paint.
* @param x x-coordinate the point has to be drawn to
* @param y y-coordinate the point has to be drawn to
* @param dataPoint the related data point
*/
void draw(Canvas canvas, Paint paint, float x, float y, DataPointWithLabelInterface dataPoint);
}
/**
* choose a predefined shape to render for
* each data point.
* You can also render a custom drawing via {@link com.jjoe64.graphview.series.PointsGraphSeries.CustomShape}
*/
public enum Shape {
/**
* draws a point / circle
*/
POINT,
/**
* draws a triangle
*/
TRIANGLE,
/**
* draws a rectangle
*/
RECTANGLE
}
/**
* wrapped styles for this series
*/
private final class Styles {
/**
* this is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*/
float size;
/**
* the shape that will be drawn for each point.
*/
Shape shape;
}
/**
* wrapped styles
*/
private Styles mStyles;
/**
* internal paint object
*/
private Paint mPaint;
/**
* handler to use a custom drawing
*/
private CustomShape mCustomShape;
/**
* creates the series without data
*/
public VerticalTextsGraphSeries() {
init();
}
/**
* creates the series with data
*
* @param data datapoints
*/
public VerticalTextsGraphSeries(E[] data) {
super(data);
init();
}
/**
* inits the internal objects
* set the defaults
*/
protected void init() {
mStyles = new Styles();
mStyles.size = 20f;
mPaint = new Paint();
mPaint.setStrokeCap(Paint.Cap.ROUND);
setShape(Shape.POINT);
}
/**
* plot the data to the viewport
*
* @param graphView graphview
* @param canvas canvas to draw on
* @param isSecondScale whether it is the second scale
*/
@Override
public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) {
resetDataPoints();
// get data
double maxX = graphView.getViewport().getMaxX(false);
double minX = graphView.getViewport().getMinX(false);
double maxY;
double minY;
if (isSecondScale) {
maxY = graphView.getSecondScale().getMaxY();
minY = graphView.getSecondScale().getMinY();
} else {
maxY = graphView.getViewport().getMaxY(false);
minY = graphView.getViewport().getMinY(false);
}
Iterator<E> values = getValues(minX, maxX);
// draw background
double lastEndY = 0;
double lastEndX = 0;
// draw data
mPaint.setColor(getColor());
double diffY = maxY - minY;
double diffX = maxX - minX;
float graphHeight = graphView.getGraphContentHeight();
float graphWidth = graphView.getGraphContentWidth();
float graphLeft = graphView.getGraphContentLeft();
float graphTop = graphView.getGraphContentTop();
lastEndY = 0;
lastEndX = 0;
float firstX = 0;
int i = 0;
while (values.hasNext()) {
E value = values.next();
double valY = value.getY() - minY;
double ratY = valY / diffY;
double y = graphHeight * ratY;
double valX = value.getX() - minX;
double ratX = valX / diffX;
double x = graphWidth * ratX;
double orgX = x;
double orgY = y;
// overdraw
boolean overdraw = false;
if (x > graphWidth) { // end right
overdraw = true;
}
if (y < 0) { // end bottom
overdraw = true;
}
if (y > graphHeight) { // end top
overdraw = true;
}
/* Fix a bug that continue to show the DOT after Y axis */
if (x < 0) {
overdraw = true;
}
float endX = (float) x + (graphLeft + 1);
float endY = (float) (graphTop - y) + graphHeight;
registerDataPoint(endX, endY, value);
// draw data point
if (!overdraw) {
if (value.getLabel() != null) {
mPaint.setTextSize((int) (getSize() * 3));
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
Rect bounds = new Rect();
mPaint.getTextBounds(value.getLabel(), 0, value.getLabel().length(), bounds);
mPaint.setStyle(Paint.Style.STROKE);
float px = endX + bounds.height() / 2;
float py = (float) (graphHeight * ratY + bounds.width() + 10);
canvas.save();
canvas.rotate(-90, px, py);
canvas.drawText(value.getLabel(), px, py, mPaint);
canvas.drawRect(px - 3, bounds.top + py - 3, bounds.right + px + 3, bounds.bottom + py + 3, mPaint);
canvas.restore();
}
}
i++;
}
}
/**
* helper to render triangle
*
* @param point array with 3 coordinates
* @param canvas canvas to draw on
* @param paint paint object
*/
private void drawArrows(Point[] point, Canvas canvas, Paint paint) {
float[] points = new float[8];
points[0] = point[0].x;
points[1] = point[0].y;
points[2] = point[1].x;
points[3] = point[1].y;
points[4] = point[2].x;
points[5] = point[2].y;
points[6] = point[0].x;
points[7] = point[0].y;
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x, point[0].y);
path.lineTo(point[1].x, point[1].y);
path.lineTo(point[2].x, point[2].y);
canvas.drawPath(path, paint);
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @return the size of the shape
*/
public float getSize() {
return mStyles.size;
}
/**
* This is used for the size of the shape that
* will be drawn.
* This is useless if you are using a custom shape.
*
* @param radius the size of the shape
*/
public void setSize(float radius) {
mStyles.size = radius;
}
/**
* @return the shape that will be drawn for each point
*/
public Shape getShape() {
return mStyles.shape;
}
/**
* @param s the shape that will be drawn for each point
*/
public void setShape(Shape s) {
mStyles.shape = s;
}
/**
* Use a custom handler to render your own
* drawing for each data point.
*
* @param shape handler to use a custom drawing
*/
public void setCustomShape(CustomShape shape) {
mCustomShape = shape;
}
}