Ensure that rapid zoom/location changes are both honored.
This commit is contained in:
parent
89f18a074b
commit
a136ec2549
2 changed files with 74 additions and 16 deletions
|
|
@ -15,6 +15,10 @@ from ..libs import (
|
|||
from .base import Widget
|
||||
|
||||
|
||||
def approx(a, b):
|
||||
return abs(a - b) < 0.00001
|
||||
|
||||
|
||||
class TogaMapView(MKMapView):
|
||||
interface = objc_property(object, weak=True)
|
||||
impl = objc_property(object, weak=True)
|
||||
|
|
@ -26,8 +30,20 @@ class TogaMapView(MKMapView):
|
|||
|
||||
@objc_method
|
||||
def mapView_regionDidChangeAnimated_(self, mapView, animated: bool) -> None:
|
||||
# Once an animation finishes, we know the future location has been reached.
|
||||
self.impl.future_location = None
|
||||
# Once an animation finishes, compare the currently viewable region with any
|
||||
# future values
|
||||
region = self.impl.native.region
|
||||
if (
|
||||
self.impl.future_location
|
||||
and approx(region.center.latitude, self.impl.future_location.latitude)
|
||||
and approx(region.center.longitude, self.impl.future_location.longitude)
|
||||
):
|
||||
self.impl.future_location = None
|
||||
|
||||
if self.impl.future_delta and approx(
|
||||
region.span.longitudeDelta, self.impl.future_delta
|
||||
):
|
||||
self.impl.future_delta = None
|
||||
|
||||
|
||||
class MapView(Widget):
|
||||
|
|
@ -43,8 +59,11 @@ class MapView(Widget):
|
|||
# finished animating to the new location yet. Whenever we change location, store
|
||||
# the desired future location, so that any zoom changes that occur during
|
||||
# animation can use the desired *future* location as the center of the zoom
|
||||
# window, rather than wherever the window is mid-pan.
|
||||
# window, rather than wherever the window is mid-pan. Similarly, store the
|
||||
# future span delta, so that the desired span can be applied rather than the
|
||||
# current span.
|
||||
self.future_location = None
|
||||
self.future_delta = None
|
||||
|
||||
# Setting the zoom level also requires knowing the size of the rendered area.
|
||||
# We won't know this until layout happens at least once, so retain a backlog
|
||||
|
|
@ -88,10 +107,17 @@ class MapView(Widget):
|
|||
def set_location(self, position):
|
||||
if self.backlog is None:
|
||||
self.future_location = CLLocationCoordinate2D(*position)
|
||||
self.native.setCenterCoordinate(
|
||||
self.future_location,
|
||||
animated=True,
|
||||
delta = (
|
||||
self.future_delta
|
||||
if self.future_delta
|
||||
else self.native.region.span.longitudeDelta
|
||||
)
|
||||
|
||||
region = MKCoordinateRegion(
|
||||
self.future_location,
|
||||
MKCoordinateSpan(0, delta),
|
||||
)
|
||||
self.native.setRegion(region, animated=True)
|
||||
else:
|
||||
self.backlog["location"] = position
|
||||
|
||||
|
|
@ -112,7 +138,10 @@ class MapView(Widget):
|
|||
# The horizontal axis can't show more than 360 degrees of longitude, so clip
|
||||
# the range to that value. The OSM zoom level is based on 360 degrees of
|
||||
# longitude being split into 2**zoom sections.
|
||||
delta = min(360.0, (360 * self.interface.layout.width) / (256 * 2**zoom))
|
||||
self.future_delta = min(
|
||||
360.0,
|
||||
(360 * self.interface.layout.width) / (256 * 2**zoom),
|
||||
)
|
||||
|
||||
# If we're currently panning to a new location, use the desired *future*
|
||||
# location as the center of the zoom region. Otherwise use the current center
|
||||
|
|
@ -124,7 +153,7 @@ class MapView(Widget):
|
|||
)
|
||||
region = MKCoordinateRegion(
|
||||
center,
|
||||
MKCoordinateSpan(0, delta),
|
||||
MKCoordinateSpan(0, self.future_delta),
|
||||
)
|
||||
self.native.setRegion(region, animated=True)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ from ..libs import (
|
|||
from .base import Widget
|
||||
|
||||
|
||||
def approx(a, b):
|
||||
return abs(a - b) < 0.00001
|
||||
|
||||
|
||||
class TogaMapView(MKMapView):
|
||||
interface = objc_property(object, weak=True)
|
||||
impl = objc_property(object, weak=True)
|
||||
|
|
@ -26,8 +30,20 @@ class TogaMapView(MKMapView):
|
|||
|
||||
@objc_method
|
||||
def mapView_regionDidChangeAnimated_(self, mapView, animated: bool) -> None:
|
||||
# Once an animation finishes, we know the future location has been reached.
|
||||
self.impl.future_location = None
|
||||
# Once an animation finishes, compare the currently viewable region with any
|
||||
# future values
|
||||
region = self.impl.native.region
|
||||
if (
|
||||
self.impl.future_location
|
||||
and approx(region.center.latitude, self.impl.future_location.latitude)
|
||||
and approx(region.center.longitude, self.impl.future_location.longitude)
|
||||
):
|
||||
self.impl.future_location = None
|
||||
|
||||
if self.impl.future_delta and approx(
|
||||
region.span.longitudeDelta, self.impl.future_delta
|
||||
):
|
||||
self.impl.future_delta = None
|
||||
|
||||
|
||||
class MapView(Widget):
|
||||
|
|
@ -43,8 +59,11 @@ class MapView(Widget):
|
|||
# finished animating to the new location yet. Whenever we change location, store
|
||||
# the desired future location, so that any zoom changes that occur during
|
||||
# animation can use the desired *future* location as the center of the zoom
|
||||
# window, rather than wherever the window is mid-pan.
|
||||
# window, rather than wherever the window is mid-pan. Similarly, store the
|
||||
# future span delta, so that the desired span can be applied rather than the
|
||||
# current span.
|
||||
self.future_location = None
|
||||
self.future_delta = None
|
||||
|
||||
# Setting the zoom level also requires knowing the size of the rendered area.
|
||||
# We won't know this until layout happens at least once, so retain a backlog
|
||||
|
|
@ -88,10 +107,17 @@ class MapView(Widget):
|
|||
def set_location(self, position):
|
||||
if self.backlog is None:
|
||||
self.future_location = CLLocationCoordinate2D(*position)
|
||||
self.native.setCenterCoordinate(
|
||||
self.future_location,
|
||||
animated=True,
|
||||
delta = (
|
||||
self.future_delta
|
||||
if self.future_delta
|
||||
else self.native.region.span.longitudeDelta
|
||||
)
|
||||
|
||||
region = MKCoordinateRegion(
|
||||
self.future_location,
|
||||
MKCoordinateSpan(0, delta),
|
||||
)
|
||||
self.native.setRegion(region, animated=True)
|
||||
else:
|
||||
self.backlog["location"] = position
|
||||
|
||||
|
|
@ -112,7 +138,10 @@ class MapView(Widget):
|
|||
# The horizontal axis can't show more than 360 degrees of longitude, so clip
|
||||
# the range to that value. The OSM zoom level is based on 360 degrees of
|
||||
# longitude being split into 2**zoom sections.
|
||||
delta = min(360.0, (360 * self.interface.layout.width) / (256 * 2**zoom))
|
||||
self.future_delta = min(
|
||||
360.0,
|
||||
(360 * self.interface.layout.width) / (256 * 2**zoom),
|
||||
)
|
||||
|
||||
# If we're currently panning to a new location, use the desired *future*
|
||||
# location as the center of the zoom region. Otherwise use the current center
|
||||
|
|
@ -124,7 +153,7 @@ class MapView(Widget):
|
|||
)
|
||||
region = MKCoordinateRegion(
|
||||
center,
|
||||
MKCoordinateSpan(0, delta),
|
||||
MKCoordinateSpan(0, self.future_delta),
|
||||
)
|
||||
self.native.setRegion(region, animated=True)
|
||||
else:
|
||||
|
|
|
|||
Loading…
Reference in a new issue