-
-
Notifications
You must be signed in to change notification settings - Fork 893
Description
This issue is actually a feature request : it is labelled as a bug because it originated from a bug and I originally planned on only creating this issue, however after trying to understand what causes this behaviour, I created issue #2072 which is the underlying bug. They are two separate issues and solving #2072 will not "solve" this feature request
What is the bug?
If cameraConstraint is set from -90;-180 to 90;180, panning to the horizontal edges of the map will be inconsistent and there is no way to have unconstrained horizontal scroll with latitude boundaries of -90 to 90. If you don't pan with enough speed it will stop at the border and if you pan with enough speed it will jump to the other side with some lag and it will be quite jerky.
Seems to be the same issue as #2005 don't know why he marked it as completed though ? Is there already a way to fix it I missed ?
How can we reproduce it?
Create a FlutterMap with the following property set in MapOptions : cameraConstraint: CameraConstraint.contain(LatLngBounds(const LatLng(-90, -180), const LatLng(90, 180))),
Do you have a potential solution?
I see two ways to fix the problem :
- Ignore the longitude constraints when they're 180 or -180, but it would make it impossible for someone to actually constrain a map to these longitudes if they want to
- Create a camera constraint that only constrains latitude
To work around it I opted for the second solution and made the following camera constraint class inspired from the other classes, it only constrains the camera on the latitude.
@immutable
class ContainCameraVertically extends CameraConstraint {
const ContainCameraVertically(this.a, this.b);
final double a;
final double b;
@override
MapCamera? constrain(MapCamera camera) {
final double testZoom = camera.zoom;
final LatLng testCenter = camera.center;
final Offset aPixel = camera.projectAtZoom(LatLng(a, 0), testZoom);
final Offset bPixel = camera.projectAtZoom(LatLng(b, 0), testZoom);
final Size halfSize = camera.size / 2;
// Find the limits for the map center which would keep the camera within the
// [a] and [b] bounds.
final double topOkCenter = math.min(aPixel.dy, bPixel.dy) + halfSize.height;
final double botOkCenter = math.max(aPixel.dy, bPixel.dy) - halfSize.height;
// Stop if we are zoomed out so far that the camera cannot be translated to
// stay within the [a] and [b] bounds.
if (topOkCenter > botOkCenter) {
return null;
}
final Offset centerPix = camera.projectAtZoom(testCenter, testZoom);
final newCenterPix = Offset(centerPix.dx, centerPix.dy.clamp(topOkCenter, botOkCenter));
if (newCenterPix == centerPix) {
return camera;
}
return camera.withPosition(center: camera.unprojectAtZoom(newCenterPix, testZoom));
}
@override
bool operator ==(Object other) {
return other is ContainCameraVertically && other.a == a && other.b == b;
}
@override
int get hashCode => a.hashCode ^ b.hashCode;
}