Bonjour les codeurs,
Je me suis lancée dans un projet sur les bornes électriques pour les voitures, j’aimerais une analyse de pointure pour savoir si je fais fausse route.
L’idée je vais lire un fichier de donnée (csv) que l’on trouve sur data.gouv, une fois les données lues, je crée un tableau, qui va être affiché sur une carte.
Mon problème :
une fois que la carte s’affiche, la console se remplit de messages d’erreur, et cela bloque la carte, je ne peux pas non plus cliquer sur les points pour afficher le détail (certains seulement).
Je cherche l’origine du problème, mais je ne trouve pas mon erreur, je cherche depuis un bon moment déjà.
Je ne sais pas si on peut créer une carte avec des données venant d’un tableau, c’est peut-être la taille du tableau qui pose problème ou les données du csv ou je fais fausse route complètement plus de pistes.
Source des données Fichier consolidé des Bornes de Recharge pour Véhicules Électriques (IRVE) - data.gouv.fr même si j’ai recrée un csv avec comme séparateur le « ; »
Autre point pour le moment le fichier de données csv est stockée sur le serveur web wordpress mutualisé chez ovh je ne sais pas si celui-ci est dimensionné pour un grand nombre de connexions simultanées.
Pour les personnes qui téléchargeront le projet, le bouton en haut de la carte désactive le suivi de le l’utilisateur pour pouvoir déplacer le carte sinon la carte se recentre sur la position GPS.
Les bornes apparaissent en rouge normalement on peut cliquer dessus pour afficher le détail cela ne fonctionne pas sur toutes je pense que cela est dû à l’erreur de maj dans la console.
D’animation de chargement est assez longue, car le fichier csv est volumineux
Toute la partie chargement du fichier se trouve dans le fichier accesDonnees la construction de la carte le contentView
Merci d’avance aux personnes qui voudront bien regarder le projet pour m’aider, car je sèche et je ne souhaite pas continuer dans l’erreur si je fais fausse route.
Je ne suis pas un développeur pro, mais juste un amateur qui apprend tout seul avec son lot d’erreurs dans la construction et du code. Le projet est en construction donc j’ai aussi plein d’erreurs sur la compatibilité entre les versions de swiftUI mais je me concentre pour le moment sur l’erreur d’affichage des points sur la carte.
code complet sous git pour exécution Xcode
Chargement des données
import SwiftUI
import UIKit
@MainActor // Gestion des files attentes processeur, pour les tâches asynchrones
class AccesDonnees:ObservableObject {
// tableau de donnée pour affichage points sur la carte
@Published var listeBornes:[BorneModele] = []
@Published var afficherCarte:Bool = false
@Published var chargementBorbes:Bool = false
@Published var ChargementExplication = "Chargement en cours"
// lecture du fichier csv
func lectureDonnees() async throws {
//Task.init() {
//let statusTache = Task { () -> String in
let statusTache = Task { () in
if let sourceFichier = URL(string: "https://titastus.com/wp-content/uploads/titastusdev/bornesrecharges/bornesrecharges.csv") {
for try await line in sourceFichier.lines {
let colonnes = line.split(separator: ";")
//let nom_amenageur = colonnes[0]
//let siren_amenageur = colonnes[1]
//let contact_amenageur = colonnes[2]
//let nom_operateur = colonnes[3]
//let contact_operateur = colonnes[4]
//let telephone_operateur = colonnes[5]
//let nom_enseigne = colonnes[6]
//let id_station_itinerance = colonnes[7]
//let id_station_local = colonnes[8]
let nom_station = nettoyageChaine(chaine: String(colonnes[9]))
//let implantation_station = colonnes[10]
let adresse_station = nettoyageChaine(chaine: String(colonnes[11]))
//let code_insee_commune = colonnes[12]
//let coordonneesXY = colonnes[13]
let nbre_pdc = nettoyageChaine(chaine: String(colonnes[14]))
//let id_pdc_itinerance = colonnes[15]
// let id_pdc_local = colonnes[16]
let puissance_nominale = nettoyageChaine(chaine: String(colonnes[17]))
let prise_type_ef = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[18])))
let prise_type_2 = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[19])))
let prise_type_combo_ccs = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[20])))
let prise_type_chademo = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[21])))
let prise_type_autre = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[22])))
let gratuit = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[23])))
let paiement_acte = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[24])))
let paiement_cb = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[25])))
let paiement_autre = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[26])))
//let horaires = colonnes[27]
let accessibilite_pmr = nettoyageChaine(chaine: String(colonnes[31]))
let condition_acces = nettoyageChaine(chaine: String(colonnes[28]))
let station_deux_roues = convertirStrVSBouleen(chaine: nettoyageChaine(chaine: String(colonnes[33])))
let raccordement = nettoyageChaine(chaine: String(colonnes[34]))
let num_pdl = nettoyageChaine(chaine: String(colonnes[37]))
//let date_mise_en_service = colonnes[32]
//let observations = colonnes[33]
//let date_maj = colonnes[34]
//let last_modified = colonnes[35]
//let datagouv_dataset_id = colonnes[36]
//let datagouv_resource_id = colonnes[37]
//let datagouv_organization_or_owner = colonnes[38]
let consolidated_longitude = convertirStrVSDouble(chaine: nettoyageChaine(chaine: String(colonnes[43])))
let consolidated_latitude = convertirStrVSDouble(chaine: nettoyageChaine(chaine: String(colonnes[44])))
//let consolidated_code_postal = colonnes[41]
//let consolidated_commune = colonnes[42]
//let consolidated_is_lon_lat_correct = colonnes[43]
//let consolidated_is_code_insee_verified = colonnes[44]
if nom_station != "\"nom_station(9)\"" {
let mesBornes = BorneModele(nom_station: nom_station, adresse_station: adresse_station,puissance_nominale: puissance_nominale, consolidated_longitude: consolidated_longitude, consolidated_latitude: consolidated_latitude, prise_type_ef: prise_type_ef, prise_type_2: prise_type_2, prise_type_combo_ccs: prise_type_combo_ccs, prise_type_chademo: prise_type_chademo,prise_type_autre:prise_type_autre,num_pdl:num_pdl,nbre_pdc:nbre_pdc, paiement_acte:paiement_acte, gratuit: gratuit, paiement_cb: paiement_cb,paiement_autre: paiement_autre, condition_acces: condition_acces, accessibilite_pmr:accessibilite_pmr,station_deux_roues:station_deux_roues, raccordement:raccordement)
//DispatchQueue.main.async {
self.listeBornes.append(mesBornes)
//self.chargementBorbes = true
//}
}
} // fin for
} // fin du fin
//return " \(ChargementExplication)"
}
let resultatTache = await statusTache.result
switch resultatTache {
case .success( _):
self.chargementBorbes = true
self.ChargementExplication = "Chargement terminé"
DispatchQueue.main.asyncAfter(deadline: .now() + 1.7) {
self.afficherCarte = true
}
case .failure(let error):
self.ChargementExplication = "Error: \(error.localizedDescription)"
self.chargementBorbes = false
}
//}
}
// suppression des guillemets
func nettoyageChaine(chaine:String) -> String {
var newchaine:String?
let caractereRecherche = "\""
if chaine.contains(caractereRecherche) {
newchaine = chaine.replacingOccurrences(of: caractereRecherche, with: "")
newchaine = newchaine!.trimmingCharacters(in: .whitespaces)
}
return newchaine!
}
//convertir chaine vers double
func convertirStrVSDouble(chaine:String) -> Double {
var resultatDouble:Double?
if let convertirDouble = Double(chaine) {
resultatDouble = convertirDouble
} else {
resultatDouble = 0.000
}
return resultatDouble!
}
//convertir chaine vers booleen
func convertirStrVSBouleen(chaine:String) -> Bool {
var resultatBooleen:Bool?
if let convertirBooleen = Bool(chaine) {
resultatBooleen = convertirBooleen
} else {
resultatBooleen = false
}
return resultatBooleen!
}
}
struct ContentView: View {
@StateObject var lireDonnees:AccesDonnees = AccesDonnees()
@StateObject var valeurAleatoire:Aleatoire = Aleatoire()
@StateObject var suivreUtilisateur:SuiviUtilisateurViewModel = SuiviUtilisateurViewModel(CLLocation(latitude: 0, longitude: 0))
@State private var montrerPopup:Bool = false
@State private var BorneSelectionnee:String = ""
@State private var montrerFenetre:Bool = false // pour suppression
@State private var borneSelectionAffichee:Bool = false
@State private var valeurPuissance:String = ""
//parametre écran
let milieu = UIScreen.main.bounds.height / 2
let largeurEcran = UIScreen.main.bounds.width
let hauteurEcran = UIScreen.main.bounds.height
// partie animation
// paramétre pour animation capsule
@State private var capsuleLargeur:CGFloat = 15
@State private var capsuleHauteur0:CGFloat = 100
@State private var capsuleHauteur1:CGFloat = 100
@State private var capsuleHauteur2:CGFloat = 100
@State private var couleurCapsule:[Color] = [Color("MonRouge"),.gray, Color("MonVert")]
@State private var timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
if (self.lireDonnees.afficherCarte) == true {
GeometryReader { geo in
VStack {
//ZStack {
// Map avec annotation
Map(coordinateRegion: $suivreUtilisateur.coordoneGeo, interactionModes: .all, showsUserLocation: true, userTrackingMode: .none, annotationItems: lireDonnees.listeBornes, annotationContent: { mesBornes in
MapAnnotation(coordinate: mesBornes.coordonneGeo(), anchorPoint: CGPoint(x: 0.5, y: 0.5)) {
// exemple avec onTapeGesture
Image(systemName: Ressources.image.borneRecharge.rawValue)
.foregroundColor(.red)
.opacity(montrerPopup ? 0 : 1)
.animation(Animation.linear(duration: 0.2))
.onTapGesture {
withAnimation {
BorneSelectionnee = mesBornes.nom_station
transfertInfoBorne(infoBorne: mesBornes)
self.montrerPopup = true
}
}
//////////////
if montrerPopup {
if mesBornes.nom_station == BorneSelectionnee {
ZStack(alignment: .top) {
DetailsBornesVuePopup(libelle: .constant(mesBornes.nom_station), adresse: .constant(mesBornes.adresse_station), latitudeSTR: .constant(String(mesBornes.consolidated_latitude)), longitudeSTR: .constant(String(mesBornes.consolidated_longitude)), montrerFenetreDetail:$montrerFenetre)
}
}
}
}
})
// .onReceive(lireDonnees.listeBornes) {listeBornes in
// self.tests = listeBornes
//}
//.ignoresSafeArea(.container, edges: [.top, .vertical])
.ignoresSafeArea(.all)
// ferme la vue popup de la carte si on
.onTapGesture {
withAnimation {
montrerPopup = false
borneSelectionAffichee = false
}
}// bouton localisation
.overlay(alignment:.topTrailing,content: {
Button {
suivreUtilisateur.suivreUtilisateur.toggle()
} label: {
Image(systemName: (suivreUtilisateur.suivreUtilisateur) ? Ressources.image.localiser.rawValue : Ressources.image.nonLocaliser.rawValue)
.padding()
.background(.black.opacity(0.60))
.font(.title2)
.clipShape(Circle())
.foregroundColor(suivreUtilisateur.suivreUtilisateur ? .green : .red)
}
})
.sheet(isPresented: $montrerPopup) {
ZStack() {
CaracteristiquesBornesVue()
.frame(height:UIScreen.main.bounds.width - 10)
.presentationDetents([.fraction(0.49)])
.overlay(alignment:.topTrailing,content: {
Button {
self.montrerPopup = false
} label: {
Image(systemName: Ressources.image.fermer.rawValue)
.padding(5)
.font(.title2)
.foregroundColor(.primary)
.clipShape(Circle())
.padding(5)
}
})
}
}
} // fin Vstack
}// fin du géo
} else {
// le if est déprecier
HStack(spacing:0){
// annimation de chargement
VueCapsule(largeur: $capsuleLargeur, hauteur: $capsuleHauteur0, color: $couleurCapsule[0])
VueCapsule(largeur: $capsuleLargeur, hauteur: $capsuleHauteur1, color: $couleurCapsule[1])
VueCapsule(largeur: $capsuleLargeur, hauteur: $capsuleHauteur2, color: $couleurCapsule[2])
HStack(spacing:0){
Text("\(lireDonnees.ChargementExplication)")
.font(.caption2)
.multilineTextAlignment(.leading)
.frame(width: 200,height: 100)
}
}
}
} // fin du if lire borne
//} // VStack
// execute ne tâche chargement des donnée
.task {
try? await lireDonnees.lectureDonnees()
}
// timer pour animation
.animation((Animation.linear))
.onReceive(timer) { time in
capsuleHauteur0 = valeurAleatoire.hauteurAleatoire()
capsuleHauteur1 = valeurAleatoire.hauteurAleatoire()
capsuleHauteur2 = valeurAleatoire.hauteurAleatoire()
}
} // fin du navigationView
}
message erreur
dans la console à l’affichage de la carte :
screen application
Merci à tous