0

i'm very new to ios development, i'm fetching data from firebase and processing it into two arrays full of tuples currently(Will eventually be 3). the x axis is the first value in the tuple and so on, each tuple should be a point of the line and each array is one line.

Chart {
            ForEach(listOfEv.indices, id: \.self) { index in
                LineMark(
                    x: .value("Time", Float(listOfEv[index].time)),
                    y: .value("EV", Float(listOfEv[index].ev))
                    
                ).foregroundStyle(
                    .linearGradient(
                        // You can have more colours here depends on your data.
                        colors: [.blue, .red],
                        startPoint: .bottom,
                        endPoint: .top)
                )
                
                PointMark(
                    x: .value("Time", Float(listOfEv[index].time)),
                    y: .value("EV", Float(listOfEv[index].ev))
                )
                
            }
            
            ForEach(listOfAv.indices, id: \.self) { index1 in
                LineMark(
                    x: .value("Time", Float(listOfAv[index1].time)),
                    y: .value("EV", Float(listOfAv[index1].ev))
                ).foregroundStyle(.green)
                PointMark(
                    x: .value("Time", Float(listOfAv[index1].time)),
                    y: .value("EV", Float(listOfAv[index1].ev))
                )
            }
            
            
        }.foregroundStyle(.green)
            .frame(width: .infinity,height: 300)
            .onAppear(perform: {
                firebaseData.BetTracker(username: "rozzaroo", completion: { EvData, AvData, SpData in
                    
                    listOfAv = AvData
                    listOfSp = SpData
                    listOfEv = EvData
                    
                })
            })
     

This is the chart i'm using to display the data

unc BetTracker(username: String, completion: @escaping ([(Int, Int)], [(Int, Int)], [(Int, Int)]) -> Void) {
        
        let ref = Database.database().reference().child("users").child(username.lowercased()).child("bets")
        
        ref.observeSingleEvent(of: .value) { snapshot, error in
            if let error = error {
                print("Error fetching odds list: \(error)")
                return
            }
            
            if let data = snapshot.value as? [String: Any] {
                let keysCount = data.keys.count
                var processedKeys = 0
                var EvCounter = 0
                var AvCounter = 0
                var time = 0
                
                let sortedKeys = data.keys.sorted {
                    guard let first = data[$0] as? [Any], let second = data[$1] as? [Any],
                          let firstInt = first[1] as? Int, let secondInt = second[1] as? Int else { return false }
                    return firstInt < secondInt
                }
                
                for key in sortedKeys {
                    if let usersBetTrack = data[key] as? [Any] {
                        let refMaster = Database.database().reference().child("Master").child(key)
                        
                        refMaster.observeSingleEvent(of: .value) { caughtBet, error in
                            processedKeys += 1
                            
                            if let error = error {
                                print("Error fetching data: \(error)")
                                return
                            }
                            
                            if caughtBet.exists() {
                                if let array = caughtBet.value as? [AnyObject], let evMaster = array.first as? String,
                                   let userBetAmtTrack = usersBetTrack[2] as? String,
                                   
                                    let betTimePlace1 = usersBetTrack[1] as? Int {
                                    if let userBookOdd = usersBetTrack[3] as? String {
                                        var userBookOdds = Float(userBookOdd)
                                        
                                        
                                        var updatedEvMaster = Float(evMaster.dropLast())! / 100
                                        var dollarAmountBet = Float(userBetAmtTrack.dropFirst())!
                                        dollarAmountBet *= updatedEvMaster
                                        let currentTimeZone = TimeZone.current
                                        let gmtOffsetInSeconds = currentTimeZone.secondsFromGMT()
                                        var betTimePlace2 = betTimePlace1 + gmtOffsetInSeconds
                                        
                                        EvCounter = Int(dollarAmountBet) + EvCounter
                                        EvCounter = Int(EvCounter)
                                        
                                        time = 1 + time
                                        
                                        if let gameResult = array[12] as? String {
                                            
                                            switch (gameResult) {
                                            case "win":
                                                var usersStake = Float(userBetAmtTrack.dropFirst())
                                                usersStake = (userBookOdds! - 1) * usersStake!
                                                AvCounter = AvCounter + Int(Float(usersStake!))
                                                
                                            case "lose":
                                                AvCounter = AvCounter - Int(Float(userBetAmtTrack.dropFirst())!)
                                            case "pending":
                                                AvCounter = AvCounter + 0
                                            default:
                                                AvCounter = AvCounter + 0
                                            }
                                        }
                                        
                                        time = time + 1
                                        self.AvList.append((time: Int(time), ev: AvCounter))
                                        self.EvList.append((time: Int(time), ev: EvCounter))
                                        
                                        // Check if all keys have been processed, then call the completion handler
                                        if processedKeys == keysCount {
                                            
                                            completion(self.EvList, self.AvList, self.SpList)
                                        }
                                    }
                                }
                            } else {
                                print("Snapshot does not exist")
                            }
                        }
                    }
                }
            }
        }
    }

all my data is correct and sorted with the lowest x axis value coming first in the array.

currently this is what the line looks like, i want it to be 2 seperate lines. i'm very stuck and unsure how to make them not connected

enter image description here

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52

1 Answers1

0

The modifier you are looking for is .foregroundStyle(by: ) to be applied on both ForEach with different values.

It also gives you a legend under the chart, which can be hidden with .chartLegend(.hidden).

enter image description here

Here is the code:

struct ContentView: View {
    
    // test data
    let listOfEv = [1400, 1700, 1800, 1800]
    let listOfAv = [0,0,0,0]
    
    var body: some View {
        
        Chart {
            ForEach(listOfEv.indices, id: \.self) { index in
                LineMark(
                    x: .value("Time", Float( index )),
                    y: .value("EV", Float(listOfEv[index]))
                )
                    .foregroundStyle(
                        .linearGradient(
                            colors: [.blue, .red],
                            startPoint: .bottom,
                            endPoint: .top)
                    )
                
                PointMark(
                    x: .value("Time", Float(index)),
                    y: .value("EV", Float(listOfEv[index]))
                )
                
            }
            .foregroundStyle(by: .value("Type", "EV")) // Here

            ForEach(listOfAv.indices, id: \.self) { index1 in
                LineMark(
                    x: .value("Time", Float( index1 )),
                    y: .value("EV", Float(listOfAv[index1]))
                ).foregroundStyle(.green)
                
                PointMark(
                    x: .value("Time", Float( index1 )),
                    y: .value("EV", Float(listOfAv[index1]))
                )
            }
            .foregroundStyle(by: .value("Type", "AV")) // Here
            
        }
        .chartLegend(.hidden) // optional
        .frame(height: 300)
        .padding()
    }
}
ChrisR
  • 9,523
  • 1
  • 8
  • 26