代码之家  ›  专栏  ›  技术社区  ›  Asif Raza

在SwiftUI的Swift图表中点击条形图和X轴标签时无法获得操作

  •  0
  • Asif Raza  · 技术社区  · 2 年前

    1. 点击带有标签文本的X轴红色突出显示矩形区域进行操作

    我使用了轻击手势,但在轻击点2区域不起作用。

    import SwiftUI
    import Charts
    
    struct Item: Identifiable {
        let id = UUID()
        let month: String
        let revenue: Double
        let visits: Double
    }
    
    struct TapChart: View {
    
        let items: [Item] = [
            Item(month: "Jan", revenue: 100, visits: 2),
            Item(month: "Feb", revenue: 200, visits: 1),
            Item(month: "Mar", revenue: 150, visits: 4),
            Item(month: "Apr", revenue: 130, visits: 0),
            Item(month: "May", revenue: 300, visits: 3),
            Item(month: "Jun", revenue: 50, visits: 2)
        ]
    
        var myItems = [Item]()
    
        var body: some View {
            Chart {
                ForEach(items) { items in
                    BarMark(
                        x: .value("Month", items.month),
                        y: .value("Revenue", items.revenue)
                    )
                    .foregroundStyle(Color.green.gradient)
                }
            }
            .chartForegroundStyleScale([
                "SEO Revenue" : Color(.green),
                "Visits": Color(.purple)
            ])
            .chartLegend(position: .top, alignment: .bottomTrailing)
            .chartXAxis {
                AxisMarks { axis in
                    AxisValueLabel(centered: true) {
                        Text("\(items[axis.index].month)")
                            .font(.system(size: 12, weight: .bold))
                            .padding(.horizontal, 12)
                            .padding(.vertical, 8)
                            .background(Color.red.opacity(0.3))
                            .cornerRadius(4)
                            .onTapGesture {
                                print("\(items[axis.index].month)")
                            }
                    }
                }
            }
            .chartYAxis(.visible)
            .padding()
            .cornerRadius(15)
            .frame(height: 300)
        }
    }
    

    enter image description here

    1 回复  |  直到 1 年前
        1
  •  2
  •   Sweeper    2 年前

    我认为你必须用 chartOverlay

    .chartXAxis(.hidden)
    .chartOverlay { proxy in
        if let y = proxy.position(forY: 0.0) {
            ForEach(items) { item in
                if let x = proxy.position(forX: item.month) {
                    Text("\(item.month)")
                        .font(.system(size: 12, weight: .bold))
                        .padding(.horizontal, 12)
                        .padding(.vertical, 8)
                        .background(Color.red.opacity(0.3))
                        .cornerRadius(4)
                        .position(x: x, y: y + 40) // +40 to offset the label downwards a bit
                        .onTapGesture {
                            print("Tapped on label \(item.month)")
                        }
                }
            }
        }
    }
    

    为了防止标签被绘图区域剪切,您还应该添加一些底部填充:

    .chartPlotStyle { plot in
        plot.padding(.bottom, 30)
    }
    

    至于检测酒吧的水龙头,你可以做:

    .chartGesture{ proxy in
        SpatialTapGesture().onEnded { value in
            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
    
            // assuming the bars occupy half of the available width
            // i.e. BarMark(x: ..., y: ..., width: .ratio(0.5))
            let barRatio = 0.5
            let barRange = (xRange.lowerBound + rangeWidth * barRatio / 2)...(xRange.upperBound - rangeWidth * barRatio / 2)
            
            guard barRange.contains(value.location.x),
                  let item = items.first(where: { $0.month == x }),
                  let y = proxy.position(forY: item.revenue),
                  let maxY = proxy.position(forY: 0.0),
                  value.location.y >= y && value.location.y <= maxY else {
                return
            }
            print("Tapped on bar \(x)")
            
        }
    }