Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fitBounds does not work as expected when a Map is rotated #1342

Closed
5 tasks done
SheenaJacob opened this issue Aug 16, 2022 · 7 comments · Fixed by #1550
Closed
5 tasks done

fitBounds does not work as expected when a Map is rotated #1342

SheenaJacob opened this issue Aug 16, 2022 · 7 comments · Fixed by #1550
Labels
bug This issue reports broken functionality or another error

Comments

@SheenaJacob
Copy link

SheenaJacob commented Aug 16, 2022

What is the bug?

The aim of this example is to be able to fit the map to contain the four specified bounds. When the Fit Bounds button is clicked with no Map Rotation then it works as expected, but when a Map is first rotated and then the FitBounds button is pressed this is no longer the case.

What is the expected behaviour?

When a map is not rotated fitBounds works as expected

expected

When a map is rotated then the map no longer shows all the bounds.
After_rotating

How can we reproduce this issue?

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';

void main() {
  runApp(FitBounds());
}

class FitBounds extends StatelessWidget {
  FitBounds({Key? key}) : super(key: key);

  static LatLng topRightCorner = LatLng(4.214943, 33.925781);
  static LatLng topLeftCorner = LatLng(3.480523, 30.844116);
  static LatLng bottomLeftCorner = LatLng(-1.362176, 29.575195);
  static LatLng bottomRightCorner = LatLng(-0.999705, 33.925781);
  final MapController mapController = MapController();

  @override
  Widget build(BuildContext context) {
    final markers = <Marker>[
      Marker(
        width: 100,
        height: 100,
        point: topLeftCorner,
        builder: (ctx) => const Icon(Icons.circle, color: Colors.green),
      ),
      Marker(
        width: 100,
        height: 100,
        point: topRightCorner,
        builder: (ctx) => const Icon(Icons.circle, color: Colors.blue),
      ),
      Marker(
        width: 100,
        height: 100,
        point: bottomLeftCorner,
        builder: (ctx) => const Icon(Icons.circle, color: Colors.red),
      ),
      Marker(
        width: 100,
        height: 100,
        point: bottomRightCorner,
        builder: (ctx) => const Icon(Icons.circle, color: Colors.purple),
      ),
    ];

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Animated MapController')),
        body: Padding(
          padding: const EdgeInsets.all(8),
          child: Column(
            children: [
              Padding(
                padding: const EdgeInsets.only(top: 8, bottom: 8),
                child: Row(
                  children: <Widget>[
                    MaterialButton(
                      onPressed: () {
                        final bounds = LatLngBounds.fromPoints([
                          topLeftCorner,
                          topRightCorner,
                          bottomLeftCorner,
                          bottomRightCorner
                        ]);
                        mapController.fitBounds(
                          bounds,
                          options: const FitBoundsOptions(
                            padding: EdgeInsets.all(20),
                          ),
                        );
                      },
                      child: const Text('Fit Bounds'),
                    ),
                  ],
                ),
              ),
              Flexible(
                child: FlutterMap(
                  mapController: mapController,
                  options: MapOptions(
                      center: LatLng(2.108899, 33.112793),
                      zoom: 5,
                      maxZoom: 10,
                      minZoom: 3),
                  layers: [
                    TileLayerOptions(
                      urlTemplate:
                      'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                      subdomains: ['a', 'b', 'c'],
                      userAgentPackageName: 'dev.fleaflet.flutter_map.example',
                    ),
                    MarkerLayerOptions(markers: markers),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Do you have a potential solution?

While I don't have a solution I assume that there is a problem when calculating the new zoom value, as the problem occurs while using two of the methods in the MapController class.

  1. centerZoomFitBounds(LatLngBounds bounds, {FitBoundsOptions? options})
  2. fitBounds(LatLngBounds bounds, {FitBoundsOptions? options}).

In the MapState class (https://github.com/fleaflet/flutter_map/blob/master/lib/src/map/map.dart) both these methods use the getBoundsCenterZoom(LatLngBounds bounds, FitBoundsOptions options) function where the new center and zoom value are calculated. While the center is calculated correctly, the zoom (calculated by getBoundsZoom(LatLngBounds bounds, CustomPoint padding,{bool inside = false}) )value does not take into account that a map is rotated.

Can you provide any other information?

No response

Platforms Affected

Android

Severity

Minimum: Allows normal functioning

Frequency

Consistently: Always occurs at the same time and location

Requirements

  • I agree to follow this project's Code of Conduct
  • My Flutter/Dart installation is unaltered, and flutter doctor finds no relevant issues
  • I am using the latest stable version of this package
  • I have checked the FAQs section on the documentation website
  • I have checked for similar issues which may be duplicates
@SheenaJacob SheenaJacob added bug This issue reports broken functionality or another error needs triage This new bug report needs reproducing and prioritizing labels Aug 16, 2022
@ibrierley
Copy link
Collaborator

I haven't tested this yet, but think this has been raised before and don't think there's any code to deal with it yet, so I think makes sense it wouldn't work.

I think this will get done at some point, but pull requests welcome, to make it sooner!

@ibrierley ibrierley removed the needs triage This new bug report needs reproducing and prioritizing label Aug 17, 2022
@mohammedX6
Copy link

Try to set rotation to zero before fitbounds

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@JosefWN
Copy link
Contributor

JosefWN commented Nov 1, 2022

I think have fixed this in my fork, still testing. My code looks slightly different, but it's a quick fix anyway.

In getBoundsZoom:

  1. Use nonrotatedSize, the size of the viewport itself (which is our reference for fitting) is not affected by rotation.
  2. Instead, rotate the bounding box we are fitting the viewport to, just as we do with the viewport in _updateSizeByOriginalSizeAndRotation.

EDIT: The rotated bounding box approach works well when the layers fill the whole non-rotated bounds, but with vector layers for example, it feels a bit less intuitive to the untrained eye since the bounding box itself is not visible...

The bounding box may have some transparent regions which this approach takes care to include, making a rotated fit a bit "loose"/too zoomed out. Maybe there is a smarter way, this was just the most straight-forward solution that came up from the top of my head...

@github-actions
Copy link

github-actions bot commented Dec 2, 2022

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions
Copy link

github-actions bot commented Jan 2, 2023

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue reports broken functionality or another error
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants