I had to show locations around the user location. The locations info will arrive from the server. I am using 'for' loop to parse the location and add to map with annotation pin. As of now, it shows only the last arrived location. But the requirement is such that multiple locations should be shown with user location as Center point. As of now I am able to show only one pin. Please help how to achieve this?
for (NSDictionary* dictionary in responseDict)
{
NSString *latitudeString=[NSString stringWithFormat:#"%#",[dictionary valueForKey:#"LATITUDE"]];
double latitude=[latitudeString doubleValue];
NSString *longitudeString=[NSString stringWithFormat:#"%#",[dictionary valueForKey:#"LONGITUDE"]];
double longitude=[longitudeString doubleValue];
NSLog(#"the LATITUDE AND LONGITUDE is %f, %f",latitude,longitude);
CLLocationCoordinate2D locationCoordinate;
locationCoordinate.latitude=latitude;
locationCoordinate.longitude=longitude;
[self.mapView addAnnotation:locationCoordinate withPinColor:WKInterfaceMapPinColorPurple];
MKCoordinateSpan coordinateSpan = MKCoordinateSpanMake(0.05, 0.05);
[self.mapView setRegion:(MKCoordinateRegionMake(locationCoordinate, coordinateSpan))];
}
`
You zoom on a single location in each iteration of the loop, so eventually you end up zoomed on the last location. Sadly WKInterfaceMap doesn't have a showAnnotations method as MKMapView does, so you need to write a function yourself to achieve showing an MKCoordinateRegion including several annotations.
I haven't written any Obj-C for a while, but here's the function in Swift that shows two annotations on a Map and works on watchOS:
func showTwoMapCoordinates(first: CLLocationCoordinate2D, second: CLLocationCoordinate2D)->MKCoordinateRegion{
let center = CLLocationCoordinate2D(latitude: (first.latitude+second.latitude)/2, longitude: (first.longitude+second.longitude)/2)
var latDelta:CLLocationDegrees {
let delta = abs((first.latitude-second.latitude)*1.4)
if delta > 0 {
return delta
} else {
return 0.1
}
}
var lonDelta:CLLocationDegrees {
let delta = abs((first.longitude-second.longitude)*1.4)
if delta > 0 {
return delta
} else {
return 0.1
}
}
let span = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
return MKCoordinateRegion(center: center, span: span)
}
To extend this to n points, where n>2, all you need to do is iterate through each pair of points you want to display, find the maximum deltas the same way as in the function above and set the center and span using the function above called on the two points that yielded the max deltas.
Related
I am using a map with some annotations, I want to group the nearest annotations in annotation group to not overlap in the design in case of user zoom out, but my problem is to how to know the distance between annotations and this distance should change when zooming in and out.
the distance should be between points with x and y formate note meters
So my question is to how to catch the difference between 2 points on the map and consider the zoom
// convert location to cLLocation
let cLLocation1 = CLLocation(latitude: post1Location?.lat ?? 0, longitude: post1Location?.lng ?? 0)
let cLLocation2 = CLLocation(latitude: post2Location?.lat ?? 0, longitude: post2Location?.lng ?? 0)
// this is return the dinsactence in metres but i don't need that
let distance = cLLocation1.distance(from: cLLocation2)
let annotaionPoint1 = MKMapPoint(cLLocation1.coordinate)
let annotaionPoint2 = MKMapPoint(cLLocation2.coordinate)
let xDistance = max(annotaionPoint1.x, annotaionPoint2.x) - min(annotaionPoint1.x, annotaionPoint2.x)
let yDistance = max(annotaionPoint1.y, annotaionPoint2.y) - min(annotaionPoint1.y, annotaionPoint2.y)
this is working but zoom in and zoom out no effect so I need zoom to make change
if min(xDistance, yDistance) <= 32 {
/// action
}
I am in a confusion, on how to get a zoom level and radius of a visible area of the map (using mapkit mapview).
Here is what I am looking for (either of them or both, as needed) -
Zoom level, is to see at what level of the map is being shown to the users and with that information, I want to display the custom pins in the visible area. If zoom level is high, I need to show the actual logos of some commerce stores as pins. If zoom level is low, I need to show colored dots instead of logos.
As of now, I am using let updatedRadius = (mapView.camera.altitude)/1000 to get altitude of the camera, and if the updatedRadius value is > 25.0, I am showing colored dots. Below 25.0, I show the logos. I am doing this in regionDidChanged
Is this approach correct?
Radius, is to send it as a parameter to my REST API to fetch the list of places within that radius. When user zooms out on the map, visible area increases and so the REST API needs bigger radius to return the places covered in that area.
Ultimately, what should happen is, whenever user zooms out, then the radius changes. I need to send this changed radius to my REST to get an updated list.
What are latitude longtitude deltas, can we get radius/width of visible area using these values?
let latitudeDeltaVal = mapView.region.span.latitudeDelta
let longitudeDeltaVal = mapView.region.span.longitudeDelta
Can someone throw some light on what needs to be done please?
Since you need to call the api when the region changes you need to calculate the radius in mapView's delegate function, RegionDidChange.
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let centralLocation = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
self.centralLocationCoordinate = mapView.centerCoordinate
print("Radius - \(self.getRadius(centralLocation))")
}
func getRadius(centralLocation: CLLocation) -> Double{
let topCentralLat:Double = centralLocation.coordinate.latitude - mapView.region.span.latitudeDelta/2
let topCentralLocation = CLLocation(latitude: topCentralLat, longitude: centralLocation.coordinate.longitude)
let radius = centralLocation.distanceFromLocation(topCentralLocation)
return radius / 1000.0 // to convert radius to meters
}
To account for both landscape and portrait orientations, and/or situations where the map orientation is close to Northeast, Northwest, Southwest, Southeast, and to enclose the full screen up to the corners, one should consider both latitudeDelta and longitudeDelta:
func getRadius() -> Double{
let centralLocation = CLLocation(latitude: mapView.region.center.latitude, longitude: mapView.region.center.longitude)
let cornerOfMap = CLLocation(latitude: centralLocation.coordinate.latitude + mapView.region.span.latitudeDelta , longitude: centralLocation.coordinate.longitude + mapView.region.span.longitudeDelta)
let radius = centralLocation.distance(from: cornerOfMap)
return radius / 1000.0 // to convert radius to meters
}
I found a method for android called setLatLngBoundsForCameraTarget. But could not find for ios. Has any one idea about it? I want to scroll into particular bound. User can't scroll out of the bound which is already defined
The iOS equivalent method is setCameraTargetBounds. You can use it as follows:
GMSCoordinateBounds *gmsBounds = [[GMSCoordinateBounds alloc]
initWithCoordinate:bounds.northWest
coordinate:bounds.southEast];
[self.mapView setCameraTargetBounds:bounds];
Additionally, you may want to set a minimum zoom level, by doing this:
[self.mapView setMinZoom:15 maxZoom:23];
Try this :
let camera = GMSCameraPosition.camera(withLatitude: -33.8683,
longitude: 151.2086,
zoom: 16)
let mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
More
I used cameraTargetBounds but not useful for me. Then I used
func mapView(mapView: GMSMapView, didChangeCameraPosition position: GMSCameraPosition) {
var latitude = position.target.latitude;
var longitude = position.target.longitude;
if (position.target.latitude > bounds.northEast.latitude) {
latitude = bounds.northEast.latitude;
}
if (position.target.latitude < bounds.southWest.latitude) {
latitude = bounds.southWest.latitude;
}
if (position.target.longitude > bounds.northEast.longitude) {
longitude = bounds.northEast.longitude;
}
if (position.target.longitude < bounds.southWest.longitude) {
longitude = bounds.southWest.longitude;
}
if (latitude != position.target.latitude || longitude != position.target.longitude) {
var l = CLLocationCoordinate2D();
l.latitude = latitude;
l.longitude = longitude;
mapView.animateToLocation(l);
}
}
And it works.
I am using this to zoom into the users location at startup.
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
var newRegion = MKCoordinateRegion(center: coord, span: MKCoordinateSpanMake(spanX, spanY))
mapView.setRegion(newRegion, animated: true)
}
Now I'd like to take an action if the map has been zoomed into the users location. I've tried to use the mapDidChange delegate method, but this is fired a few times. Any thoughts how to do this the clever way? (iOS 8 / Swift)
Just In my opinion , you can compare newRegion's span values with map view's current span values in regionDidChangeAnimated. If span values are the same, you can secondly play with "mapview.region". May be getting visible mapView.region and comparing it with newRegion or getting centre coordinate of current visible region and comparing it with current location's coordinate can work.
How can I center a map between two points? Sort of like when the native map application generates directions between location A and location B. I'm got a start coordinate and an end coordinate and I'll like to show two pins. I can place the pins in place, but I'm not sure how to set the center of the map.
Do I need to find the math to work out the exact distance from the points and set the map to that location? Is there a built in function for this?
this.currentMapView.SetCenterCoordinate (annotation.Coordinate, true);
Calculating the midpoint between two coordinates needs a simple formula. For example, let's say you have two coordinates: (x1,y1) and (x2,y2).
Their midpoint coordinate is: ( (x1+x2)/2, (y1+y2)/2 ).
So for example, in map coordinates, let's say you have the following start/end points:
a. long: 40, lat: 39
b. long: 41, lat: 38
Their midpoint coordinate is: ( (40+41)/2, (39+38)/2 ) = (40.5, 38.5)
So you set the map view's center coordinate to the outcome of this formula.
I am not aware of a built-in function for calculating this.
Taken from: http://codisllc.com/blog/zoom-mkmapview-to-fit-annotations/
BasicMapAnnotation is inherit class from MKAnnotation
private void GetRegion(MKMapView mapView)
{
var userWasVisible = mapView.ShowsUserLocation;
mapView.ShowsUserLocation = false; // ignoring the blue blip
// start with the widest possible viewport
var tl = new CLLocationCoordinate2D(-90, 180); // top left
var br = new CLLocationCoordinate2D(90, -180); // bottom right
foreach (var an in mapView.Annotations)
{
// narrow the viewport bit-by-bit
CLLocationCoordinate2D coordinate = ((BasicMapAnnotation) an).Coordinate;
tl.Longitude = Math.Min(tl.Longitude, coordinate.Longitude);
tl.Latitude = Math.Max(tl.Latitude, coordinate.Latitude);
br.Longitude = Math.Max(br.Longitude, coordinate.Longitude);
br.Latitude = Math.Min(br.Latitude, coordinate.Latitude);
}
var center = new CLLocationCoordinate2D
{
// divide the range by two to get the center
Latitude = tl.Latitude - (tl.Latitude - br.Latitude)*0.5
,
Longitude = tl.Longitude + (br.Longitude - tl.Longitude)*0.5
};
var span = new MKCoordinateSpan
{
// calculate the span, with 20% margin so pins aren’t on the edge
LatitudeDelta = Math.Abs(tl.Latitude - br.Latitude)*1.2
,
LongitudeDelta = Math.Abs(br.Longitude - tl.Longitude)*1.2
};
var region = new MKCoordinateRegion {Center = center, Span = span};
region = mapView.RegionThatFits(region); // adjusts zoom level too
mapView.SetRegion(region, true); // animated transition
mapView.ShowsUserLocation =
userWasVisible;
}
} ``