MapProxy conversion from screen to coords is wrong on macOS

Try the following code on macOS, and you'll see the marker is added in the wrong place, as the conversion from screen coordinates to map coordinates doesn't work correctly.

The screenCoord value is correct, but reader.convert(screenCoord, from: .local) offsets the resulting coordinate by the height of the content above the map, despite the .local parameter.

struct TestMapView: View {
    @State var placeAPin = false
    @State var pinLocation :CLLocationCoordinate2D? = nil
    
    @State private var cameraProsition: MapCameraPosition = .camera(
        MapCamera(
            centerCoordinate: .denver,
            distance: 3729,
            heading: 92,
            pitch: 70
        )
    )
    
    var body: some View {
        VStack {
            Text("This is a bug demo.")
            Text("If there are other views above the map, the MapProxy doesn't convert the coordinates correctly.")
            
            MapReader { reader in
                Map(
                    position: $cameraProsition,
                    interactionModes: .all
                )
                {
                    if let pl = pinLocation {
                        Marker("(\(pl.latitude), \(pl.longitude))", coordinate: pl)
                    }
                }
                .onTapGesture(perform: { screenCoord in
                    pinLocation = reader.convert(screenCoord, from: .local)
                    placeAPin = false
                    
                    if let pinLocation {
                        print("tap: screen \(screenCoord), location \(pinLocation)")
                    }
                })
                
                .mapControls{
                    MapCompass()
                    MapScaleView()
                    MapPitchToggle()
                }
                
                .mapStyle(.standard(elevation: .automatic))
            }
            
        }
    }
}

extension CLLocationCoordinate2D {
    static var denver = CLLocationCoordinate2D(latitude: 39.742043, longitude: -104.991531)
}

(FB13135770)

  • What is screenCoord? Where does it come from?

Add a Comment

Replies

It's a point. The closure argument for .onTapGesture(perform:).

(Oops, this was supposed to be a comment; I don't see how to delete it.)

Can you try using a custom coordinate space like this and see if it works. I can't test it because I'm on Ventura.

Map {
    ...    
}
.onTapGesture(perform: { screenCoord in
    pinLocation = reader.convert(screenCoord, from: .named("map"))
    ...
})
.coordinateSpace(.named("map"))
  • No, that's worse; clicking on the top of the map adds a pin towards the bottom, and vice versa (but not 100% reversed; clicking in the bottom third adds a pin at the top).

Add a Comment

Just ran into this. But... I don't have any views above the map. In my case the Y coordinate seems to be off by 25 points. If I add 25.0 to the Y coordinate of the reported position before conversion I get what I believe to be the correct value. Or certainly something much, much closer to the correct value.

macOS 14.3.1.