Reputation: 11
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