I have a macOS App written in Swift and I need to visualise some temperatures sensors like a Charts. The project doesn't use SwiftUI, but only for this view.
I've created this View and works fine. Now I need to enable users zoom over the chart (zooming only x-axis) by pinch with fingers on trackpad and by using +/- buttons in page. And second, I need to show a popup with single point information when the user pass mouse over the charts.
I've tried many way, but I'm really new in SwiftUI (and to be honest I don't like it) and I can't find the right way to achieve this two functionalities.
This is the code I have written until now (with a lot of effort). Can you help me ? Thanks.
struct LineChartSerie: Identifiable {
let id = UUID()
let label: String
let points: [LineChartPoint]
let color: Color
}
struct LineChartPoint: Identifiable {
let id = UUID()
let x: Int
let y: Double
}
struct LineChart: View {
private var series: [LineChartSerie] = []
init(_ series: [LineChartSerie]) {
changeSeries(series)
}
mutating func changeSeries(_ series: [LineChartSerie]) {
self.series = series
}
var body: some View {
Chart {
ForEach(series) { serie in
ForEach(serie.points) { point in
LineMark(x: .value("Time", point.x),
y: .value("Temp", point.y)
)
.foregroundStyle(serie.color)
.position(by: .value("Label", serie.label))
.foregroundStyle(by: .value("Label", serie.label))
.interpolationMethod(Charts.InterpolationMethod.linear)
.symbol {
Circle()
.fill(serie.color)
.frame(width: 0)
}
}
}
}
.chartYAxis {
AxisMarks(position: .leading, values: .automatic(desiredCount: 30)) { value in
AxisGridLine()
AxisValueLabel {
if let intValue = value.as(Int.self) {
Text("\(intValue) C°")
}
}
}
}
.chartYAxisLabel("Temperature")
.chartXAxis {
AxisMarks(values: .automatic(desiredCount: 25)) { value in
AxisGridLine()
AxisTick()
AxisValueLabel {
if let intValue = value.as(Int.self) {
Text(getTimeFromSeconds(intValue))
}
}
}
}
.chartXScale(domain: [0,86_400])
.chartXAxisLabel("Time in the day")
.chartForegroundStyleScale(range: graphColors(for: series))
.chartLegend (position: .bottom, alignment: .leading)
.clipped()
}
}