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

问题描述 投票:0回答:1

我可以使用 Swift Charts 框架绘制条形图。 现在我想在下面的条形图中执行 2 个操作。

  1. 点击绿色栏即可执行操作
  2. 点击 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

swiftui charts
1个回答
0
投票

我认为你必须用

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)")
        
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.