Mostafa Sadek
Mostafa Sadek

Reputation: 11

Tapping, ChartGesture, and onTapGesture is not always working on Bar Chart

The bar chart works fine and so does the animation and all is well. The only problem I'm facing now is that the bars are not always clickable, sometimes it works and sometimes it doesn't. I have been facing this problem with buttons in other views in the project, and when I used .simultaneousGesture(TapGesture().onEnded { _ in instead of "action" in the buttons it works like a charm. I have tried to used the same for this but I'm faced with syntax errors and it's not accepting it. Any ideas how I can make this bar chart consistently clickable? Thanks a lot in advance

Comment:

I have also tried the following, but the problem still persists:-

.chartGesture{ proxy in
                    SpatialTapGesture().onEnded { value in
                        print("spatial tapped")
                        guard let x = proxy.value(atX: value.location.x, as: String.self),
                              let xRange = proxy.positionRange(forX: x) else { return }
                        let rangeWidth = xRange.upperBound - xRange.lowerBound
                        let barRatio = 0.5
                        let barRange = (xRange.lowerBound + rangeWidth * barRatio / 2)...(xRange.upperBound - rangeWidth * barRatio / 2)

                        guard barRange.contains(value.location.x),
                              let item = variables.rigsTrippingKPIs.first(where: { $0.rig == x }),
                              let y = proxy.position(forY: item.flatTime),
                              let maxY = proxy.position(forY: minYaxis),
                              let minY = proxy.position(forY: maxYaxis),
                              (value.location.y >= minY && value.location.y <= maxY) /*||*/
                                /*(value.location.y <= y && value.location.y >= minY)*/ else {
                            return
                        }
                        print("Tapped on bar \(x)")

                        DispatchQueue.global(qos: .background).async {
                            getYTDKPIs(selectedDate: variables.selectedDate, selectedRig: x, completion: { response in
                                if response == "Success" {
                                    DispatchQueue.main.async {
                                        print("Successfully retrieved YTD KPIs for Rig")

                                        variables.rigsYTDTrippingKPIs = TempVariables.rigsYTDTrippingKPIs
                                        variables.rigsYTDCasingKPIs = TempVariables.rigsYTDCasingKPIs
                                        variables.rigsYTDCompletionKPIs = TempVariables.rigsYTDCompletionKPIs

                                        variables.selectedRig = x

                                        withAnimation {
                                            variables.showYTDChart = true
                                        }
                                    }
                                }
                            })
                        }
                    }
                }
import SwiftUI
import Charts

struct RigsTrippingChartiPadOS: View {
    @ObservedObject var variables: Variables
    @State private var showingPopover = false
    
    var body: some View {
        
        VStack {
            
            Text("Rigs Tripping Flat Time")
                .font(.system(size: 14))
                .frame(alignment: .center)
                .padding(.top, 10)
            
            GeometryReader
            {
                geometry in
                VStack (alignment: .leading, spacing: 0)
                {
                    
                    let tempMaxYaxis = (variables.rigsTrippingKPIs.map { $0.flatTime }.max() ?? 0)
                    let tempMinYaxis = (variables.rigsTrippingKPIs.map { $0.flatTime }.min() ?? 0)
                    let minYaxis = (tempMinYaxis > 0 ? 0 : tempMinYaxis)
                    let maxYaxis = (tempMaxYaxis < 0 || minYaxis  == tempMaxYaxis ? 0 : tempMaxYaxis)
                    let count = variables.rigsTrippingKPIs.count
                    
                    Chart{
                        
                        ForEach(variables.rigsTrippingKPIs) { item in
                            
                            BarMark(
                                x: .value("Rig", item.rig),
                                y: .value("Flat Time", item.animate ? item.flatTime : 0)
                            )
                            .annotation(position: .automatic) {
                                Text("\(String(format: "%.0f", (item.flatTime * 100)))%")
                                    .foregroundColor(Color.white)
                                    .opacity(0.6)
                                    .font(.system(size: 8))
                            }
                            .foregroundStyle(.linearGradient(
                                colors: [barColors1(value: item.rig, selectedCompany: variables.selectedCompany, data: item.flatTime), barColors1(value: item.rig, selectedCompany: variables.selectedCompany, data: item.flatTime)],
                                startPoint: .leading,
                                endPoint: .trailing)
                            )
                            .cornerRadius(10)
                        }
                    }
                    .chartOverlay { proxy in
                        GeometryReader { geometry in
                            ZStack(alignment: .top) {
                                Rectangle().fill(.clear).contentShape(Rectangle())
                                
                                    .onTapGesture { location in
                                        updateSelectedRig(at: location, proxy: proxy, geometry: geometry, completion: { response in
                                            print("tapped")
                                            print(response)
                                            
                                            variables.allowUserInteraction = false
                                            
                                            DispatchQueue.global(qos: .background).async {
                                                
                                                getYTDKPIs(selectedDate: variables.selectedDate, selectedRig: response, completion: { funcResponse in
                                                    if funcResponse == "Success" {
                                                        DispatchQueue.main.async {
                                                            print("Successfully retrieved YTD KPIs for Rig")
                                                            
                                                            variables.rigsYTDTrippingKPIs = TempVariables.rigsYTDTrippingKPIs
                                                            variables.rigsYTDCasingKPIs = TempVariables.rigsYTDCasingKPIs
                                                            variables.rigsYTDCompletionKPIs = TempVariables.rigsYTDCompletionKPIs
                                                            
                                                            variables.selectedRig = response
                                                            variables.allowUserInteraction = true
                                                            
                                                            withAnimation {
                                                                variables.showYTDChart = true
                                                                
                                                            }
                                                        }
                                                    }
                                                    else {
                                                        variables.allowUserInteraction = true
                                                    }
                                                    
                                                })
                                            }
                                        })
                                    }
                            }
                        }
                    }
                    .allowsHitTesting(variables.allowUserInteraction)
                    .onAppear {
                        for (index,_) in variables.rigsTrippingKPIs.enumerated() {
                            DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.05){
                                withAnimation(.interactiveSpring(response: 0.8, dampingFraction: 0.8, blendDuration: 0.8)){
                                    variables.rigsTrippingKPIs[index].animate = true
                                }
                            }
                            variables.showYTDChart = false
                        }
                    }
                    .onChange(of: variables.loadKPIGraphs, perform: {value in
                        for (index,_) in variables.rigsTrippingKPIs.enumerated() {
                            DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.05){
                                withAnimation(.interactiveSpring(response: 0.8, dampingFraction: 0.8, blendDuration: 0.8)){
                                    variables.rigsTrippingKPIs[index].animate = true
                                }
                            }
                            variables.showYTDChart = false
                        }
                    })
                    .padding(.top, 30)
                    .padding(.bottom, 50)
                    .padding(.leading, 30)
                    .padding(.trailing, 30)
                    .chartYScale(domain: minYaxis...maxYaxis)
                    .chartXAxis{
                        let rigs = variables.rigsTrippingKPIs.map{$0.rig}
                        AxisMarks (preset: .automatic, position: .bottom)
                        { data in
                            let value = rigs[data.index]
                            AxisValueLabel(centered: true, collisionResolution: .truncate,
                                           orientation: AxisValueLabelOrientation.horizontal){
                                Text(value)
                                    .frame(width: (geometry.size.width / IntToCGFloat(v: count)!!), alignment: .center)
                                    .multilineTextAlignment(.center)
                            }
                                           .font(.system(size: 8))
                                           .foregroundStyle(Color.white.opacity(0.6))
                        }
                    }
                    .padding(.leading, 3)
                    .chartYAxis (.hidden)
                }
            }
            .background(Color.black.opacity(0.7))
            .cornerRadius(15)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    
    func IntToCGFloat(v: Int??) -> CGFloat?? {
        v.flatMap { $0.flatMap { CGFloat($0) } }
    }
    
    func updateSelectedRig(at location: CGPoint, proxy: ChartProxy, geometry: GeometryProxy, completion: @escaping(_ Result: String) -> ()) {
        let xPosition = location.x - geometry[proxy.plotAreaFrame].origin.x
        guard let rig: String = proxy.value(atX: xPosition) else {
            return
        }
        completion(rig)
    }
    
    private func getValue(for date: String) -> (String, Double) {
        let value = variables.rigsYTDTrippingKPIs.first{$0.reportDate == date}
        return (String(date), Double(value!.flatTime))
    }
}

Upvotes: 0

Views: 129

Answers (0)

Related Questions