diff options
4 files changed, 68 insertions, 18 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index d2694b5b8a..6156b3af73 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -87,6 +87,11 @@ public class MapboxConstants { public static final double MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE = 2.5; /** + * Maximum possible zoom change during the quick zoom gesture executed across the whole screen + */ + public static final double QUICK_ZOOM_MAX_ZOOM_CHANGE = 4.0; + + /** * Scale velocity animation duration multiplier. */ public static final double SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER = 150; @@ -156,12 +161,18 @@ public class MapboxConstants { /** * The currently used minimum scale factor to clamp to when a quick zoom gesture occurs + * + * @deprecated unused */ + @Deprecated public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.00f; /** * The currently used maximum scale factor to clamp to when a quick zoom gesture occurs + * + * @deprecated unused */ + @Deprecated public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.15f; /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 0b28c669af..90e3934f7c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.Resources; import android.graphics.PointF; import android.os.Handler; import android.support.annotation.NonNull; @@ -31,11 +32,13 @@ import java.util.concurrent.CopyOnWriteArrayList; import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAXIMUM_ANGULAR_VELOCITY; import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.QUICK_ZOOM_MAX_ZOOM_CHANGE; import static com.mapbox.mapboxsdk.constants.MapboxConstants.ROTATE_VELOCITY_RATIO_THRESHOLD; import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER; import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_RATIO_THRESHOLD; import static com.mapbox.mapboxsdk.constants.MapboxConstants.ZOOM_RATE; import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE; +import static com.mapbox.mapboxsdk.utils.MathUtils.normalize; /** * Manages gestures events on a MapView. @@ -76,6 +79,9 @@ final class MapGestureDetector { @Nullable private PointF constantFocalPoint; + @NonNull + private PointF doubleTapFocalPoint = new PointF(); + private AndroidGesturesManager gesturesManager; private Animator scaleAnimator; @@ -321,8 +327,6 @@ final class MapGestureDetector { } private final class StandardGestureListener extends StandardGestureDetector.SimpleStandardOnGestureListener { - - private PointF doubleTapFocalPoint; private final float doubleTapMovementThreshold; StandardGestureListener(float doubleTapMovementThreshold) { @@ -495,6 +499,8 @@ final class MapGestureDetector { private final double scaleVelocityRatioThreshold; private boolean quickZoom; private float spanSinceLast; + private double screenHeight; + private double startZoom; ScaleGestureListener(double densityMultiplier, float minimumGestureSpeed, float minimumAngledGestureSpeed, float minimumVelocity) { @@ -548,6 +554,9 @@ final class MapGestureDetector { } } + screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + startZoom = transform.getRawZoom(); + cancelTransitionsIfRequired(); notifyOnScaleBeginListeners(detector); @@ -562,10 +571,24 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - float scaleFactor = detector.getScaleFactor(); - double zoomBy = getNewZoom(scaleFactor, quickZoom); PointF focalPoint = getScaleFocalPoint(detector); - transform.zoomBy(zoomBy, focalPoint); + if (quickZoom) { + double pixelDeltaChange = Math.abs(detector.getCurrentEvent().getY() - doubleTapFocalPoint.y); + boolean zoomedOut = detector.getCurrentEvent().getY() < doubleTapFocalPoint.y; + + // normalize the pixel delta change, ranging from 0 to screen height, to a constant zoom change range + double normalizedDeltaChange = normalize(pixelDeltaChange, 0, screenHeight, 0, QUICK_ZOOM_MAX_ZOOM_CHANGE); + + // calculate target zoom and adjust for a multiplier + double targetZoom = (zoomedOut ? startZoom - normalizedDeltaChange : startZoom + normalizedDeltaChange); + targetZoom *= uiSettings.getZoomRate(); + + transform.setZoom(targetZoom, focalPoint); + } else { + double zoomBy = + (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) * ZOOM_RATE * uiSettings.getZoomRate(); + transform.zoomBy(zoomBy, focalPoint); + } notifyOnScaleListeners(detector); @@ -628,19 +651,6 @@ final class MapGestureDetector { } return zoomAddition; } - - private double getNewZoom(float scaleFactor, boolean quickZoom) { - double zoomBy = (Math.log(scaleFactor) / Math.log(Math.PI / 2)) * ZOOM_RATE * uiSettings.getZoomRate(); - if (quickZoom) { - // clamp scale factors we feed to core #7514 - boolean negative = zoomBy < 0; - zoomBy = MathUtils.clamp(Math.abs(zoomBy), - MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP, - MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP); - return negative ? -zoomBy : zoomBy; - } - return zoomBy; - } } private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java index 0c90e4b244..7ec3262c57 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java @@ -46,4 +46,19 @@ public class MathUtils { return secondMod + min; } + + /** + * Scale a value from an arbitrary range to a normalized range. + * + * @param x The value to be normalized. + * @param dataLow lowest expected value from a data set + * @param dataHigh highest expected value from a data set + * @param normalizedLow normalized lowest value + * @param normalizedHigh normalized highest value + * @return The result of the normalization. + */ + public static double normalize(double x, double dataLow, double dataHigh, + double normalizedLow, double normalizedHigh) { + return ((x - dataLow) / (dataHigh - dataLow)) * (normalizedHigh - normalizedLow) + normalizedLow; + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt index 3980199cad..525c576df4 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt @@ -176,4 +176,18 @@ class MapGestureDetectorTest : BaseTest() { Assert.assertNotEquals(initialCameraPosition!!.target.longitude, mapboxMap.cameraPosition.target.longitude, 1.0) } } + + @Test + fun quickZoom_roundTripping() { + validateTestSetup() + rule.runOnUiThread { + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.0, 16.0), 3.0)) + } + onView(withId(R.id.mapView)).perform(quickScale(300f, withVelocity = false, duration = 750L)) + onView(withId(R.id.mapView)).perform(quickScale(-300f, withVelocity = false, duration = 750L)) + + rule.runOnUiThread { + Assert.assertEquals(3.0, mapboxMap.cameraPosition.zoom, 0.0001) + } + } }
\ No newline at end of file |