Tenho um gráfico Swift simples onde estou tentando colocar uma RuleMark atrás de uma BarMark.
Quando o RuleMark é incluído antes do BarMark, as barras ficam irregulares e se movem conforme a seleção avança. Exemplo reproduzível abaixo.
import SwiftUI
import Charts
struct datStruct: Identifiable {
let id = UUID()
let label: String
let value: Int
}
struct ContentView: View {
let dat = [
datStruct(label: "A", value: 1),
datStruct(label: "B", value: 2),
datStruct(label: "C", value: 3)
]
@State var rawSelection: String?
var selection: datStruct? {
guard let rawSelection else {return nil}
return dat.first(where: { $0.label == rawSelection })
}
var body: some View {
Chart(){
if let selection {
RuleMark(x: .value("label", selection.label))
.foregroundStyle(.red)
}
ForEach(dat) {dat in
BarMark(x: .value("label", dat.label), y: .value("count", dat.value))
}
}
.chartXSelection(value: $rawSelection)
}
}
#Preview {
ContentView()
}
Quando a RuleMark é movida para depois da BarMark e um ZIndex negativo é aplicado, a regra é exibida atrás da barra, conforme desejado. Mas, quando adiciono animação à seleção, a regra aparece brevemente acima da barra e, em seguida, é animada para trás dela.
Como posso sempre mostrar o RuleMark atrás do BarMark com animação aplicada?
import SwiftUI
import Charts
struct datStruct: Identifiable {
let id = UUID()
let label: String
let value: Int
}
struct ContentView: View {
let dat = [
datStruct(label: "A", value: 1),
datStruct(label: "B", value: 2),
datStruct(label: "C", value: 3)
]
@State var rawSelection: String?
var selection: datStruct? {
guard let rawSelection else {return nil}
return dat.first(where: { $0.label == rawSelection })
}
var body: some View {
Chart(){
ForEach(dat) {dat in
BarMark(x: .value("label", dat.label), y: .value("count", dat.value))
}
if let selection {
RuleMark(x: .value("label", selection.label))
.foregroundStyle(.red)
.zIndex(-1)
}
}
.chartXSelection(value: $rawSelection.animation())
}
}
#Preview {
ContentView()
}
As barras "se movem conforme a seleção se move" estão relacionadas à forma como os Gráficos ordenam automaticamente os valores discretos do eixo X. O comportamento padrão é apenas "ordená-los na ordem em que aparecem".
Suponha que você esteja selecionando "A". O primeiro valor X que aparece no gráfico é "A", então o eixo X se move para "A", "B", "C". Então, quando você move o dedo para "B", o valor
RuleMark
agora está em "B". Isso altera a ordem dos valores X para "B", "A", "C". Isso faz com que as barras se movam para novas posições. Como resultado, seu dedo está novamente em "A", e assim as barras se reorganizam para "A", "B", "C" novamente, e o ciclo continua.Você pode adicionar um
chartXScale
modificador aoChart
, para especificar exatamente como os valores x devem ser ordenados, a fim de impedir que sejam ordenados automaticamente.Por exemplo, aqui eu os ordenei na mesma ordem em que aparecem em
dat
.Como alternativa, use a
chartOverlay
em vez deRuleMark
. Na sobreposição, insira aRectangle
de largura 1.