From 4fc57fd04c9f57508e893b125577eb4df66c784b Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Wed, 8 Mar 2017 21:09:10 +0300 Subject: [PATCH] Fit chart to the map view (track details) --- OsmAnd/src/net/osmand/plus/GPXUtilities.java | 4 +- .../other/TrackDetailsMenu.java | 213 +++++++++++++----- .../other/TrackDetailsMenuFragment.java | 18 ++ .../osmand/plus/views/MapControlsLayer.java | 2 +- 4 files changed, 183 insertions(+), 54 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/GPXUtilities.java b/OsmAnd/src/net/osmand/plus/GPXUtilities.java index d48ae9e4fb..106ef7334a 100644 --- a/OsmAnd/src/net/osmand/plus/GPXUtilities.java +++ b/OsmAnd/src/net/osmand/plus/GPXUtilities.java @@ -337,6 +337,7 @@ public class GPXUtilities { channelBottom = channelBase; channelThres = channelThresMin; + float segmentDistance = 0f; metricEnd += s.metricEnd; secondaryMetricEnd += s.secondaryMetricEnd; points += numberOfPoints; @@ -448,7 +449,8 @@ public class GPXUtilities { // a little more exact, also seems slightly faster: net.osmand.Location.distanceBetween(prev.lat, prev.lon, point.lat, point.lon, calculations); totalDistance += calculations[0]; - point.distance = totalDistance; + segmentDistance += calculations[0]; + point.distance = segmentDistance; timeDiff = (int)((point.time - prev.time) / 1000); // Motion detection: diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java index a92d5d2843..3b6d799445 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenu.java @@ -10,15 +10,20 @@ import android.widget.ImageView; import android.widget.TextView; import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.highlight.Highlight; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; import com.github.mikephil.charting.listener.ChartTouchListener; import com.github.mikephil.charting.listener.OnChartGestureListener; +import com.github.mikephil.charting.listener.OnChartValueSelectedListener; import net.osmand.data.LatLon; +import net.osmand.data.QuadRect; +import net.osmand.data.RotatedTileBox; import net.osmand.plus.GPXUtilities; import net.osmand.plus.GPXUtilities.GPXTrackAnalysis; +import net.osmand.plus.GPXUtilities.TrkSegment; import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.IconsCache; @@ -43,6 +48,7 @@ public class TrackDetailsMenu { private MapActivity mapActivity; private GpxDisplayItem gpxItem; private TrackDetailsBarController toolbarController; + private TrkSegment segment; private static boolean VISIBLE; @@ -99,6 +105,7 @@ public class TrackDetailsMenu { if (fragmentRef != null) { fragmentRef.get().dismiss(); } else { + segment = null; VISIBLE = false; } } @@ -129,14 +136,165 @@ public class TrackDetailsMenu { mapActivity.getMapLayers().getMapInfoLayer().setSelectedPointLatLon(null); mapActivity.getMapView().setMapPositionX(0); mapActivity.getMapView().refreshMap(); + segment = null; } public void updateInfo(final View main) { updateView(main); } + private TrkSegment getTrackSegment(LineChart chart) { + if (segment == null) { + List ds = chart.getLineData().getDataSets(); + if (ds != null && ds.size() > 0) { + for (GPXUtilities.Track t : gpxItem.group.getGpx().tracks) { + for (TrkSegment s : t.segments) { + if (s.points.size() > 0 && s.points.get(0).equals(gpxItem.analysis.locationStart)) { + segment = s; + break; + } + } + if (segment != null) { + break; + } + } + } + } + return segment; + } + + private WptPt getPoint(LineChart chart, float pos) { + WptPt wpt = null; + List ds = chart.getLineData().getDataSets(); + if (ds != null && ds.size() > 0) { + TrkSegment segment = getTrackSegment(chart); + OrderedLineDataSet dataSet = (OrderedLineDataSet) ds.get(0); + if (gpxItem.chartAxisType == GPXDataSetAxisType.TIME) { + float time = pos * 1000; + for (WptPt p : segment.points) { + if (p.time - gpxItem.analysis.startTime >= time) { + wpt = p; + break; + } + } + } else { + float distance = pos * dataSet.getDivX(); + for (WptPt p : segment.points) { + if (p.distance >= distance) { + wpt = p; + break; + } + } + } + } + return wpt; + } + + private QuadRect getRect(LineChart chart, float startPos, float endPos) { + double left = 0, right = 0; + double top = 0, bottom = 0; + List ds = chart.getLineData().getDataSets(); + if (ds != null && ds.size() > 0) { + TrkSegment segment = getTrackSegment(chart); + OrderedLineDataSet dataSet = (OrderedLineDataSet) ds.get(0); + if (gpxItem.chartAxisType == GPXDataSetAxisType.TIME) { + float startTime = startPos * 1000; + float endTime = endPos * 1000; + for (WptPt p : segment.points) { + if (p.time - gpxItem.analysis.startTime >= startTime && + p.time - gpxItem.analysis.startTime <= endTime) { + if (left == 0 && right == 0) { + left = p.getLongitude(); + right = p.getLongitude(); + top = p.getLatitude(); + bottom = p.getLatitude(); + } else { + left = Math.min(left, p.getLongitude()); + right = Math.max(right, p.getLongitude()); + top = Math.max(top, p.getLatitude()); + bottom = Math.min(bottom, p.getLatitude()); + } + } + } + } else { + float startDistance = startPos * dataSet.getDivX(); + float endDistance = endPos * dataSet.getDivX(); + for (WptPt p : segment.points) { + if (p.distance >= startDistance && p.distance <= endDistance) { + if (left == 0 && right == 0) { + left = p.getLongitude(); + right = p.getLongitude(); + top = p.getLatitude(); + bottom = p.getLatitude(); + } else { + left = Math.min(left, p.getLongitude()); + right = Math.max(right, p.getLongitude()); + top = Math.max(top, p.getLatitude()); + bottom = Math.min(bottom, p.getLatitude()); + } + } + } + } + } + return new QuadRect(left, top, right, bottom); + } + + private void fitTrackOnMap(LineChart chart) { + QuadRect rect = getRect(chart, chart.getLowestVisibleX(), chart.getHighestVisibleX()); + if (rect != null) { + RotatedTileBox tb = mapActivity.getMapView().getCurrentRotatedTileBox().copy(); + int tileBoxWidthPx = 0; + int tileBoxHeightPx = 0; + + WeakReference fragmentRef = findMenuFragment(); + if (fragmentRef != null) { + TrackDetailsMenuFragment f = fragmentRef.get(); + boolean portrait = AndroidUiHelper.isOrientationPortrait(mapActivity); + if (!portrait) { + tileBoxWidthPx = tb.getPixWidth() - f.getWidth(); + } else { + tileBoxHeightPx = tb.getPixHeight() - f.getHeight(); + } + } + mapActivity.getMapView().fitRectToMap(rect.left, rect.right, rect.top, rect.bottom, + tileBoxWidthPx, tileBoxHeightPx, 0); + } + } + + + private void refreshChart(LineChart chart) { + gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch()); + Highlight[] highlights = chart.getHighlighted(); + if (highlights != null && highlights.length > 0) { + gpxItem.chartHighlightPos = highlights[0].getX(); + WptPt wpt = getPoint(chart, gpxItem.chartHighlightPos); + if (wpt != null) { + if (gpxItem.route) { + mapActivity.getMapLayers().getMapInfoLayer().setSelectedPointLatLon(new LatLon(wpt.lat, wpt.lon)); + } else { + mapActivity.getMapLayers().getGpxLayer().setSelectedPointLatLon(new LatLon(wpt.lat, wpt.lon)); + } + //mapActivity.setMapLocation(wpt.lat, wpt.lon); + } + } else { + gpxItem.chartHighlightPos = -1; + } + fitTrackOnMap(chart); + } + private void updateView(final View parentView) { final LineChart chart = (LineChart) parentView.findViewById(R.id.chart); + chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { + @Override + public void onValueSelected(Entry e, Highlight h) { + refreshChart(chart); + } + + @Override + public void onNothingSelected() { + + } + }); chart.setOnChartGestureListener(new OnChartGestureListener() { @Override public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { @@ -144,58 +302,7 @@ public class TrackDetailsMenu { @Override public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) { - gpxItem.chartMatrix = new Matrix(chart.getViewPortHandler().getMatrixTouch()); - Highlight[] highlights = chart.getHighlighted(); - if (highlights != null && highlights.length > 0) { - gpxItem.chartHighlightPos = highlights[0].getX(); - - List ds = chart.getLineData().getDataSets(); - if (ds != null && ds.size() > 0) { - GPXUtilities.TrkSegment segment = null; - for (GPXUtilities.Track t : gpxItem.group.getGpx().tracks) { - for (GPXUtilities.TrkSegment s : t.segments) { - if (s.points.size() > 0 && s.points.get(0).equals(gpxItem.analysis.locationStart)) { - segment = s; - break; - } - } - if (segment != null) { - break; - } - } - if (segment != null) { - WptPt wpt = null; - OrderedLineDataSet dataSet = (OrderedLineDataSet) ds.get(0); - if (gpxItem.chartAxisType == GPXDataSetAxisType.TIME) { - float time = gpxItem.chartHighlightPos * 1000; - for (WptPt p : segment.points) { - if (p.time - gpxItem.analysis.startTime >= time) { - wpt = p; - break; - } - } - } else { - float distance = gpxItem.chartHighlightPos * dataSet.getDivX(); - for (WptPt p : segment.points) { - if (p.distance >= distance) { - wpt = p; - break; - } - } - } - if (wpt != null) { - if (gpxItem.route) { - mapActivity.getMapLayers().getMapInfoLayer().setSelectedPointLatLon(new LatLon(wpt.lat, wpt.lon)); - } else { - mapActivity.getMapLayers().getGpxLayer().setSelectedPointLatLon(new LatLon(wpt.lat, wpt.lon)); - } - mapActivity.setMapLocation(wpt.lat, wpt.lon); - } - } - } - } else { - gpxItem.chartHighlightPos = -1; - } + refreshChart(chart); } @Override @@ -343,6 +450,8 @@ public class TrackDetailsMenu { xAxis.setBackgroundResource(0); xAxisArrow.setVisibility(View.GONE); } + + refreshChart(chart); } private void updateChart(LineChart chart) { diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenuFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenuFragment.java index fcf262ef62..2d84982757 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/other/TrackDetailsMenuFragment.java @@ -1,5 +1,6 @@ package net.osmand.plus.mapcontextmenu.other; +import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; @@ -7,6 +8,7 @@ import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -61,6 +63,22 @@ public class TrackDetailsMenuFragment extends Fragment { updateInfo(); + ViewTreeObserver vto = mainView.getViewTreeObserver(); + vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + + @Override + public void onGlobalLayout() { + + ViewTreeObserver obs = mainView.getViewTreeObserver(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + obs.removeOnGlobalLayoutListener(this); + } else { + obs.removeGlobalOnLayoutListener(this); + } + updateInfo(); + } + }); + return view; } diff --git a/OsmAnd/src/net/osmand/plus/views/MapControlsLayer.java b/OsmAnd/src/net/osmand/plus/views/MapControlsLayer.java index bcd4749004..8446fa62a7 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapControlsLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapControlsLayer.java @@ -636,7 +636,7 @@ public class MapControlsLayer extends OsmandMapLayer { boolean trackDialogOpened = TrackDetailsMenu.isVisible(); boolean showRouteCalculationControls = routePlanningMode || ((app.accessibilityEnabled() || (System.currentTimeMillis() - touchEvent < TIMEOUT_TO_SHOW_BUTTONS)) && routeFollowingMode); - updateMyLocation(rh, routeDialogOpened); + updateMyLocation(rh, routeDialogOpened || trackDialogOpened); boolean showButtons = (showRouteCalculationControls || !routeFollowingMode) && !isInChangeMarkerPositionMode() && !isInGpxDetailsMode(); //routePlanningBtn.setIconResId(routeFollowingMode ? R.drawable.ic_action_gabout_dark : R.drawable.map_directions);