mapbox-maps-ios icon indicating copy to clipboard operation
mapbox-maps-ios copied to clipboard

iOS: camera.zoom calculates smaller zoom for camera(for:) initially

Open mfazekas opened this issue 1 year ago • 9 comments

Environment

  • Xcode version: 15.3
  • iOS version: iOS 17.4 Simulator
  • Devices affected: iPhone 15 Pro - iOS 17.4 Simulator
  • Maps SDK Version: v11.4.0, #32bb4e4766b7434dcf0f50fd6728aa5765faa5b9

Observed behavior and steps to reproduce

CameraOptions calculated for camera(for: coordinates) just after map is added to a view is smaller than when calculated from onStyleDataLoaded

When calculated just after map added to a view the zoom is less than the ideal (: image

When calculated from onStyleDataLoaded the zoom is correct: image

To reproduce use the code snippet at the end of the report to replace BasicMapExample in the Apps/Examples Xcode project. Observe the zoom values printed and uncomment the setCamera in onStyleDataLoaded handler to verify that that the zoom value is correct there.

=> zoom: Optional(3.535590091035326)
=> zoom(styleDataLoaded): Optional(3.9738550186157227)

Expected behaviour

Either camera(for:) should return an error, so signal that it's not in the state to calculate CameraOption correctly or return the correct camera settings (zoom!) for the actual bounds. I don't think any map loading is needed for that calculation.

Notes / preliminary analysis

Additional links and references

import UIKit
import MapboxMaps

final class BasicMapExample: UIViewController, ExampleProtocol {
    private var mapView: MapView!
  
    var handlers: [AnyCancelable] = [];

    override func viewDidLoad() {
        super.viewDidLoad()

        
      mapView = MapView(frame: view.bounds)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.ornaments.options.scaleBar.visibility = .visible
      
    
      let coordinates = [
          CLLocationCoordinate2D(latitude: -74.41429582091831, longitude: -105.02738295071447),
          CLLocationCoordinate2D(latitude: -82.41571395310365, longitude: -108.67784207799926),
          CLLocationCoordinate2D(latitude: -71.45151781686236, longitude: -117.5641615804278),
          CLLocationCoordinate2D(latitude: -74.41429582091831, longitude: -105.02738295071447)
      ]
      

      view.addSubview(mapView)
      
      let camera = try! mapView.mapboxMap.camera(for: coordinates, camera:
                                                CameraOptions(), coordinatesPadding: nil,
                                              maxZoom: nil,
                                              offset: nil
      )
      
      print("=> zoom: \(String(describing: camera.zoom))")
      mapView.mapboxMap.setCamera(to: camera)
      
      handlers.append(mapView.mapboxMap.onStyleDataLoaded.observe {
        event in
        
        let camera1 = try! self.mapView.mapboxMap.camera(for: coordinates, camera:
                                                  CameraOptions(), coordinatesPadding: nil,
                                                maxZoom: nil,
                                                offset: nil
        )
        print("=> zoom(styleDataLoaded): \(String(describing: camera1.zoom))")
        // uncomment this next line to see the correct zoom
        // self.mapView.mapboxMap.setCamera(to: camera1)
      })
      
      handlers.append(mapView.mapboxMap.onMapLoaded.observe {
        event in
        
        let sourceData = GeoJSONSourceData.geometry(.lineString(LineString(coordinates)))
        var source = GeoJSONSource(id: "poly")
        source.data = sourceData
        try! self.mapView.mapboxMap.addSource(source)
        
        var layer = LineLayer(id: "poly-l", source: "poly")
        layer.lineWidth = .constant(2.0)
        layer.lineColor = .constant(StyleColor(UIColor.red))
        try! self.mapView.mapboxMap.addLayer(layer)
      })
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // The below line is used for internal testing purposes only.
        finish()
    }
}

https://github.com/rnmapbox/sponsors/issues/3

mfazekas avatar Apr 25 '24 11:04 mfazekas

Hey, @mfazekas I'm currently working on the issues with camera(for:) and will take a look at this too. Thank you, for the reproduction steps!

aleksproger avatar Apr 25 '24 11:04 aleksproger

Hi @aleksproger - any updates on findings for this issue?

benjamin-sweney avatar May 07 '24 18:05 benjamin-sweney

@mfazekas hey! do you observe similar problem in Android in v11.4.0-rc.1 when using async overload of cameraForCoordinates which makes sure that viewport is set properly.

kiryldz avatar May 13 '24 13:05 kiryldz

@kiryldz sorry, I cannot comment on that, this was reported as an iOS only issue, so this might not have surfaced on android beacuse timing or other

mfazekas avatar May 16 '24 05:05 mfazekas

+1 on this camera(for coordinates:camera:coordinatesPadding:maxZoom:offset:) behaves inconsistently in my app. The zoom is smaller than expected in some scenarios.

SDK Version (iOS): v11.5.1

I have to stay on v10.x until it's fixed :( Hope a fix can be found soon.

nmondollot avatar Jul 11 '24 14:07 nmondollot

v11.6.0, ios Same problem

svyatoslavpavlov avatar Sep 05 '24 13:09 svyatoslavpavlov

Hello @aleksproger any update on this? thx

nmondollot avatar Sep 05 '24 13:09 nmondollot

@aleksproger any updates? it is really unpleasant bug

Crysp avatar Sep 23 '24 07:09 Crysp

I found solution:

func updateCameraBounds(coordinates: [CLLocationCoordinate2D], padding: UIEdgeInsets, animated: Bool = true) {
        do {
            let referenceCamera = CameraOptions(padding: padding, bearing: 0, pitch: 0)
            let camera = try mapboxMap.camera(for: coordinates, camera: referenceCamera, coordinatesPadding: nil, maxZoom: nil, offset: nil)
            setCameraOptions(cameraOptions: camera, animated: animated)
        } catch {
            debug("\(error)")
        }
    }

SigmaAppdevelopment avatar Dec 03 '24 06:12 SigmaAppdevelopment