Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
78c5967cbf
5 changed files with 494 additions and 384 deletions
|
@ -5,29 +5,13 @@ import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
|
|
||||||
import com.github.mikephil.charting.charts.LineChart;
|
|
||||||
import com.github.mikephil.charting.components.AxisBase;
|
|
||||||
import com.github.mikephil.charting.components.Legend;
|
|
||||||
import com.github.mikephil.charting.components.XAxis;
|
|
||||||
import com.github.mikephil.charting.components.YAxis;
|
|
||||||
import com.github.mikephil.charting.data.Entry;
|
|
||||||
import com.github.mikephil.charting.data.LineData;
|
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
|
||||||
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
|
|
||||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
|
||||||
import com.github.mikephil.charting.utils.Utils;
|
|
||||||
|
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.data.LocationPoint;
|
import net.osmand.data.LocationPoint;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.plus.myplaces.SelectedGPXFragment;
|
|
||||||
import net.osmand.plus.views.OsmandMapTileView;
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.plus.views.Renderable;
|
import net.osmand.plus.views.Renderable;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
@ -51,7 +35,6 @@ import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.DecimalFormatSymbols;
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -65,13 +48,6 @@ import java.util.Map;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import static com.github.mikephil.charting.components.XAxis.XAxisPosition.BOTTOM;
|
|
||||||
import static net.osmand.plus.OsmAndFormatter.FEET_IN_ONE_METER;
|
|
||||||
import static net.osmand.plus.OsmAndFormatter.METERS_IN_KILOMETER;
|
|
||||||
import static net.osmand.plus.OsmAndFormatter.METERS_IN_ONE_MILE;
|
|
||||||
import static net.osmand.plus.OsmAndFormatter.METERS_IN_ONE_NAUTICALMILE;
|
|
||||||
import static net.osmand.plus.OsmAndFormatter.YARDS_IN_ONE_METER;
|
|
||||||
|
|
||||||
public class GPXUtilities {
|
public class GPXUtilities {
|
||||||
public final static Log log = PlatformUtil.getLog(GPXUtilities.class);
|
public final static Log log = PlatformUtil.getLog(GPXUtilities.class);
|
||||||
|
|
||||||
|
@ -1306,345 +1282,4 @@ public class GPXUtilities {
|
||||||
to.warning = from.warning;
|
to.warning = from.warning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupGPXChart(OsmandApplication ctx, LineChart mChart, int yLabelsCount) {
|
|
||||||
OsmandSettings settings = ctx.getSettings();
|
|
||||||
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
|
||||||
boolean useFeet = (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) || (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS);
|
|
||||||
boolean light = settings.isLightContent();
|
|
||||||
|
|
||||||
//mChart.setHardwareAccelerationEnabled(true);
|
|
||||||
mChart.setTouchEnabled(true);
|
|
||||||
mChart.setDragEnabled(true);
|
|
||||||
mChart.setScaleEnabled(true);
|
|
||||||
mChart.setPinchZoom(true);
|
|
||||||
mChart.setScaleYEnabled(false);
|
|
||||||
mChart.setAutoScaleMinMaxEnabled(true);
|
|
||||||
mChart.setDrawBorders(false);
|
|
||||||
mChart.getDescription().setEnabled(false);
|
|
||||||
mChart.setMaxVisibleValueCount(10);
|
|
||||||
mChart.setMinOffset(0f);
|
|
||||||
|
|
||||||
mChart.setExtraTopOffset(24f);
|
|
||||||
mChart.setExtraBottomOffset(16f);
|
|
||||||
|
|
||||||
// create a custom MarkerView (extend MarkerView) and specify the layout
|
|
||||||
// to use for it
|
|
||||||
SelectedGPXFragment.MyMarkerView mv =
|
|
||||||
new SelectedGPXFragment.MyMarkerView(mChart.getContext(), R.layout.chart_marker_view);
|
|
||||||
mv.setChartView(mChart); // For bounds control
|
|
||||||
mChart.setMarker(mv); // Set the marker to the chart
|
|
||||||
mChart.setDrawMarkers(true);
|
|
||||||
|
|
||||||
XAxis xAxis = mChart.getXAxis();
|
|
||||||
xAxis.setDrawAxisLine(false);
|
|
||||||
xAxis.setDrawGridLines(false);
|
|
||||||
xAxis.setPosition(BOTTOM);
|
|
||||||
xAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
|
||||||
|
|
||||||
YAxis yAxis = mChart.getAxisLeft();
|
|
||||||
yAxis.enableGridDashedLine(10f, 5f, 0f);
|
|
||||||
yAxis.setGridColor(ActivityCompat.getColor(mChart.getContext(), R.color.divider_color));
|
|
||||||
yAxis.setDrawAxisLine(false);
|
|
||||||
yAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
|
|
||||||
yAxis.setXOffset(16f);
|
|
||||||
yAxis.setYOffset(-6f);
|
|
||||||
yAxis.setLabelCount(yLabelsCount);
|
|
||||||
yAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
|
||||||
|
|
||||||
yAxis = mChart.getAxisRight();
|
|
||||||
yAxis.enableGridDashedLine(10f, 5f, 0f);
|
|
||||||
yAxis.setGridColor(ActivityCompat.getColor(mChart.getContext(), R.color.divider_color));
|
|
||||||
yAxis.setDrawAxisLine(false);
|
|
||||||
yAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
|
|
||||||
yAxis.setXOffset(16f);
|
|
||||||
yAxis.setYOffset(-6f);
|
|
||||||
yAxis.setLabelCount(yLabelsCount);
|
|
||||||
yAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
|
||||||
yAxis.setEnabled(false);
|
|
||||||
|
|
||||||
Legend legend = mChart.getLegend();
|
|
||||||
legend.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void getXAxisParams(OsmandApplication ctx, float meters, float[] koef, StringBuilder format, StringBuilder unit) {
|
|
||||||
OsmandSettings settings = ctx.getSettings();
|
|
||||||
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
|
||||||
float divX;
|
|
||||||
|
|
||||||
String format1 = "{0,number,0.#} ";
|
|
||||||
String format2 = "{0,number,0.##} ";
|
|
||||||
String fmt = null;
|
|
||||||
int mainUnitStr;
|
|
||||||
float mainUnitInMeters;
|
|
||||||
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS) {
|
|
||||||
mainUnitStr = R.string.km;
|
|
||||||
mainUnitInMeters = METERS_IN_KILOMETER;
|
|
||||||
} else if (mc == OsmandSettings.MetricsConstants.NAUTICAL_MILES) {
|
|
||||||
mainUnitStr = R.string.nm;
|
|
||||||
mainUnitInMeters = METERS_IN_ONE_NAUTICALMILE;
|
|
||||||
} else {
|
|
||||||
mainUnitStr = R.string.mile;
|
|
||||||
mainUnitInMeters = METERS_IN_ONE_MILE;
|
|
||||||
}
|
|
||||||
if (meters > 9.99f * mainUnitInMeters) {
|
|
||||||
fmt = format1;
|
|
||||||
}
|
|
||||||
if (meters >= 100 * mainUnitInMeters ||
|
|
||||||
meters > 9.99f * mainUnitInMeters ||
|
|
||||||
meters > 0.999f * mainUnitInMeters ||
|
|
||||||
mc == OsmandSettings.MetricsConstants.MILES_AND_FEET && meters > 0.249f * mainUnitInMeters ||
|
|
||||||
mc == OsmandSettings.MetricsConstants.MILES_AND_METERS && meters > 0.249f * mainUnitInMeters ||
|
|
||||||
mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS && meters > 0.249f * mainUnitInMeters ||
|
|
||||||
mc == OsmandSettings.MetricsConstants.NAUTICAL_MILES && meters > 0.99f * mainUnitInMeters) {
|
|
||||||
|
|
||||||
divX = mainUnitInMeters;
|
|
||||||
if (fmt == null) {
|
|
||||||
fmt = format2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt = null;
|
|
||||||
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS || mc == OsmandSettings.MetricsConstants.MILES_AND_METERS) {
|
|
||||||
divX = 1f;
|
|
||||||
mainUnitStr = R.string.m;
|
|
||||||
} else if (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) {
|
|
||||||
divX = 1f / FEET_IN_ONE_METER;
|
|
||||||
mainUnitStr = R.string.foot;
|
|
||||||
} else if (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS) {
|
|
||||||
divX = 1f / YARDS_IN_ONE_METER;
|
|
||||||
mainUnitStr = R.string.yard;
|
|
||||||
} else {
|
|
||||||
divX = 1f;
|
|
||||||
mainUnitStr = R.string.m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
koef[0] = divX;
|
|
||||||
format.append(fmt);
|
|
||||||
unit.append(ctx.getString(mainUnitStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LineDataSet createGPXElevationDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis) {
|
|
||||||
OsmandSettings settings = ctx.getSettings();
|
|
||||||
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
|
||||||
boolean useFeet = (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) || (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS);
|
|
||||||
boolean light = settings.isLightContent();
|
|
||||||
final float convEle = useFeet ? 3.28084f : 1.0f;
|
|
||||||
final float meters = analysis.totalDistance;
|
|
||||||
|
|
||||||
float[] koef = new float[] { 1f };
|
|
||||||
StringBuilder fmt = new StringBuilder();
|
|
||||||
StringBuilder unitX = new StringBuilder();
|
|
||||||
|
|
||||||
getXAxisParams(ctx, meters, koef, fmt, unitX);
|
|
||||||
float divX = koef[0];
|
|
||||||
final String formatX = fmt.toString();
|
|
||||||
final String mainUnitX = unitX.toString();
|
|
||||||
|
|
||||||
XAxis xAxis = mChart.getXAxis();
|
|
||||||
xAxis.setValueFormatter(new IAxisValueFormatter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormattedValue(float value, AxisBase axis) {
|
|
||||||
if (!Algorithms.isEmpty(formatX)) {
|
|
||||||
return MessageFormat.format(formatX + mainUnitX, value);
|
|
||||||
} else {
|
|
||||||
return (int)value + " " + mainUnitX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final String mainUnitY = useFeet ? ctx.getString(R.string.foot) : ctx.getString(R.string.m);
|
|
||||||
|
|
||||||
YAxis yAxis;
|
|
||||||
if (useRightAxis) {
|
|
||||||
yAxis = mChart.getAxisRight();
|
|
||||||
yAxis.setEnabled(true);
|
|
||||||
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsRight(mainUnitY);
|
|
||||||
} else {
|
|
||||||
yAxis = mChart.getAxisLeft();
|
|
||||||
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsLeft(mainUnitY);
|
|
||||||
}
|
|
||||||
if (analysis.minElevation >=0) {
|
|
||||||
yAxis.setAxisMinimum(0f);
|
|
||||||
}
|
|
||||||
yAxis.setValueFormatter(new IAxisValueFormatter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormattedValue(float value, AxisBase axis) {
|
|
||||||
return (int)value + " " + mainUnitY;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ArrayList<Entry> values = new ArrayList<>();
|
|
||||||
List<Elevation> elevationData = analysis.elevationData;
|
|
||||||
float nextX = 0;
|
|
||||||
float nextY;
|
|
||||||
for (Elevation e : elevationData) {
|
|
||||||
if (e.distance > 0) {
|
|
||||||
nextX += (float) e.distance / divX;
|
|
||||||
nextY = (float) (e.elevation * convEle);
|
|
||||||
values.add(new Entry(nextX, nextY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LineDataSet dataSet = new LineDataSet(values, "");
|
|
||||||
|
|
||||||
dataSet.setColor(Color.BLACK);
|
|
||||||
dataSet.setDrawValues(false);
|
|
||||||
dataSet.setLineWidth(0f);
|
|
||||||
dataSet.setValueTextSize(9f);
|
|
||||||
dataSet.setDrawFilled(true);
|
|
||||||
dataSet.setFormLineWidth(1f);
|
|
||||||
dataSet.setFormSize(15.f);
|
|
||||||
|
|
||||||
dataSet.setDrawCircles(false);
|
|
||||||
dataSet.setDrawCircleHole(false);
|
|
||||||
|
|
||||||
dataSet.setHighlightEnabled(true);
|
|
||||||
dataSet.setDrawVerticalHighlightIndicator(true);
|
|
||||||
dataSet.setDrawHorizontalHighlightIndicator(false);
|
|
||||||
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
|
||||||
|
|
||||||
if (Utils.getSDKInt() >= 18) {
|
|
||||||
// fill drawable only supported on api level 18 and above
|
|
||||||
Drawable drawable = ContextCompat.getDrawable(mChart.getContext(), R.drawable.line_chart_fade_blue);
|
|
||||||
dataSet.setFillDrawable(drawable);
|
|
||||||
} else {
|
|
||||||
dataSet.setFillColor(ContextCompat.getColor(mChart.getContext(), R.color.transport_route_line));
|
|
||||||
}
|
|
||||||
if (useRightAxis) {
|
|
||||||
dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
|
||||||
}
|
|
||||||
return dataSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setGPXElevationChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis) {
|
|
||||||
LineDataSet dataSet = createGPXElevationDataSet(ctx, mChart, analysis, useRightAxis);
|
|
||||||
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
|
||||||
dataSets.add(dataSet);
|
|
||||||
LineData data = new LineData(dataSets);
|
|
||||||
mChart.setData(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LineDataSet createGPXSpeedDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis) {
|
|
||||||
OsmandSettings settings = ctx.getSettings();
|
|
||||||
boolean light = settings.isLightContent();
|
|
||||||
final float meters = analysis.totalDistance;
|
|
||||||
|
|
||||||
float[] koef = new float[] { 1f };
|
|
||||||
StringBuilder fmt = new StringBuilder();
|
|
||||||
StringBuilder unitX = new StringBuilder();
|
|
||||||
|
|
||||||
getXAxisParams(ctx, meters, koef, fmt, unitX);
|
|
||||||
float divX = koef[0];
|
|
||||||
final String formatX = fmt.toString();
|
|
||||||
final String mainUnitX = unitX.toString();
|
|
||||||
|
|
||||||
XAxis xAxis = mChart.getXAxis();
|
|
||||||
xAxis.setValueFormatter(new IAxisValueFormatter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormattedValue(float value, AxisBase axis) {
|
|
||||||
if (!Algorithms.isEmpty(formatX)) {
|
|
||||||
return MessageFormat.format(formatX + mainUnitX, value);
|
|
||||||
} else {
|
|
||||||
return (int)value + " " + mainUnitX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
OsmandSettings.SpeedConstants sps = settings.SPEED_SYSTEM.get();
|
|
||||||
float mulSpeed = Float.NaN;
|
|
||||||
float divSpeed = Float.NaN;
|
|
||||||
final String mainUnitY = sps.toShortString(ctx);
|
|
||||||
if (sps == OsmandSettings.SpeedConstants.KILOMETERS_PER_HOUR) {
|
|
||||||
mulSpeed = 3.6f;
|
|
||||||
} else if (sps == OsmandSettings.SpeedConstants.MILES_PER_HOUR) {
|
|
||||||
mulSpeed = 3.6f * METERS_IN_KILOMETER / METERS_IN_ONE_MILE;
|
|
||||||
} else if (sps == OsmandSettings.SpeedConstants.NAUTICALMILES_PER_HOUR) {
|
|
||||||
mulSpeed = 3.6f * METERS_IN_KILOMETER / METERS_IN_ONE_NAUTICALMILE;
|
|
||||||
} else if (sps == OsmandSettings.SpeedConstants.MINUTES_PER_KILOMETER) {
|
|
||||||
divSpeed = METERS_IN_KILOMETER / 60;
|
|
||||||
} else if (sps == OsmandSettings.SpeedConstants.MINUTES_PER_MILE) {
|
|
||||||
divSpeed = METERS_IN_ONE_MILE / 60;
|
|
||||||
} else {
|
|
||||||
mulSpeed = 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
YAxis yAxis;
|
|
||||||
if (useRightAxis) {
|
|
||||||
yAxis = mChart.getAxisRight();
|
|
||||||
yAxis.setEnabled(true);
|
|
||||||
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsRight(mainUnitY);
|
|
||||||
} else {
|
|
||||||
yAxis = mChart.getAxisLeft();
|
|
||||||
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsLeft(mainUnitY);
|
|
||||||
}
|
|
||||||
yAxis.setAxisMinimum(0f);
|
|
||||||
yAxis.setValueFormatter(new IAxisValueFormatter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormattedValue(float value, AxisBase axis) {
|
|
||||||
return (int)value + " " + mainUnitY;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ArrayList<Entry> values = new ArrayList<>();
|
|
||||||
List<Speed> speedData = analysis.speedData;
|
|
||||||
float nextX = 0;
|
|
||||||
float nextY;
|
|
||||||
for (Speed s : speedData) {
|
|
||||||
if (s.distance > 0) {
|
|
||||||
nextX += (float) s.distance / divX;
|
|
||||||
if (Float.isNaN(divSpeed)) {
|
|
||||||
nextY = (float) (s.speed * mulSpeed);
|
|
||||||
} else {
|
|
||||||
nextY = (float) (divSpeed / s.speed);
|
|
||||||
}
|
|
||||||
if (nextY < 0) {
|
|
||||||
nextY = 0;
|
|
||||||
}
|
|
||||||
values.add(new Entry(nextX, nextY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LineDataSet dataSet = new LineDataSet(values, "");
|
|
||||||
|
|
||||||
dataSet.setColor(Color.BLACK);
|
|
||||||
dataSet.setDrawValues(false);
|
|
||||||
dataSet.setLineWidth(0f);
|
|
||||||
dataSet.setValueTextSize(9f);
|
|
||||||
dataSet.setDrawFilled(true);
|
|
||||||
dataSet.setFormLineWidth(1f);
|
|
||||||
dataSet.setFormSize(15.f);
|
|
||||||
|
|
||||||
dataSet.setDrawCircles(false);
|
|
||||||
dataSet.setDrawCircleHole(false);
|
|
||||||
|
|
||||||
dataSet.setHighlightEnabled(true);
|
|
||||||
dataSet.setDrawVerticalHighlightIndicator(true);
|
|
||||||
dataSet.setDrawHorizontalHighlightIndicator(false);
|
|
||||||
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
|
||||||
|
|
||||||
if (Utils.getSDKInt() >= 18) {
|
|
||||||
// fill drawable only supported on api level 18 and above
|
|
||||||
Drawable drawable = ContextCompat.getDrawable(mChart.getContext(), R.drawable.line_chart_fade_red);
|
|
||||||
dataSet.setFillDrawable(drawable);
|
|
||||||
} else {
|
|
||||||
dataSet.setFillColor(ContextCompat.getColor(mChart.getContext(), R.color.transport_end));
|
|
||||||
}
|
|
||||||
if (useRightAxis) {
|
|
||||||
dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
|
||||||
}
|
|
||||||
return dataSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setGPXSpeedChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis) {
|
|
||||||
LineDataSet dataSet = createGPXSpeedDataSet(ctx, mChart, analysis, useRightAxis);
|
|
||||||
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
|
||||||
dataSets.add(dataSet);
|
|
||||||
LineData data = new LineData(dataSets);
|
|
||||||
mChart.setData(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.osmand.plus;
|
package net.osmand.plus;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
|
||||||
|
@ -660,5 +661,6 @@ public class GpxSelectionHelper {
|
||||||
public String url;
|
public String url;
|
||||||
public Bitmap image;
|
public Bitmap image;
|
||||||
public boolean expanded;
|
public boolean expanded;
|
||||||
|
public Matrix chartMatrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.github.mikephil.charting.charts.LineChart;
|
import com.github.mikephil.charting.charts.LineChart;
|
||||||
import com.github.mikephil.charting.utils.Utils;
|
|
||||||
|
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
|
@ -41,6 +40,7 @@ import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandSettings;
|
import net.osmand.plus.OsmandSettings;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.helpers.GpxUiHelper;
|
||||||
import net.osmand.plus.mapcontextmenu.other.MapRouteInfoMenu;
|
import net.osmand.plus.mapcontextmenu.other.MapRouteInfoMenu;
|
||||||
import net.osmand.plus.routing.RouteDirectionInfo;
|
import net.osmand.plus.routing.RouteDirectionInfo;
|
||||||
import net.osmand.plus.routing.RoutingHelper;
|
import net.osmand.plus.routing.RoutingHelper;
|
||||||
|
@ -212,7 +212,7 @@ public class ShowRouteInfoDialogFragment extends DialogFragment {
|
||||||
private void buildHeader(View headerView) {
|
private void buildHeader(View headerView) {
|
||||||
OsmandApplication app = getMyApplication();
|
OsmandApplication app = getMyApplication();
|
||||||
LineChart mChart = (LineChart) headerView.findViewById(R.id.chart);
|
LineChart mChart = (LineChart) headerView.findViewById(R.id.chart);
|
||||||
GPXUtilities.setupGPXChart(app, mChart, 4);
|
GpxUiHelper.setupGPXChart(app, mChart, 4);
|
||||||
mChart.setOnTouchListener(new View.OnTouchListener() {
|
mChart.setOnTouchListener(new View.OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
@ -222,7 +222,7 @@ public class ShowRouteInfoDialogFragment extends DialogFragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
|
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
|
||||||
GPXUtilities.setGPXElevationChartData(app, mChart, analysis, false);
|
GpxUiHelper.setGPXElevationChartData(app, mChart, analysis, false, true);
|
||||||
|
|
||||||
((TextView) headerView.findViewById(R.id.average_text))
|
((TextView) headerView.findViewById(R.id.average_text))
|
||||||
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
|
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
|
||||||
|
|
|
@ -7,9 +7,11 @@ import android.app.ProgressDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.ListPopupWindow;
|
import android.support.v7.widget.ListPopupWindow;
|
||||||
|
@ -31,6 +33,21 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.github.mikephil.charting.charts.LineChart;
|
||||||
|
import com.github.mikephil.charting.components.AxisBase;
|
||||||
|
import com.github.mikephil.charting.components.Legend;
|
||||||
|
import com.github.mikephil.charting.components.XAxis;
|
||||||
|
import com.github.mikephil.charting.components.YAxis;
|
||||||
|
import com.github.mikephil.charting.data.Entry;
|
||||||
|
import com.github.mikephil.charting.data.LineData;
|
||||||
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
|
import com.github.mikephil.charting.formatter.DefaultFillFormatter;
|
||||||
|
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
|
||||||
|
import com.github.mikephil.charting.formatter.IFillFormatter;
|
||||||
|
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
|
||||||
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||||
|
import com.github.mikephil.charting.utils.Utils;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.CallbackWithObject;
|
import net.osmand.CallbackWithObject;
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
|
@ -54,6 +71,7 @@ import net.osmand.plus.activities.SettingsActivity;
|
||||||
import net.osmand.plus.dialogs.ConfigureMapMenu;
|
import net.osmand.plus.dialogs.ConfigureMapMenu;
|
||||||
import net.osmand.plus.dialogs.ConfigureMapMenu.AppearanceListItem;
|
import net.osmand.plus.dialogs.ConfigureMapMenu.AppearanceListItem;
|
||||||
import net.osmand.plus.dialogs.ConfigureMapMenu.GpxAppearanceAdapter;
|
import net.osmand.plus.dialogs.ConfigureMapMenu.GpxAppearanceAdapter;
|
||||||
|
import net.osmand.plus.myplaces.SelectedGPXFragment;
|
||||||
import net.osmand.render.RenderingRuleProperty;
|
import net.osmand.render.RenderingRuleProperty;
|
||||||
import net.osmand.render.RenderingRulesStorage;
|
import net.osmand.render.RenderingRulesStorage;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
@ -63,6 +81,7 @@ import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -70,6 +89,12 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.github.mikephil.charting.components.XAxis.XAxisPosition.BOTTOM;
|
||||||
|
import static net.osmand.plus.OsmAndFormatter.FEET_IN_ONE_METER;
|
||||||
|
import static net.osmand.plus.OsmAndFormatter.METERS_IN_KILOMETER;
|
||||||
|
import static net.osmand.plus.OsmAndFormatter.METERS_IN_ONE_MILE;
|
||||||
|
import static net.osmand.plus.OsmAndFormatter.METERS_IN_ONE_NAUTICALMILE;
|
||||||
|
import static net.osmand.plus.OsmAndFormatter.YARDS_IN_ONE_METER;
|
||||||
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR;
|
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_COLOR_ATTR;
|
||||||
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_WIDTH_ATTR;
|
import static net.osmand.plus.dialogs.ConfigureMapMenu.CURRENT_TRACK_WIDTH_ATTR;
|
||||||
import static net.osmand.plus.dialogs.ConfigureMapMenu.refreshMapComplete;
|
import static net.osmand.plus.dialogs.ConfigureMapMenu.refreshMapComplete;
|
||||||
|
@ -819,6 +844,387 @@ public class GpxUiHelper {
|
||||||
}, "Loading gpx").start(); //$NON-NLS-1$
|
}, "Loading gpx").start(); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setupGPXChart(OsmandApplication ctx, LineChart mChart, int yLabelsCount) {
|
||||||
|
OsmandSettings settings = ctx.getSettings();
|
||||||
|
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
||||||
|
boolean useFeet = (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) || (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS);
|
||||||
|
boolean light = settings.isLightContent();
|
||||||
|
|
||||||
|
//mChart.setHardwareAccelerationEnabled(true);
|
||||||
|
mChart.setTouchEnabled(true);
|
||||||
|
mChart.setDragEnabled(true);
|
||||||
|
mChart.setScaleEnabled(true);
|
||||||
|
mChart.setPinchZoom(true);
|
||||||
|
mChart.setScaleYEnabled(false);
|
||||||
|
mChart.setAutoScaleMinMaxEnabled(true);
|
||||||
|
mChart.setDrawBorders(false);
|
||||||
|
mChart.getDescription().setEnabled(false);
|
||||||
|
mChart.setMaxVisibleValueCount(10);
|
||||||
|
mChart.setMinOffset(0f);
|
||||||
|
|
||||||
|
mChart.setExtraTopOffset(24f);
|
||||||
|
mChart.setExtraBottomOffset(16f);
|
||||||
|
|
||||||
|
// create a custom MarkerView (extend MarkerView) and specify the layout
|
||||||
|
// to use for it
|
||||||
|
SelectedGPXFragment.MyMarkerView mv =
|
||||||
|
new SelectedGPXFragment.MyMarkerView(mChart.getContext(), R.layout.chart_marker_view);
|
||||||
|
mv.setChartView(mChart); // For bounds control
|
||||||
|
mChart.setMarker(mv); // Set the marker to the chart
|
||||||
|
mChart.setDrawMarkers(true);
|
||||||
|
|
||||||
|
XAxis xAxis = mChart.getXAxis();
|
||||||
|
xAxis.setDrawAxisLine(false);
|
||||||
|
xAxis.setDrawGridLines(false);
|
||||||
|
xAxis.setPosition(BOTTOM);
|
||||||
|
xAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
|
YAxis yAxis = mChart.getAxisLeft();
|
||||||
|
yAxis.enableGridDashedLine(10f, 5f, 0f);
|
||||||
|
yAxis.setGridColor(ActivityCompat.getColor(mChart.getContext(), R.color.divider_color));
|
||||||
|
yAxis.setDrawAxisLine(false);
|
||||||
|
yAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
|
||||||
|
yAxis.setXOffset(16f);
|
||||||
|
yAxis.setYOffset(-6f);
|
||||||
|
yAxis.setLabelCount(yLabelsCount);
|
||||||
|
yAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
|
yAxis = mChart.getAxisRight();
|
||||||
|
yAxis.enableGridDashedLine(10f, 5f, 0f);
|
||||||
|
yAxis.setGridColor(ActivityCompat.getColor(mChart.getContext(), R.color.divider_color));
|
||||||
|
yAxis.setDrawAxisLine(false);
|
||||||
|
yAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
|
||||||
|
yAxis.setXOffset(16f);
|
||||||
|
yAxis.setYOffset(-6f);
|
||||||
|
yAxis.setLabelCount(yLabelsCount);
|
||||||
|
yAxis.setTextColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
yAxis.setEnabled(false);
|
||||||
|
|
||||||
|
Legend legend = mChart.getLegend();
|
||||||
|
legend.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getXAxisParams(OsmandApplication ctx, float meters, float[] koef, StringBuilder format, StringBuilder unit) {
|
||||||
|
OsmandSettings settings = ctx.getSettings();
|
||||||
|
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
||||||
|
float divX;
|
||||||
|
|
||||||
|
String format1 = "{0,number,0.#} ";
|
||||||
|
String format2 = "{0,number,0.##} ";
|
||||||
|
String fmt = null;
|
||||||
|
float granularity = 1f;
|
||||||
|
int mainUnitStr;
|
||||||
|
float mainUnitInMeters;
|
||||||
|
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS) {
|
||||||
|
mainUnitStr = R.string.km;
|
||||||
|
mainUnitInMeters = METERS_IN_KILOMETER;
|
||||||
|
} else if (mc == OsmandSettings.MetricsConstants.NAUTICAL_MILES) {
|
||||||
|
mainUnitStr = R.string.nm;
|
||||||
|
mainUnitInMeters = METERS_IN_ONE_NAUTICALMILE;
|
||||||
|
} else {
|
||||||
|
mainUnitStr = R.string.mile;
|
||||||
|
mainUnitInMeters = METERS_IN_ONE_MILE;
|
||||||
|
}
|
||||||
|
if (meters > 9.99f * mainUnitInMeters) {
|
||||||
|
fmt = format1;
|
||||||
|
granularity = .1f;
|
||||||
|
}
|
||||||
|
if (meters >= 100 * mainUnitInMeters ||
|
||||||
|
meters > 9.99f * mainUnitInMeters ||
|
||||||
|
meters > 0.999f * mainUnitInMeters ||
|
||||||
|
mc == OsmandSettings.MetricsConstants.MILES_AND_FEET && meters > 0.249f * mainUnitInMeters ||
|
||||||
|
mc == OsmandSettings.MetricsConstants.MILES_AND_METERS && meters > 0.249f * mainUnitInMeters ||
|
||||||
|
mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS && meters > 0.249f * mainUnitInMeters ||
|
||||||
|
mc == OsmandSettings.MetricsConstants.NAUTICAL_MILES && meters > 0.99f * mainUnitInMeters) {
|
||||||
|
|
||||||
|
divX = mainUnitInMeters;
|
||||||
|
if (fmt == null) {
|
||||||
|
fmt = format2;
|
||||||
|
granularity = .01f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt = null;
|
||||||
|
granularity = 1f;
|
||||||
|
if (mc == OsmandSettings.MetricsConstants.KILOMETERS_AND_METERS || mc == OsmandSettings.MetricsConstants.MILES_AND_METERS) {
|
||||||
|
divX = 1f;
|
||||||
|
mainUnitStr = R.string.m;
|
||||||
|
} else if (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) {
|
||||||
|
divX = 1f / FEET_IN_ONE_METER;
|
||||||
|
mainUnitStr = R.string.foot;
|
||||||
|
} else if (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS) {
|
||||||
|
divX = 1f / YARDS_IN_ONE_METER;
|
||||||
|
mainUnitStr = R.string.yard;
|
||||||
|
} else {
|
||||||
|
divX = 1f;
|
||||||
|
mainUnitStr = R.string.m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
koef[0] = divX;
|
||||||
|
if (fmt != null) {
|
||||||
|
format.append(fmt);
|
||||||
|
}
|
||||||
|
unit.append(ctx.getString(mainUnitStr));
|
||||||
|
return granularity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OrderedLineDataSet createGPXElevationDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
|
OsmandSettings settings = ctx.getSettings();
|
||||||
|
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
||||||
|
boolean useFeet = (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) || (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS);
|
||||||
|
boolean light = settings.isLightContent();
|
||||||
|
final float convEle = useFeet ? 3.28084f : 1.0f;
|
||||||
|
final float meters = analysis.totalDistance;
|
||||||
|
|
||||||
|
float[] koef = new float[] { 1f };
|
||||||
|
StringBuilder fmt = new StringBuilder();
|
||||||
|
StringBuilder unitX = new StringBuilder();
|
||||||
|
|
||||||
|
float granularity = getXAxisParams(ctx, meters, koef, fmt, unitX);
|
||||||
|
float divX = koef[0];
|
||||||
|
final String formatX = fmt.toString();
|
||||||
|
final String mainUnitX = unitX.toString();
|
||||||
|
|
||||||
|
XAxis xAxis = mChart.getXAxis();
|
||||||
|
xAxis.setGranularity(granularity);
|
||||||
|
xAxis.setValueFormatter(new IAxisValueFormatter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormattedValue(float value, AxisBase axis) {
|
||||||
|
if (!Algorithms.isEmpty(formatX)) {
|
||||||
|
return MessageFormat.format(formatX + mainUnitX, value);
|
||||||
|
} else {
|
||||||
|
return (int)value + " " + mainUnitX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final String mainUnitY = useFeet ? ctx.getString(R.string.foot) : ctx.getString(R.string.m);
|
||||||
|
|
||||||
|
YAxis yAxis;
|
||||||
|
if (useRightAxis) {
|
||||||
|
yAxis = mChart.getAxisRight();
|
||||||
|
yAxis.setEnabled(true);
|
||||||
|
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsRight(mainUnitY);
|
||||||
|
} else {
|
||||||
|
yAxis = mChart.getAxisLeft();
|
||||||
|
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsLeft(mainUnitY);
|
||||||
|
}
|
||||||
|
yAxis.setGranularity(1f);
|
||||||
|
yAxis.setValueFormatter(new IAxisValueFormatter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormattedValue(float value, AxisBase axis) {
|
||||||
|
return (int)value + " " + mainUnitY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayList<Entry> values = new ArrayList<>();
|
||||||
|
List<GPXUtilities.Elevation> elevationData = analysis.elevationData;
|
||||||
|
float nextX = 0;
|
||||||
|
float nextY;
|
||||||
|
for (GPXUtilities.Elevation e : elevationData) {
|
||||||
|
if (e.distance > 0) {
|
||||||
|
nextX += (float) e.distance / divX;
|
||||||
|
nextY = (float) (e.elevation * convEle);
|
||||||
|
values.add(new Entry(nextX, nextY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "");
|
||||||
|
dataSet.priority = (float) (analysis.avgElevation - analysis.minElevation) * convEle;
|
||||||
|
if (drawFilled) {
|
||||||
|
dataSet.setColor(Color.BLACK);
|
||||||
|
dataSet.setLineWidth(0f);
|
||||||
|
dataSet.setDrawFilled(true);
|
||||||
|
} else {
|
||||||
|
dataSet.setColor(ContextCompat.getColor(mChart.getContext(), R.color.map_widget_blue));
|
||||||
|
dataSet.setLineWidth(1f);
|
||||||
|
dataSet.setDrawFilled(false);
|
||||||
|
}
|
||||||
|
dataSet.setDrawValues(false);
|
||||||
|
dataSet.setValueTextSize(9f);
|
||||||
|
dataSet.setFormLineWidth(1f);
|
||||||
|
dataSet.setFormSize(15.f);
|
||||||
|
|
||||||
|
dataSet.setDrawCircles(false);
|
||||||
|
dataSet.setDrawCircleHole(false);
|
||||||
|
|
||||||
|
dataSet.setHighlightEnabled(true);
|
||||||
|
dataSet.setDrawVerticalHighlightIndicator(true);
|
||||||
|
dataSet.setDrawHorizontalHighlightIndicator(false);
|
||||||
|
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
|
if (Utils.getSDKInt() >= 18) {
|
||||||
|
// fill drawable only supported on api level 18 and above
|
||||||
|
Drawable drawable = ContextCompat.getDrawable(mChart.getContext(), R.drawable.line_chart_fade_blue);
|
||||||
|
dataSet.setFillDrawable(drawable);
|
||||||
|
} else {
|
||||||
|
dataSet.setFillColor(ContextCompat.getColor(mChart.getContext(), R.color.transport_route_line));
|
||||||
|
}
|
||||||
|
dataSet.setFillFormatter(new IFillFormatter() {
|
||||||
|
@Override
|
||||||
|
public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) {
|
||||||
|
return dataProvider.getYChartMin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (useRightAxis) {
|
||||||
|
dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
||||||
|
}
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setGPXElevationChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
|
LineDataSet dataSet = createGPXElevationDataSet(ctx, mChart, analysis, useRightAxis, drawFilled);
|
||||||
|
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
|
dataSets.add(dataSet);
|
||||||
|
LineData data = new LineData(dataSets);
|
||||||
|
mChart.setData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OrderedLineDataSet createGPXSpeedDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
|
OsmandSettings settings = ctx.getSettings();
|
||||||
|
boolean light = settings.isLightContent();
|
||||||
|
final float meters = analysis.totalDistance;
|
||||||
|
|
||||||
|
float[] koef = new float[] { 1f };
|
||||||
|
StringBuilder fmt = new StringBuilder();
|
||||||
|
StringBuilder unitX = new StringBuilder();
|
||||||
|
|
||||||
|
float granularity = getXAxisParams(ctx, meters, koef, fmt, unitX);
|
||||||
|
float divX = koef[0];
|
||||||
|
final String formatX = fmt.toString();
|
||||||
|
final String mainUnitX = unitX.toString();
|
||||||
|
|
||||||
|
XAxis xAxis = mChart.getXAxis();
|
||||||
|
xAxis.setGranularity(granularity);
|
||||||
|
xAxis.setValueFormatter(new IAxisValueFormatter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormattedValue(float value, AxisBase axis) {
|
||||||
|
if (!Algorithms.isEmpty(formatX)) {
|
||||||
|
return MessageFormat.format(formatX + mainUnitX, value);
|
||||||
|
} else {
|
||||||
|
return (int)value + " " + mainUnitX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
OsmandSettings.SpeedConstants sps = settings.SPEED_SYSTEM.get();
|
||||||
|
float mulSpeed = Float.NaN;
|
||||||
|
float divSpeed = Float.NaN;
|
||||||
|
final String mainUnitY = sps.toShortString(ctx);
|
||||||
|
if (sps == OsmandSettings.SpeedConstants.KILOMETERS_PER_HOUR) {
|
||||||
|
mulSpeed = 3.6f;
|
||||||
|
} else if (sps == OsmandSettings.SpeedConstants.MILES_PER_HOUR) {
|
||||||
|
mulSpeed = 3.6f * METERS_IN_KILOMETER / METERS_IN_ONE_MILE;
|
||||||
|
} else if (sps == OsmandSettings.SpeedConstants.NAUTICALMILES_PER_HOUR) {
|
||||||
|
mulSpeed = 3.6f * METERS_IN_KILOMETER / METERS_IN_ONE_NAUTICALMILE;
|
||||||
|
} else if (sps == OsmandSettings.SpeedConstants.MINUTES_PER_KILOMETER) {
|
||||||
|
divSpeed = METERS_IN_KILOMETER / 60;
|
||||||
|
} else if (sps == OsmandSettings.SpeedConstants.MINUTES_PER_MILE) {
|
||||||
|
divSpeed = METERS_IN_ONE_MILE / 60;
|
||||||
|
} else {
|
||||||
|
mulSpeed = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
YAxis yAxis;
|
||||||
|
if (useRightAxis) {
|
||||||
|
yAxis = mChart.getAxisRight();
|
||||||
|
yAxis.setEnabled(true);
|
||||||
|
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsRight(mainUnitY);
|
||||||
|
} else {
|
||||||
|
yAxis = mChart.getAxisLeft();
|
||||||
|
((SelectedGPXFragment.MyMarkerView)mChart.getMarker()).setUnitsLeft(mainUnitY);
|
||||||
|
}
|
||||||
|
yAxis.setAxisMinimum(0f);
|
||||||
|
yAxis.setValueFormatter(new IAxisValueFormatter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormattedValue(float value, AxisBase axis) {
|
||||||
|
return (int)value + " " + mainUnitY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayList<Entry> values = new ArrayList<>();
|
||||||
|
List<GPXUtilities.Speed> speedData = analysis.speedData;
|
||||||
|
float nextX = 0;
|
||||||
|
float nextY;
|
||||||
|
for (GPXUtilities.Speed s : speedData) {
|
||||||
|
if (s.distance > 0) {
|
||||||
|
nextX += (float) s.distance / divX;
|
||||||
|
if (Float.isNaN(divSpeed)) {
|
||||||
|
nextY = (float) (s.speed * mulSpeed);
|
||||||
|
} else {
|
||||||
|
nextY = (float) (divSpeed / s.speed);
|
||||||
|
}
|
||||||
|
if (nextY < 0) {
|
||||||
|
nextY = 0;
|
||||||
|
}
|
||||||
|
values.add(new Entry(nextX, nextY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "");
|
||||||
|
|
||||||
|
if (Float.isNaN(divSpeed)) {
|
||||||
|
dataSet.priority = analysis.avgSpeed * mulSpeed;
|
||||||
|
} else {
|
||||||
|
dataSet.priority = divSpeed / analysis.avgSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawFilled) {
|
||||||
|
dataSet.setColor(Color.BLACK);
|
||||||
|
dataSet.setLineWidth(0f);
|
||||||
|
dataSet.setDrawFilled(true);
|
||||||
|
} else {
|
||||||
|
dataSet.setColor(ContextCompat.getColor(mChart.getContext(), R.color.transport_end));
|
||||||
|
dataSet.setLineWidth(1f);
|
||||||
|
dataSet.setDrawFilled(false);
|
||||||
|
}
|
||||||
|
dataSet.setDrawValues(false);
|
||||||
|
dataSet.setValueTextSize(9f);
|
||||||
|
dataSet.setFormLineWidth(1f);
|
||||||
|
dataSet.setFormSize(15.f);
|
||||||
|
|
||||||
|
dataSet.setDrawCircles(false);
|
||||||
|
dataSet.setDrawCircleHole(false);
|
||||||
|
|
||||||
|
dataSet.setHighlightEnabled(true);
|
||||||
|
dataSet.setDrawVerticalHighlightIndicator(true);
|
||||||
|
dataSet.setDrawHorizontalHighlightIndicator(false);
|
||||||
|
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
|
if (Utils.getSDKInt() >= 18) {
|
||||||
|
// fill drawable only supported on api level 18 and above
|
||||||
|
Drawable drawable = ContextCompat.getDrawable(mChart.getContext(), R.drawable.line_chart_fade_red);
|
||||||
|
dataSet.setFillDrawable(drawable);
|
||||||
|
} else {
|
||||||
|
dataSet.setFillColor(ContextCompat.getColor(mChart.getContext(), R.color.transport_end));
|
||||||
|
}
|
||||||
|
if (useRightAxis) {
|
||||||
|
dataSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
|
||||||
|
}
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setGPXSpeedChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
|
LineDataSet dataSet = createGPXSpeedDataSet(ctx, mChart, analysis, useRightAxis, drawFilled);
|
||||||
|
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
|
dataSets.add(dataSet);
|
||||||
|
LineData data = new LineData(dataSets);
|
||||||
|
mChart.setData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OrderedLineDataSet extends LineDataSet {
|
||||||
|
|
||||||
|
public float priority;
|
||||||
|
|
||||||
|
public OrderedLineDataSet(List<Entry> yVals, String label) {
|
||||||
|
super(yVals, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class GPXInfo {
|
public static class GPXInfo {
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private long lastModified;
|
private long lastModified;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.osmand.plus.myplaces;
|
package net.osmand.plus.myplaces;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
import android.support.v4.view.PagerAdapter;
|
import android.support.v4.view.PagerAdapter;
|
||||||
|
@ -19,11 +20,11 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import com.github.mikephil.charting.charts.LineChart;
|
import com.github.mikephil.charting.charts.LineChart;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
|
||||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||||
|
import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture;
|
||||||
|
import com.github.mikephil.charting.listener.OnChartGestureListener;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.plus.GPXUtilities;
|
|
||||||
import net.osmand.plus.GPXUtilities.GPXTrackAnalysis;
|
import net.osmand.plus.GPXUtilities.GPXTrackAnalysis;
|
||||||
import net.osmand.plus.GpxSelectionHelper;
|
import net.osmand.plus.GpxSelectionHelper;
|
||||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
||||||
|
@ -32,6 +33,8 @@ import net.osmand.plus.IconsCache;
|
||||||
import net.osmand.plus.OsmAndFormatter;
|
import net.osmand.plus.OsmAndFormatter;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.helpers.GpxUiHelper;
|
||||||
|
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
|
||||||
import net.osmand.plus.views.controls.PagerSlidingTabStrip;
|
import net.osmand.plus.views.controls.PagerSlidingTabStrip;
|
||||||
import net.osmand.plus.views.controls.PagerSlidingTabStrip.CustomTabProvider;
|
import net.osmand.plus.views.controls.PagerSlidingTabStrip.CustomTabProvider;
|
||||||
import net.osmand.plus.views.controls.WrapContentHeightViewPager;
|
import net.osmand.plus.views.controls.WrapContentHeightViewPager;
|
||||||
|
@ -99,6 +102,7 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||||
View row = convertView;
|
View row = convertView;
|
||||||
PagerSlidingTabStrip tabLayout = null;
|
PagerSlidingTabStrip tabLayout = null;
|
||||||
|
WrapContentHeightViewPager pager;
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
LayoutInflater inflater = getMyActivity().getLayoutInflater();
|
LayoutInflater inflater = getMyActivity().getLayoutInflater();
|
||||||
row = inflater.inflate(R.layout.gpx_list_item_tab_content, parent, false);
|
row = inflater.inflate(R.layout.gpx_list_item_tab_content, parent, false);
|
||||||
|
@ -113,12 +117,15 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
tabLayout.setTextSize(AndroidUtils.spToPx(app, 12f));
|
tabLayout.setTextSize(AndroidUtils.spToPx(app, 12f));
|
||||||
tabLayout.setShouldExpand(true);
|
tabLayout.setShouldExpand(true);
|
||||||
tabLayout.setTabSelectionType(PagerSlidingTabStrip.TabSelectionType.SOLID_COLOR);
|
tabLayout.setTabSelectionType(PagerSlidingTabStrip.TabSelectionType.SOLID_COLOR);
|
||||||
|
pager = (WrapContentHeightViewPager) row.findViewById(R.id.pager);
|
||||||
|
pager.setSwipeable(false);
|
||||||
|
} else {
|
||||||
|
pager = (WrapContentHeightViewPager) row.findViewById(R.id.pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tabLayout != null) {
|
if (tabLayout != null) {
|
||||||
final WrapContentHeightViewPager pager = (WrapContentHeightViewPager) row.findViewById(R.id.pager);
|
|
||||||
pager.setAdapter(getPagerAdapter(tabLayout, getItem(position)));
|
pager.setAdapter(getPagerAdapter(tabLayout, getItem(position)));
|
||||||
pager.setSwipeable(false);
|
pager.setOffscreenPageLimit(2);
|
||||||
tabLayout.setViewPager(pager);
|
tabLayout.setViewPager(pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +216,7 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
OsmandApplication app = (OsmandApplication) getActivity().getApplicationContext();
|
OsmandApplication app = (OsmandApplication) getActivity().getApplicationContext();
|
||||||
if (gpxItem != null) {
|
if (gpxItem != null) {
|
||||||
GPXTrackAnalysis analysis = gpxItem.analysis;
|
GPXTrackAnalysis analysis = gpxItem.analysis;
|
||||||
LineChart chart = (LineChart) view.findViewById(R.id.chart);
|
final LineChart chart = (LineChart) view.findViewById(R.id.chart);
|
||||||
chart.setOnTouchListener(new View.OnTouchListener() {
|
chart.setOnTouchListener(new View.OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
@ -217,22 +224,72 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
final View finalView = view;
|
||||||
|
chart.setOnChartGestureListener(new OnChartGestureListener() {
|
||||||
|
@Override
|
||||||
|
public void onChartGestureStart(MotionEvent me, ChartGesture lastPerformedGesture) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartGestureEnd(MotionEvent me, ChartGesture lastPerformedGesture) {
|
||||||
|
gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch());
|
||||||
|
for (int i = 0; i < getCount(); i++) {
|
||||||
|
View v = getViewAtPosition(i);
|
||||||
|
if (v != finalView) {
|
||||||
|
updateChart(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartLongPressed(MotionEvent me) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartDoubleTapped(MotionEvent me) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartSingleTapped(MotionEvent me) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChartTranslate(MotionEvent me, float dX, float dY) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
IconsCache ic = app.getIconsCache();
|
IconsCache ic = app.getIconsCache();
|
||||||
switch (tabType) {
|
switch (tabType) {
|
||||||
case GPX_TAB_ITEM_GENERAL:
|
case GPX_TAB_ITEM_GENERAL:
|
||||||
if (analysis != null) {
|
if (analysis != null) {
|
||||||
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
List<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
if (analysis.elevationData != null || analysis.isSpeedSpecified()) {
|
if (analysis.elevationData != null || analysis.isSpeedSpecified()) {
|
||||||
GPXUtilities.setupGPXChart(app, chart, 4);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
|
OrderedLineDataSet speedDataSet = null;
|
||||||
|
OrderedLineDataSet elevationDataSet = null;
|
||||||
if (analysis.isSpeedSpecified()) {
|
if (analysis.isSpeedSpecified()) {
|
||||||
LineDataSet dataSet = GPXUtilities.createGPXSpeedDataSet(app, chart, analysis, true);
|
speedDataSet = GpxUiHelper.createGPXSpeedDataSet(app, chart, analysis, true, true);
|
||||||
dataSets.add(dataSet);
|
|
||||||
}
|
}
|
||||||
if (analysis.elevationData != null) {
|
if (analysis.elevationData != null) {
|
||||||
LineDataSet dataSet = GPXUtilities.createGPXElevationDataSet(app, chart, analysis, false);
|
elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, analysis, false, true);
|
||||||
dataSets.add(dataSet);
|
|
||||||
}
|
}
|
||||||
|
if (speedDataSet != null) {
|
||||||
|
dataSets.add(speedDataSet);
|
||||||
|
if (elevationDataSet != null) {
|
||||||
|
dataSets.add(elevationDataSet.priority < speedDataSet.priority ? 1 : 0, elevationDataSet);
|
||||||
|
}
|
||||||
|
} else if (elevationDataSet != null) {
|
||||||
|
dataSets.add(elevationDataSet);
|
||||||
|
}
|
||||||
|
|
||||||
LineData data = new LineData(dataSets);
|
LineData data = new LineData(dataSets);
|
||||||
chart.setData(data);
|
chart.setData(data);
|
||||||
chart.setVisibility(View.VISIBLE);
|
chart.setVisibility(View.VISIBLE);
|
||||||
|
@ -285,8 +342,8 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
case GPX_TAB_ITEM_ALTITUDE:
|
case GPX_TAB_ITEM_ALTITUDE:
|
||||||
if (analysis != null) {
|
if (analysis != null) {
|
||||||
if (analysis.elevationData != null) {
|
if (analysis.elevationData != null) {
|
||||||
GPXUtilities.setupGPXChart(app, chart, 4);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
GPXUtilities.setGPXElevationChartData(app, chart, analysis, false);
|
GpxUiHelper.setGPXElevationChartData(app, chart, analysis, false, true);
|
||||||
chart.setVisibility(View.VISIBLE);
|
chart.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
chart.setVisibility(View.GONE);
|
chart.setVisibility(View.GONE);
|
||||||
|
@ -327,9 +384,8 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
break;
|
break;
|
||||||
case GPX_TAB_ITEM_SPEED:
|
case GPX_TAB_ITEM_SPEED:
|
||||||
if (analysis != null && analysis.isSpeedSpecified()) {
|
if (analysis != null && analysis.isSpeedSpecified()) {
|
||||||
GPXUtilities.setupGPXChart(app, chart, 4);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
GPXUtilities.setGPXSpeedChartData(app, chart, analysis, false);
|
GpxUiHelper.setGPXSpeedChartData(app, chart, analysis, false, true);
|
||||||
|
|
||||||
((ImageView) view.findViewById(R.id.average_icon))
|
((ImageView) view.findViewById(R.id.average_icon))
|
||||||
.setImageDrawable(ic.getThemedIcon(R.drawable.ic_action_speed));
|
.setImageDrawable(ic.getThemedIcon(R.drawable.ic_action_speed));
|
||||||
((ImageView) view.findViewById(R.id.max_icon))
|
((ImageView) view.findViewById(R.id.max_icon))
|
||||||
|
@ -442,5 +498,16 @@ public class TrackSegmentFragment extends SelectedGPXFragment {
|
||||||
public View getViewAtPosition(int position) {
|
public View getViewAtPosition(int position) {
|
||||||
return views.get(position);
|
return views.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateChart(int position) {
|
||||||
|
View view = getViewAtPosition(position);
|
||||||
|
updateChart((LineChart) view.findViewById(R.id.chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateChart(LineChart chart) {
|
||||||
|
if (gpxItem.chartMatrix != null) {
|
||||||
|
chart.getViewPortHandler().refresh(new Matrix(gpxItem.chartMatrix), chart, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue