最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - Preserving original chart horizontal scroll while adding a new DragGesture - Stack Overflow

programmeradmin1浏览0评论

I am trying to add a chart overlay, and a custom DragGesture to not reset my variable called rawSelectedDate after stopping dragging.

The implementation is fine, but it does not allow the original horizontal scrolling of my chart, which I also need to preserve.

I tried adding simultaneousGesture(), but it didn't solve the problem. I also tried increasing the minimumDistance parameter in DragGesture, but that didn't work either.

The code:

struct ScoreChartModel: Identifiable {
    let id = UUID()
    var score: Int
    var date: Date
}

struct SleepScoreChart: View {
    @State var chartDisplayData: [ScoreChartModel]
    @Binding var rawSelectedDate: Date?
    
    var body: some View {
        Chart {
            ForEach(chartDisplayData) { chartData in
                PointMark(
                    x: .value("sleep date", chartData.date, unit: .day),
                    y: .value("sleep score", chartData.score)
                )
                .interpolationMethod(.catmullRom)
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .day)) { _ in
                AxisTick()
                AxisGridLine()
                AxisValueLabel(format: .dateTime.weekday(.abbreviated))
            }
        }
        .chartYScale(domain: 0...120)
        .chartYAxis(.hidden)
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 7)
        .chartXSelection(value: $rawSelectedDate)
        .chartScrollPosition(initialX: Date())
        .chartOverlay { proxy in
            GeometryReader { geometry in
                Rectangle().fill(.clear).contentShape(Rectangle())
                    .simultaneousGesture(
                        DragGesture(minimumDistance: 0)
                            .onChanged { value in
                                if let plotFrame = proxy.plotFrame {
                                    let x = value.location.x - geometry[plotFrame].origin.x
                                    guard let date = proxy.value(atX: x, as: Date.self) else { return }
                                    let closestDataPoint = chartDisplayData.min { first, second in
                                        abs(first.date.timeIntervalSince(date)) < abs(second.date.timeIntervalSince(date))
                                    }
                                    if let closestDate = closestDataPoint?.date {
                                        rawSelectedDate = closestDate
                                    }
                                }
                            }
                    )
                    
            }
        }
    }
}

I am trying to add a chart overlay, and a custom DragGesture to not reset my variable called rawSelectedDate after stopping dragging.

The implementation is fine, but it does not allow the original horizontal scrolling of my chart, which I also need to preserve.

I tried adding simultaneousGesture(), but it didn't solve the problem. I also tried increasing the minimumDistance parameter in DragGesture, but that didn't work either.

The code:

struct ScoreChartModel: Identifiable {
    let id = UUID()
    var score: Int
    var date: Date
}

struct SleepScoreChart: View {
    @State var chartDisplayData: [ScoreChartModel]
    @Binding var rawSelectedDate: Date?
    
    var body: some View {
        Chart {
            ForEach(chartDisplayData) { chartData in
                PointMark(
                    x: .value("sleep date", chartData.date, unit: .day),
                    y: .value("sleep score", chartData.score)
                )
                .interpolationMethod(.catmullRom)
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .day)) { _ in
                AxisTick()
                AxisGridLine()
                AxisValueLabel(format: .dateTime.weekday(.abbreviated))
            }
        }
        .chartYScale(domain: 0...120)
        .chartYAxis(.hidden)
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 7)
        .chartXSelection(value: $rawSelectedDate)
        .chartScrollPosition(initialX: Date())
        .chartOverlay { proxy in
            GeometryReader { geometry in
                Rectangle().fill(.clear).contentShape(Rectangle())
                    .simultaneousGesture(
                        DragGesture(minimumDistance: 0)
                            .onChanged { value in
                                if let plotFrame = proxy.plotFrame {
                                    let x = value.location.x - geometry[plotFrame].origin.x
                                    guard let date = proxy.value(atX: x, as: Date.self) else { return }
                                    let closestDataPoint = chartDisplayData.min { first, second in
                                        abs(first.date.timeIntervalSince(date)) < abs(second.date.timeIntervalSince(date))
                                    }
                                    if let closestDate = closestDataPoint?.date {
                                        rawSelectedDate = closestDate
                                    }
                                }
                            }
                    )
                    
            }
        }
    }
}
Share Improve this question edited Mar 28 at 2:40 President James K. Polk 42k29 gold badges109 silver badges145 bronze badges asked Mar 28 at 0:36 Michał TomysMichał Tomys 112 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

In your .chartOverlay(...) remove the .contentShape(Rectangle())

Sometimes you just have to take a break ... and come back with a fresh mind

The solution is obvious:

struct SleepScoreChart: View {
    @State var chartDisplayData: [ScoreChartModel]
    @Binding var rawSelectedDate: Date?
    @Binding var selectedDate: Date?
    
    var body: some View {
        Chart {
            ForEach(chartDisplayData) { chartData in
                PointMark(
                    x: .value("sleep date", chartData.date, unit: .day),
                    y: .value("sleep score", chartData.score)
                )
                .interpolationMethod(.catmullRom)
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .day)) { _ in
                AxisTick()
                AxisGridLine()
                AxisValueLabel(format: .dateTime.weekday(.abbreviated))
            }
        }
        .chartYScale(domain: 0...120)
        .chartYAxis(.hidden)
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 7)
        .chartXSelection(value: $rawSelectedDate)
        .chartScrollPosition(initialX: Date())
        .onChange(of: rawSelectedDate) {
            if let date = rawSelectedDate {
                selectedDate = date
            }
        }
    }
}

Set selectedDate only when rawSelectedDate is not nil, problem solved

发布评论

评论列表(0)

  1. 暂无评论