Giter VIP home page Giter VIP logo

Comments (4)

pauljohanneskraft avatar pauljohanneskraft commented on May 29, 2024

Sure - there are currently two ways of adding overlays to this Map implementation. You can either use MKPolyline (i.e. the more UIKit way of doing UI) or specify your own Identifiable structs and then create custom MapOverlays from that (i.e. the SwiftUI way of doing things). Which one would you like more help on?

For the SwiftUI approach, I just created a code example for circles that could be transformed into using MapPolyline instead of MapCircle in the closure that is given as a parameter of the Map initializer. (See #29 (comment))

For the UIKit approach, you would have something like this:

struct MyMapView: View {

    @State private var overlays = [MKOverlay]()
    @State private var region = MKCoordinateRegion()

    var body: some View {
        Map(
            coordinateRegion: $region,
            overlays: overlays
        ) { overlay in
            // Create a MKOverlayRenderer here, for example something like this:
            let renderer = MKPolylineRenderer(overlay: overlay)
            renderer.lineWidth = 4
            renderer.strokeColor = .black
            return renderer
        }
    }
    
}

from map.

skyvalleystudio avatar skyvalleystudio commented on May 29, 2024

You mentioned adapting the #29 MapCircle to a MapPolyline but I could use a little help with that.

I have a set of locations from a @FetchRquest and want to make a polyline overlay from them. They are coredata objects from the fetch and I'm not sure where I turn them into array for the MapPolyline [CLLocationCoordinate2D]?

@FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \RoutePoint.timestamp, ascending: true)],
        animation: .default)
    private var route: FetchedResults<RoutePoint>

// I have something like this in the Map creation:
           overlayItems: route,
           overlayContent: { routePoint in
              MapPolyline(coordinates: [CLLocationCoordinate2D(latitude: routePoint.latitude, longitude: routePoint.longitude)],
                            level: .aboveRoads,
                            strokeColor: .systemIndigo,
                            lineWidth: 5)
            }

If I provide [CLLocationCoordinate2d] in overlayItems it complains it is not Identifiable (of course), so I'm not sure how these two parameters work together. I think an example would be helpful.

Your package looks quite helpful, but I haven't got it past showing the ocean at 0.0,0.0 yet either :^).

from map.

pauljohanneskraft avatar pauljohanneskraft commented on May 29, 2024

Could you make RoutePoint Identifiable? Maybe by using the timestamp or some unique identifier as id property? Since RoutePoint further needs to conform to NSObject, you might just want to use ObjectIdentifier as in the following example. It essentially uses the memory address of that object as its id, so as long as CoreData does not create new objects each time the request is fired but simply adapts the objects itself, this should work flawlessly.

extension RoutePoint: Identifiable {
    public var id: ObjectIdentifier {
        ObjectIdentifier(self)
    }
}

And regarding the issue with showing the ocean at (0,0) - could it be that you are using .constant(.init()) as the region/mapRect parameter in the initializer of the Map? If you do this, then you will always force the map to use that region, which leads it to not move at all. What you would want to do instead is have a @State wrapped property for either mapRect or region. If you don't modify it, it will simply be the user-defined value (and start at the value that you set it to initially), but you can then simply set that property and the map will move to that region/mapRect.

Edit: I think I misunderstood your point about the RoutePoint thing: You want to create one MapPolyline from all RoutePoints combined, right? Above is the solution for creating one MapPolyline per RoutePoint. Okay, in the case of one MapPolyline for all RoutePoints, it would probably make most sense to use something similar to what I did in this comment, where you would have some struct (let's call it OverlayItem here) and you would create a new array of OverlayItem with onChange(of:_:) whenever the CoreData result changes, i.e.

struct OverlayItem: Identifiable {
    let id = UUID()
    let coordinates: [CLLocationCoordinate2D]
}

struct MyView: View {

    @State private var region: MKCoordinateRegion = ... // or use `mapRect: MKMapRect ` instead
    @State private var overlayItems = [OverlayItem]()
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \RoutePoint.timestamp, ascending: true)],
        animation: .default)
    private var route: FetchedResults<RoutePoint>
    
    var body: some View {
        Map(
            coordinateRegion: $region, // or mapRect: $mapRect
            overlayItems: overlayItems,
            overlayContent: {
            }
        )
        .onChange(of: route) { route in // not sure, if FetchedResults<RoutePoint> conforms to Equatable - if not, you might want to extend it accordingly
            self.overlayItems = [
                OverlayItem(
                    coordinates: route.map { point in
                        CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude)
                    }
                )
            ]
        }
    }

}

from map.

skyvalleystudio avatar skyvalleystudio commented on May 29, 2024

You are correct, I am trying to show a MapPolyline for a list of locations in CoreData. I think this may be a common use case. The challenge is that you are trying to support multiple overlays not just one polyline.

FetchedResults does not conform to Equatable but I don't want to do a complete comparison on it since Swifui responds to changes from an @FetchRequest (that's its reason for existing.) Now I'm trying to prepare the overlayItems in the view
and it seems to work, but I have to scroll the map to my current location (see below.)

My problem with the Ocean seems to be order of when my locationManager is getting set up. I changed it to have a default at Buckingham palace ;^). The thing I'm not seeing is the map following the location as I expected with the userTrackingMode I set.

I will be adding Annotations as well in the future, so I like your general solution to all of this.

The code I'm currently trying:


    @State var region = MKCoordinateRegion(center: LocationPublisher.shared.lastLocation?.coordinate ??           
                          CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12),
                                    latitudinalMeters: 1000,
                                    longitudinalMeters: 1000)
    @State private var userTrackingMode = UserTrackingMode.follow

    var body: some View {
        let overlayItems = [
            OverlayItem(
                coordinates: route.map { point in
                    CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude)
                }
            )
        ]

        Map(
            coordinateRegion: $region,
            type: .standard,
            pointOfInterestFilter: .excludingAll,
            informationVisibility: .default.union(.userLocation),
            interactionModes: .all,
            userTrackingMode: $userTrackingMode,
            overlayItems: overlayItems,
            overlayContent: { overlayItem in
                MapPolyline(coordinates: overlayItem.coordinates,
                            level: .aboveRoads,
                            strokeColor: .systemIndigo,
                            lineWidth: 5)
            }

        )

from map.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.