У меня есть следующая диаграмма SwiftUI. Я пытаюсь получить значение y
в зависимости от того, куда перетаскивает пользователь, чтобы я мог расположить Capsule
в правильном положении на диаграмме. К сожалению, я не могу получить правильное положение y, но вместо этого этот код показывает мне, куда пользователь перетаскивает график, но не удерживает индикатор на линии графика.
Может ли кто-нибудь подсказать, где я ошибаюсь. Вот мой код. И если что-то неясно, дайте мне знать, и я смогу предоставить более подробную информацию.
Я думала этоvalue(atY:as:)
может помочь, но тоже не сработало.
struct ContentView: View {
@State private var numbers = (0...10).map { _ in
Int.random(in: 0...10)
}
@State private var indicatorIndex = 0
@State private var indicatorNumber = 0.0
@State private var indicatorLocation = CGPointMake(0, 0)
var body: some View {
Chart {
ForEach(Array(zip(numbers, numbers.indices)), id: \.0) { number, index in
LineMark(
x: .value("Index", index),
y: .value("Value", number)
)
}
}
.chartOverlay { proxy in
GeometryReader { geometry in
Capsule()
.strokeBorder(Color.red, lineWidth: 1.0)
.background(Color.blue)
.frame(width: 80, height: 20)
.overlay {
HStack {
Text("\(indicatorIndex)")
.font(.system(size: 12.0))
.fontWeight(.semibold)
.foregroundStyle(.red)
Text("\(indicatorNumber)")
.font(.system(size: 12.0))
.fontWeight(.semibold)
.foregroundStyle(.white)
}
}
.offset(x: indicatorLocation.x, y: indicatorLocation.y)
Rectangle().fill(.clear).contentShape(Rectangle())
.gesture(
DragGesture()
.onChanged { value in
// Convert the gesture location to the coordinate space of the plot area.
let origin = geometry[proxy.plotAreaFrame].origin
let location = CGPoint(
x: value.location.x - origin.x,
y: value.location.y - origin.y
)
// Get the x (date) and y (price) value from the location.
let (index, number) = proxy.value(at: location, as: (Int, Double).self) ?? (0, 0)
let test = proxy.value(atY: origin.x, as: Double.self)
indicatorIndex = index
indicatorNumber = number
indicatorLocation = CGPoint(x: value.location.x, y: test ?? 0.0)
print("Location: \(number) - number, \(index) - index , \(test) test")
}
)
}
}
}
}
Вот несколько скриншотов, показывающих, где находится капсула и где я хочу ее разместить.
ChartProxy
не имеет абсолютно никакого представления о данных, отображенных на диаграмме. Вы должны найти координаты y линии, используя свой источник данных, то есть массив numbers
.
// get the x value of the tapped location
let x = proxy.value(atX: location.x, as: Double.self) ?? 0
// get which two plotted points is the tapped location between
let (lowerIndex, upperIndex) = (x.rounded(.down), x.rounded(.up))
// get the y values for the above x values
// these indices might be out of range - you should decide what to do in that case
let (lowerNumber, upperNumber) = (numbers[Int(lowerIndex)], numbers[Int(upperIndex)])
// now convert these to y *coordinates*
let (lowerY, upperY) = (proxy.position(forY: lowerNumber) ?? 0, proxy.position(forY: upperNumber) ?? 0)
// finally, linear interpolation
func lerp(_ a: Double, _ b: Double, _ x: Double) -> Double {
a + (b - a) * x
}
let y = lerp(lowerY, upperY, x - lowerIndex)
indicatorLocation = CGPoint(x: value.location.x, y: y)
В данном случае это относительно просто, поскольку вы строите график каждого индекса массива, а интерполяция является линейной. В общем, это может оказаться очень сложным. В любом случае общая идея та же (см. комментарии к коду).