可拖动的图表选区的不透明度会根据数据点数量而变化

编程语言 2026-07-10

我在拖动时想在一个 SwiftUI Chart 中添加一个矩形。下面的代码可以工作;然而,当我增加 @State private var numbers = (0 ..< 10) 中的点数时,绿色矩形的透明度会降低。 我猜是在彼此叠加绘制了很多矩形。

如何修改代码,使点的数量增加时透明度保持不变?

下面是我的代码(灵感来自:https://swiftwithmajid.com/2023/07/18/mastering-charts-in-swiftui-selection/

import Charts
import SwiftUI

struct ContentView: View {
    @State private var dragStart: Int? = nil
    @State private var dragRange: ClosedRange<Int>? = nil
    @State private var numbers = (0 ..< 10)
        .map { _ in Double.random(in: 0 ... 10) }

    var body: some View {
        Chart {
            ForEach(Array(zip(numbers, numbers.indices)), id: \.0) { number, index in
                if let dragRange {
                    RectangleMark(
                        xStart: .value("x", dragRange.lowerBound),
                        xEnd: .value("x", dragRange.upperBound),
                        yStart: .value("y", 1),
                        yEnd: .value("y", 9)
                    )
                    .foregroundStyle(.green.opacity(0.05))
                }
                LineMark(
                    x: .value("Index", index),
                    y: .value("Value", number)
                )
            }
        }
        .chartXSelection(range: $dragRange)
        .chartOverlay { chart in
            GeometryReader { geometry in
                Rectangle()
                    .fill(Color.clear)
                    .contentShape(Rectangle())
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                guard let plotFrame = chart.plotFrame else {
                                    return
                                }

                                let currentX = value.location.x - geometry[plotFrame].origin.x
                                guard currentX >= 0, currentX < chart.plotSize.width else {
                                    return
                                }

                                guard let index = chart.value(atX: currentX, as: Int.self) else {
                                    return
                                }

                                if dragStart == nil {
                                    dragRange = nil
                                    dragStart = index
                                }

                                guard let startIndex = dragStart else {
                                    return
                                }

                                if startIndex <= index {
                                    dragRange = startIndex ... index
                                } else {
                                    dragRange = index ... startIndex
                                }
                            }
                            .onEnded { _ in
                                dragStart = nil
                            }
                    )
            }
        }
    }
}

解决方案

你只需要把矩形标记移到 ForEach 的外面,这样矩形标记的数量就不会和点的数量一样多。

Chart {
    ForEach(Array(zip(numbers, numbers.indices)), id: \.0) { number, index in

        LineMark(
            x: .value("Index", index),
            y: .value("Value", number)
        )
    }
    if let dragRange {
        RectangleMark(
            xStart: .value("x", dragRange.lowerBound),
            xEnd: .value("x", dragRange.upperBound),
            yStart: .value("y", 1),
            yEnd: .value("y", 9)
        )
        .foregroundStyle(.green.opacity(0.05))
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章