Polygon break in MapView after iOS 15.0 update - swift4

When closing lines of a polygon that after the third point in the map marking calculates an area between the points, it presented an error after the iOS 15.0 update. Some tests they work but most tests performed the polygon does not close visually and does not show the calculation. Even previous versions did not have this error.
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let polygonView = MKPolygonRenderer(overlay: overlay)
polygonView.strokeColor = Color.white()
if let _ = overlay as? MKPolygon{
polygonView.fillColor = Color.set(Color.white(), alpha: 0.2)
}
if(isAreaEnquadrada){
polygonView.strokeColor = Color.blue().withAlphaComponent(0.5)
polygonView.fillColor = Color.blue().withAlphaComponent(0.3)
}
//polygonView.fillColor = Color.set(Color.green(), alpha: 0.2)
polygonView.lineWidth = 2.0
polygonView.lineCap = CGLineCap.butt
isAreaEnquadrada = false
return polygonView
}
func toJson() -> [String: Any] {
var dictionary = [String: Any]()
dictionary["altitude"] = "0.1".formatToLocalCurrency(with: 2).replacingOccurrences(of: ",", with: ".")
dictionary["longitude"] = "\(self.longitude!.floatValue)".formatToLocalCurrency(with: 6).replacingOccurrences(of: ",", with: ".")
dictionary["latitude"] = "\(self.latitude!.floatValue)".formatToLocalCurrency(with: 6).replacingOccurrences(of: ",", with: ".")
return dictionary
}
if let polygon = PolygonSingleton.sharedInstance.currentPolygon {
if let sizeArea = polygon.area {
if sizeArea != 0 {
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
formatter.minimumIntegerDigits = 1
print(mainGleba.tamanhoArea)
if (mainGleba.tamanhoArea != nil && mainGleba.tamanhoArea! > 0) {
if let areaText = formatter.string(from: mainGleba.tamanhoArea!) {
print("Área text: \(areaText)")
areaSize = sizeArea as? Double
textFieldArea.text = "\(areaText.replacingOccurrences(of: ",", with: ".").formatToLocalCurrency(with: 2)) \(mainGleba.unidadeMedidaArea!)"
}
}else{
if let areaText = formatter.string(from: sizeArea) {
print("Área text: \(areaText)")
areaSize = sizeArea as? Double
textFieldArea.text = "\(areaText.replacingOccurrences(of: ",", with: ".").formatToLocalCurrency(with: 2)) \(mainGleba.unidadeMedidaArea!)"
}
}
if let areaText = formatter.string(from: mainGleba.areaFinanciavel) {
textFieldAreaFinanciavel.text = "\(areaText.replacingOccurrences(of: ",", with: ".").formatToLocalCurrency(with: 2)) \(mainGleba.unidadeMedidaArea!)"
}
} else {
textFieldArea.text = "Área sem demarcação"
}
}
}

Related

how to make the annotation move over the polyline

i have 3 annotation and i draw polyline between first and second annotation but i need the therd one move over that polyline but it's always move in street polyline to the destnation
-my code
func moveDelivery(_ destinationCoordinate : CLLocationCoordinate2D{
self.deliveryAnnotation.coordinate = CLLocationCoordinate2DMake(29.959640, 31.270421)
let sourcePlaceMark = MKPlacemark(coordinate: self.userAnnotation.coordinate)
//sourcePlaceMark.title
let destPlaceMkark = MKPlacemark(coordinate: self.deliveryAnnotation.coordinate)
let sourceItem = MKMapItem(placemark: sourcePlaceMark)
let destItem = MKMapItem(placemark: destPlaceMkark)
let directionRequest = MKDirections.Request()
directionRequest.source = sourceItem
directionRequest.destination = destItem
directionRequest.transportType = .any
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: {
response, error in
guard let response = response else {
if let error = error {
print(error.localizedDescription)
} else {
self.deliveryAnnotation.courseDegrees = self.getHeadingForDirectionFromCoordinate(self.kitchenAnnotation.coordinate, toLoc: self.userAnnotation.coordinate)
self.view.transform = CGAffineTransform(rotationAngle:CGFloat(self.deliveryAnnotation.courseDegrees))
}
return
}
guard let primaryRoute = response.routes.first else { return }
let route = response.routes[0]
self.mapView.addOverlay(route.polyline, level: .aboveRoads)
let rekt = route.polyline.boundingMapRect
self.mapView.setRegion(MKCoordinateRegion(rekt), animated: true)
})
//
UIView.animate(withDuration: Double(60), animations: {
self.deliveryAnnotation.coordinate = destinationCoordinate
}, completion: { success in
if success {
}
})
}
Your third annotation isn't following the route because you're animating it moving in a straight line between the first and second line. Try getting the coordinates from the MKRoute's polyline and animate between each one (According to apple's docs MKRoutes are made up of coordinates, but you might be able to use points as well)
If you'd like it to animate over the span of 60 seconds:
func moveDelivery(_ destinationCoordinate: CLLocationCoordinate2D) {
// I don't know why you have the delivery annotation start here, is this for testing?
deliveryAnnotation.coordinate = CLLocationCoordinate2DMake(29.959640, 31.270421)
let sourcePlaceMark = MKPlacemark(coordinate: destinationCoordinate)
let destPlaceMkark = MKPlacemark(coordinate: userAnnotation.coordinate)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlaceMark)
directionRequest.destination = MKMapItem(placemark: destPlaceMkark)
directionRequest.transportType = .any
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: {
response, error in
guard let response = response else {
print("MKRequest gave no response")
if let error = error {
print(error.localizedDescription)
} else {
self.deliveryAnnotation.courseDegrees = self.getHeadingForDirectionFromCoordinate(self.kitchenAnnotation.coordinate, toLoc: self.userAnnotation.coordinate)
self.view.transform = CGAffineTransform(rotationAngle:CGFloat(self.deliveryAnnotation.courseDegrees))
}
return
}
guard let primaryRoute = response.routes.first else {
print("response has no routes")
return
}
self.mapView.addOverlay(primaryRoute.polyline, level: .aboveRoads)
let rekt = primaryRoute.polyline.boundingMapRect
self.mapView.setRegion(MKCoordinateRegion(rekt), animated: true)
let coordinateArray = primaryRoute.polyline.coordinates
assert(coordinateArray.count > 0, "coordinate array is empty")
self.routeCoordinates = coordinateArray
// initiate recursive animations
self.coordinateIndex = 0
})
}
var routeCoordinates = [CLLocationCoordinate2D]()
var avgAnimationTime: Double {
return 60 / Double(routeCoordinates.count)
}
var coordinateIndex: Int! {
didSet {
guard coordinateIndex != routeCoordinates.count else {
print("animated through all coordinates, stopping function")
return
}
animateToNextCoordinate()
}
}
func animateToNextCoordinate() {
let coordinate = routeCoordinates[coordinateIndex]
UIView.animate(withDuration: avgAnimationTime, animations: {
self.deliveryAnnotation.coordinate = coordinate
}, completion: { _ in
self.coordinateIndex += 1
print("moved between coordinates")
})
}
EDIT
make sure to include this extension, otherwise you won't be able to get the coordinates of the MKRoute (source: https://gist.github.com/freak4pc/98c813d8adb8feb8aee3a11d2da1373f)
public extension MKMultiPoint {
var coordinates: [CLLocationCoordinate2D] {
var coords = [CLLocationCoordinate2D](repeating: kCLLocationCoordinate2DInvalid,
count: pointCount)
getCoordinates(&coords, range: NSRange(location: 0, length: pointCount))
return coords
}
}
EDIT #2
See above, edited original answer to animate through each coordinate after the previous finishes animating. Really rough but it should work.
EDIT #3
Added your code to get the destination variable as well as some assert and debug printing calls. If things aren't working this time, please tell me which debug messages you get.
EDIT #4
I just demo'd my code and it works. Here is the MapViewController class I used along with necessary extensions:
private let reuseId = "deliveryReuseId"
private let userTitle = "user"
private let startingPointTitle = "store"
private let deliveryTitle = "delivery truck"
class MapViewController: UIViewController {
var mapView: MKMapView!
// annotations for this demo, replace with your own annotations
var deliveryAnnotation: MKPointAnnotation = {
let annotation = MKPointAnnotation()
annotation.title = deliveryTitle
return annotation
}()
let userAnnotation: MKPointAnnotation = {
let annotation = MKPointAnnotation()
annotation.title = userTitle
annotation.coordinate = CLLocationCoordinate2DMake(29.956694, 31.276854)
return annotation
}()
let startingPointAnnotation: MKPointAnnotation = {
let annotation = MKPointAnnotation()
annotation.title = startingPointTitle
annotation.coordinate = CLLocationCoordinate2DMake(29.959622, 31.270363)
return annotation
}()
override func viewDidLoad() {
super.viewDidLoad()
loadMapView()
navigate()
}
func loadMapView() {
// set map
mapView = MKMapView()
view = mapView
mapView.delegate = self
mapView.register(MKAnnotationView.self, forAnnotationViewWithReuseIdentifier: reuseId)
// add annotations
mapView.addAnnotation(userAnnotation)
mapView.addAnnotation(startingPointAnnotation)
mapView.addAnnotation(deliveryAnnotation)
}
func navigate() {
let sourcePlaceMark = MKPlacemark(coordinate: startingPointAnnotation.coordinate)
let destPlaceMkark = MKPlacemark(coordinate: userAnnotation.coordinate)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlaceMark)
directionRequest.destination = MKMapItem(placemark: destPlaceMkark)
directionRequest.transportType = .any
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { response, error in
if let error = error {
print(error.localizedDescription)
return
}
guard let primaryRoute = response!.routes.first else {
print("response has no routes")
return
}
self.mapView.addOverlay(primaryRoute.polyline, level: .aboveRoads)
self.mapView.setRegion(MKCoordinateRegion(primaryRoute.polyline.boundingMapRect), animated: true)
// initiate recursive animation
self.routeCoordinates = primaryRoute.polyline.coordinates
self.coordinateIndex = 0
})
}
var routeCoordinates = [CLLocationCoordinate2D]()
var avgAnimationTime: Double {
// to show delivery in 60 second, replace 60 with amount of seconds you'd like to show
return 60 / Double(routeCoordinates.count)
}
var coordinateIndex: Int! {
didSet {
guard coordinateIndex != routeCoordinates.count else {
print("animated through all coordinates, stopping function")
return
}
animateToNextCoordinate()
}
}
func animateToNextCoordinate() {
let coordinate = routeCoordinates[coordinateIndex]
UIView.animate(withDuration: avgAnimationTime, animations: {
self.deliveryAnnotation.coordinate = coordinate
}, completion: { _ in
self.coordinateIndex += 1
})
}
}
extension MapViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
// replace these images with your own
switch annotation.title {
case userTitle:
annotationView.image = UIImage(named: "user")
case startingPointTitle:
annotationView.image = UIImage(named: "store")
case deliveryTitle:
annotationView.image = UIImage(named: "deliveryTruck")
default: break
}
return annotationView
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard overlay is MKPolyline else {
return MKOverlayRenderer()
}
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .black
renderer.lineWidth = 5
renderer.lineJoin = .round
return renderer
}
}
public extension MKMultiPoint {
var coordinates: [CLLocationCoordinate2D] {
var coords = [CLLocationCoordinate2D](repeating: kCLLocationCoordinate2DInvalid,
count: pointCount)
getCoordinates(&coords, range: NSRange(location: 0, length: pointCount))
return coords
}
}

swift find the 2nd and 3rd lowest numbers in an array -

Below I have a list of cities and I compare a user's current location to the cities and use the (min) function
let closestCity = min(theDistanceInMetersFromBusselton,theDistanceInMetersFromBunbury,theDistanceInMetersFromJoondalup,theDistanceInMetersFromArmadale)
to return the closest city, though now I would like to return the second and third closest city.
I haven't been able to get this to work as yet though I'm thinking something along the lines of:
citiesArray - closestCity = SecondClosestCitiesArray
then do a secondClosestCity = min(SecondClosestCitiesArray) to get the second closest city.
Then repeat this to find the third closest?
Any ideas?
extension HomePage {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let db = Firestore.firestore()
guard let uid = Auth.auth().currentUser?.uid else { return }
let location = locations[0]
let actualLatitude = String(location.coordinate.latitude)
let actualLongitude = String(location.coordinate.longitude)
guard let doubleActualLatitude = Double(actualLatitude) else { return }
guard let doubleActualLongitude = Double(actualLongitude) else { return }
///users current location
let usersCurrentLocation = CLLocation(latitude: doubleActualLatitude, longitude: doubleActualLongitude)
//////////////list of locations ////////////////
//////////ARMADALE/////////////////////
let ArmadaleLatitude = Double(-32.1530)
let ArmadaleLongitude = Double(116.0150)
let ArmadaleCoordinates = CLLocation(latitude:ArmadaleLatitude, longitude: ArmadaleLongitude)
let theDistanceInMetersFromArmadale = usersCurrentLocation.distance(from: ArmadaleCoordinates)
////////////////Bunbury///////////////////
let BunburyLatitude = Double(-33.3256)
let BunburyLongitude = Double(115.6396)
let BunburyCoordinates = CLLocation(latitude:BunburyLatitude, longitude: BunburyLongitude)
let theDistanceInMetersFromBunbury = usersCurrentLocation.distance(from: BunburyCoordinates)
/////////////////////////////////////////////
////////Busselton//////////////////
let busseltonLatitude = Double(-33.6555)
let busseltonLongitude = Double(115.3500)
let busseltonCoordinates = CLLocation(latitude:busseltonLatitude, longitude: busseltonLongitude)
let theDistanceInMetersFromBusselton = usersCurrentLocation.distance(from: busseltonCoordinates)
/////////////////////////////////
/////////Joondalup////////////////////
let JoondalupLatitude = Double(-32.5361)
let JoondalupLongitude = Double(115.7424)
let JoondalupCoordinates = CLLocation(latitude:JoondalupLatitude, longitude: JoondalupLongitude)
let theDistanceInMetersFromJoondalup = usersCurrentLocation.distance(from: JoondalupCoordinates)
//////////////////////////////////////
/////return the the closest city
let closestCity = min(theDistanceInMetersFromBusselton,theDistanceInMetersFromBunbury,theDistanceInMetersFromJoondalup,theDistanceInMetersFromArmadale)
func findClosestCity(){
//////////Armadale////////////////////////
if closestCity == theDistanceInMetersFromArmadale{
db.collection("Users").document(uid).setData(["Location": "Armadale" ], options: SetOptions.merge())
/////////Bunbury////////////
}else if closestCity == theDistanceInMetersFromBunbury{
let Bunbury = "Bunbury"
db.collection("Users").document(uid).setData(["Location": Bunbury ], options: SetOptions.merge())
///////////// Busselton//////////////
}else if closestCity == theDistanceInMetersFromBusselton{
let Busselton = "Busselton"
db.collection("Users").document(uid).setData(["Location": Busselton ], options: SetOptions.merge())
/////////////Joondalup//////////////////
}else if closestCity == theDistanceInMetersFromJoondalup{
db.collection("Users").document(uid).setData(["Location": "Joondalup" ], options: SetOptions.merge())
}
}
}
}
let cityLocations = [
"Armadale": CLLocation(latitude: -32.1530, longitude: 116.0150),
"Bunbury": CLLocation(latitude: -33.3256, longitude: 115.6396),
"Busselton": CLLocation(latitude: -33.6555, longitude: 115.3500),
"Joondalup": CLLocation(latitude: -32.5361, longitude: 115.7424)
]
func distanceFromCity(_ city: String, location: CLLocation) -> Double? {
return cityLocations[city].flatMap { location.distance(from: $0) }
}
func citiesClosestToLocation(_ location: CLLocation, n: Int) -> [String] {
let cities = cityLocations.sorted {
location.distance(from: $0.value) < location.distance(from: $1.value)
}
return cities.dropLast(cities.count - n).map({ $0.key })
}
let testLocation = cityLocations["Armadale"]!
print(citiesClosestToLocation(testLocation, n: 3)) // ["Armadale", "Joondalup", "Bunbury"]
You can add these value into an array and while adding it, make sure that they are getting added to sorting order. The array at any given point will give you closest city on the first index and second closest city on the second index.
Here is an example :
extension Array where Element == Double {
mutating func appendSorted(_ element: Double) {
if self.count == 0 {
self.append(element)
return
}
for i in 0..<self.count {
if element < self[i] {
self.insert(element, at: i)
return
}
}
self.append(element)
}
}

drawGlyphsForGlyphRange in Swift (Displaying Invisible characters). replaceGlyphAtIndex deprecated

I am trying to show Invisible characters using below class & func, and it is working fine.
But replaceGlyphAtIndex is deprecated in OS X 10.11 and we need to use setGlyhs()
setGlyphs(<#T##glyphs: UnsafePointer<CGGlyph>##UnsafePointer<CGGlyph>#>, properties: <#T##UnsafePointer<NSGlyphProperty>#>, characterIndexes: <#T##UnsafePointer<Int>#>, font: <#T##NSFont#>, forGlyphRange: <#T##NSRange#>)
But i am having difficulties on how to convert replaceGlyphAtIndex to setGlyphs.
Can any one suggest me how to convert below replaceGlyphAtIndex to setGlyphs()?
I tried as below but it is crashing.
let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
let cgG = UnsafePointer<CGGlyph>(data!.bytes)
self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))
Can any one let me know whats going wrong in the above line of code?
class MyLayoutManager: NSLayoutManager {
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ": //Blank Space
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("period")//("periodcentered")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
// let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
// let cgG = UnsafePointer<CGGlyph>(data!.bytes)
//
// self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))
}
case "\n": //New Line
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("logicalnot")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case newLineUniCodeStr:
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("logicalnot")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
default:
break
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}
}
I found another way to display Glyphs. (Posting my code below as it may be useful to others)
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
var padding:CGFloat = 0
for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
if characterIndex < s.characters.count
{
var glyphStr = ""
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ": //Blank Space
glyphStr = periodCenteredUniCodeStr
case "\n": //New Line
glyphStr = lineBreakUniCodeStr
case newLineUniCodeStr:
glyphStr = lineBreakUniCodeStr
padding += 5
default:
break
}
var glyphPoint = self.locationForGlyphAtIndex(glyphIndex)
let glyphRect = self.lineFragmentRectForGlyphAtIndex(glyphIndex, effectiveRange: nil)
if glyphStr.characters.count > 0{
glyphPoint.x = glyphPoint.x + glyphRect.origin.x
glyphPoint.y = glyphRect.origin.y
NSString(string: glyphStr).drawInRect(NSMakeRect(glyphPoint.x, glyphPoint.y, 10, 10), withAttributes: nil)
}
}else{
print("Wrong count here")
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}

How to update annotations when in mapview on zoom?

I'm trying to make an app, where you get buses positions from web API. When I got the data, I put annotations on mapview for all of the coordinates i got from API. Then, when annotation is tapped on, I try to hide all the annotations which aren't on the same route as the one clicked. It works fine, but when I zoom out the annotations that weren't in the original region aren't hidden. Is there a way to refresh what is displayed when user zooms on map view?
import UIKit
import MapKit
import MBProgressHUD
import Alamofire
class MapViewController: UIViewController {
//MARK: Properties and Outlets
private var timer: NSTimer?
private lazy var dateFormatter = NSDateFormatter()
private var vehicles = [String: Vehicle]()
private var points = [CLLocationCoordinate2D]()
private let locationManager = CLLocationManager()
private var currentLocation: CLLocation?
#IBOutlet weak var mapView: MKMapView!
//MARK: Actions
#IBAction func getMyLocation(sender: UIBarButtonItem) {
getLocation()
}
//MARK: Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.dateFormat = "HH:mm:ss"
timer = NSTimer.scheduledTimerWithTimeInterval(30, target: self, selector: "fetchVehiclesLocations", userInfo: nil, repeats: true)
fetchVehiclesLocations()
getLocation()
}
//MARK: Get Location
private func getLocation() {
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .NotDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
if authStatus == .Denied || authStatus == .Restricted {
showLocationServicesDeniedAlert()
return
}
startLocationManager()
}
//MARK: Helper methods
private func showLocationServicesDeniedAlert() {
let alert = UIAlertController(title: "Location Services Disabled", message: "Please enable location services for this app in Settings.", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(okAction)
presentViewController(alert, animated: true, completion: nil)
}
private func startLocationManager () {
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
showLoadingHUD()
}
}
private func stopLocationManager() {
locationManager.delegate = nil
locationManager.stopUpdatingLocation()
hideLoadingHUD()
}
private func rotateBus() {
UIView.animateWithDuration(1.0, delay: 0, options: .CurveLinear, animations: {
for (id, _) in self.vehicles {
if self.vehicles[id]!.lastPosition != nil {
let annotationView = self.mapView.viewForAnnotation(self.vehicles[id]!.annotation!)
let currentLocationPoint = self.mapView.convertCoordinate(self.vehicles[id]!.lastPosition!, toPointToView: self.mapView)
let destinationPoint = self.mapView.convertCoordinate(self.vehicles[id]!.coordinates, toPointToView: self.mapView)
let yDiff = currentLocationPoint.y - destinationPoint.y
let xDiff = destinationPoint.x - currentLocationPoint.x
let arcTan = atan(yDiff / xDiff)
var angle = CGFloat(M_PI / 2) - arcTan
if xDiff < 0 {
angle = angle + CGFloat(M_PI)
}
if angle.isNaN || angle == 0.0 {
continue
}
else {
annotationView?.transform = CGAffineTransformMakeRotation(CGFloat(angle))
}
}
}
}, completion: nil)
moveBus()
}
private func moveBus() {
UIView.animateWithDuration(28.0, delay: 0, options: .CurveLinear, animations: {
for(id, _) in self.vehicles {
if self.vehicles[id]!.lastPosition != nil {
self.vehicles[id]!.annotation?.coordinate = self.vehicles[id]!.coordinates
}
}
}, completion: nil)
}
private func createVehicles() {
print(vehicles.count)
for (id, _) in vehicles {
if vehicles[id]?.annotation == nil {
let annotation = BusAnnotation()
annotation.imageName = "bus"
annotation.coordinate = vehicles[id]!.coordinates
annotation.title = id
vehicles[id]?.annotation = annotation
mapView.addAnnotation(annotation)
}
}
print(mapView.annotations.count)
rotateBus()
}
private func drawPolyline() {
let myPolyline = MKPolyline(coordinates: &points, count: points.count)
mapView.addOverlay(myPolyline)
}
//MARK: HUD display methods
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(mapView, animated: true)
hud.labelText = "Getting Your Location..."
}
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(mapView, animated: true)
}
//MARK: Networking
func fetchVehiclesLocations() {
let URL = urlVehiclesLocations + apiKey
if !vehicles.isEmpty {
for (id , _) in vehicles {
vehicles[id]?.lastPosition = vehicles[id]?.coordinates
}
}
Alamofire.request(.GET, URL)
.validate()
.responseJSON {
(request, response, result) in
guard result.isSuccess else {
print("Error while fetching \(result.error!)")
return
}
let value = result.value as? [String: AnyObject]
let responseDict = value?["response"] as? [String: AnyObject]
let array = responseDict?["entity"] as? [[String: AnyObject]]
for var i = 0; i < array?.count; i++ {
let item = array?[i]["vehicle"] as? [String: AnyObject]
let position = item?["position"] as? [String: AnyObject]
let trip = item?["trip"] as? [String: AnyObject]
let vehicle = Vehicle()
vehicle.latitude = position?["latitude"] as! Double
vehicle.longitude = position?["longitude"] as! Double
vehicle.tripId = trip?["trip_id"] as! String
let startTime = trip?["start_time"] as! String
vehicle.startTime = self.dateFormatter.dateFromString(startTime)
let vehicleId = item?["vehicle"] as? [String: AnyObject]
let id = vehicleId?["id"] as! String
if self.vehicles[id] == nil {
self.vehicles[id] = vehicle
}
else {
self.vehicles[id]?.latitude = vehicle.latitude
self.vehicles[id]?.longitude = vehicle.longitude
}
}
self.createVehicles()
}
}
func fetchPointsForTripPolyline() {
let URL = urlTripPolyline + apiKey
Alamofire.request(.GET, URL)
.validate()
.responseJSON {
(request, response, result) in
guard result.isSuccess else {
print("Error while fetching \(result.error!)")
return
}
let value = result.value as! [String: AnyObject]
let responseArray = value["response"] as! [[String: AnyObject]]
for var i = 0; i < responseArray.count; i++ {
let longitude = responseArray[i]["shape_pt_lon"] as! CLLocationDegrees
let latitude = responseArray[i]["shape_pt_lat"] as! CLLocationDegrees
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
self.points.append(coordinate)
}
self.drawPolyline()
}
}
}
extension MapViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newLocation = locations.last!
if newLocation.timestamp.timeIntervalSinceNow < -5 {
return
}
if newLocation.horizontalAccuracy < 0 {
return
}
if newLocation.horizontalAccuracy <= locationManager.desiredAccuracy {
stopLocationManager()
currentLocation = newLocation
let annotation = MKPointAnnotation()
annotation.coordinate = newLocation.coordinate
mapView.addAnnotation(annotation)
}
let center = CLLocationCoordinate2D(latitude: newLocation.coordinate.latitude, longitude: newLocation.coordinate.longitude)
let region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000)
self.mapView.setRegion(region, animated: true)
}
}
extension MapViewController: MKMapViewDelegate {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if !(annotation is BusAnnotation) {
return nil
}
let reuseId = annotation.title!
var busAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId!)
if busAnnotationView == nil {
busAnnotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
busAnnotationView?.canShowCallout = true
}
else {
busAnnotationView?.annotation = annotation
}
let busAnnotation = annotation as! BusAnnotation
busAnnotationView?.image = UIImage(named: busAnnotation.imageName)
return busAnnotationView
}
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline {
let lineView = MKPolylineRenderer(overlay: overlay)
lineView.lineWidth = 3.0
lineView.strokeColor = UIColor.greenColor()
return lineView
}
return MKOverlayRenderer()
}
func hideBuses(tripId: String) {
for (_, vehicle) in vehicles {
if vehicle.tripId != tripId {
let annotationView = mapView.viewForAnnotation(vehicle.annotation!)
annotationView?.hidden = true
}
}
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
let vehicleId = view.annotation?.title!
let tripId = vehicles[vehicleId!]?.tripId
hideBuses(tripId!)
}
}

how to draw CombinedChart in ios-chart

I am using this lib for drawChart. Link: https://github.com/danielgindi/Charts
THis is my code. When i draw only CandleChart, it is OK.
But when I try to draw CombinedChart. I receiver this result.
This is my result
#IBOutlet weak var chart: CombinedChartView!
var date1 = [String]()
var open = [Double]()
var high = [Double]()
var low = [Double]()
var close = [Double]()
var volume = [Double]()
var adj_close = [Double]()
let gradientLayer = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
loadVcs()
chart.delegate = self
chart.descriptionText = ""
chart.noDataTextDescription = ""
chart.drawGridBackgroundEnabled = false
chart.maxVisibleValueCount = 0
chart.pinchZoomEnabled = false
let xAxis = chart.xAxis
xAxis.labelPosition = ChartXAxis.XAxisLabelPosition.Bottom
xAxis.spaceBetweenLabels = 15
xAxis.drawLabelsEnabled = true
let leftAxis = chart.leftAxis
leftAxis.labelCount = 7
leftAxis.drawLabelsEnabled = false
leftAxis.drawAxisLineEnabled = false
let rightAxis = chart.rightAxis
rightAxis.drawGridLinesEnabled = true
rightAxis.enabled = true
setData()
}
override func viewWillAppear(animated: Bool) {
gradientLayer.frame = self.view.bounds
let color1 = UIColor.yellowColor().CGColor as CGColorRef
let color2 = UIColor(red: 1.0, green: 0, blue: 0, alpha: 1.0).CGColor as CGColorRef
let color3 = UIColor.clearColor().CGColor as CGColorRef
let color4 = UIColor(white: 0.0, alpha: 0.7).CGColor as CGColorRef
gradientLayer.colors = [color1, color2, color3, color4]
gradientLayer.locations = [0.0, 0.0, 1.0, 1.0]
// self.chart.layer.addSublayer(gradientLayer)
}
func loadVcs()
{
var csv :CSV?
do {
let path = NSBundle.mainBundle().pathForResource("FB", ofType: "csv")
csv = try CSV(name: path!)
if let data = csv {
for dict in data.rows
{
date1.insert(dict["Date"]!, atIndex: 0)
open.insert(Double(dict["Open"]!)!, atIndex: 0)
high.insert(Double(dict["High"]!)!, atIndex: 0)
low.insert(Double(dict["Low"]!)!, atIndex: 0)
close.insert(Double(dict["Close"]!)!, atIndex: 0)
volume.insert(Double(dict["Volume"]!)!, atIndex: 0)
adj_close.insert(Double(dict["Adj Close"]!)!, atIndex: 0)
}
}
} catch let error {
NSLog("\(error)")
}
}
func setData()
{
let data : CombinedChartData = CombinedChartData(xVals: date1)
data.candleData = generateCandleChartData(date1)
data.lineData = generateLineChartData(date1)
chart.data = data
}
func generateLineChartData(xVals : [String]) -> LineChartData
{
var d = LineChartData(xVals: xVals)
var lineVals = [ChartDataEntry]()
for i in 0 ..< date1.count
{
lineVals.append(ChartDataEntry(value: high[i], xIndex: i))
}
let lineChartDataSet : LineChartDataSet = LineChartDataSet(yVals: lineVals, label: "Line Data Set")
lineChartDataSet.setColor(UIColor.greenColor())
lineChartDataSet.lineWidth = 2.5
lineChartDataSet.drawCubicEnabled = true
lineChartDataSet.drawValuesEnabled = true
d.addDataSet(lineChartDataSet)
return d
}
func generateCandleChartData(xVals : [String]) -> CandleChartData
{
var d = CandleChartData(xVals: xVals)
var yVals = [ChartDataEntry]()
for i in 0 ..< date1.count
{
yVals.append(CandleChartDataEntry(xIndex: i, shadowH: high[i], shadowL: low[i], open: open[i] , close: close[i] ))
}
let set1 = CandleChartDataSet(yVals: yVals, label: "Data")
set1.axisDependency = ChartYAxis.AxisDependency.Left
set1.setColor(UIColor(white: (80/255), alpha: 1.0))
set1.shadowColor = UIColor.darkGrayColor()
set1.shadowWidth = 1
set1.decreasingColor = UIColor.redColor()
set1.decreasingFilled = true
set1.increasingColor = UIColor(red: 122/255, green: 242/255, blue: 84/255, alpha: 1)
set1.increasingFilled = true
set1.neutralColor = UIColor.blueColor()
d.addDataSet(set1)
return d
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight) {
NSLog("chartValueSelected")
}
func chartValueNothingSelected(chartView: ChartViewBase) {
NSLog("chartValueNoSelected")
}
Please help me :)
Please take a look at the ChartsDemo which is part of the library, there is combined chart for your reference.