iOS 图表折线图未在 SwiftUI 中点击/拖动时选择值 - 最新版本 4.0.2

发布于 2025-01-16 22:47:08 字数 5517 浏览 2 评论 0原文

您预计会发生什么?

当我点击或拖动图表时,我希望它一一选择所有条目。

相反发生了什么?

但是,它仅选择最右侧的值。这真的很奇怪。

图表环境

最新版本:4.0.2
XCode 13.2.1
斯威夫特 5.5.2
仅限 iOS
macOS 12.1

运行 XCode演示项目的

[代码改编自 Stewart Lynch 的本教程:https://www.youtube.com/watch?v=csd7pyfEXgw 他制作了一个条形图,我将其转换为折线图并添加了一些额外的位,例如渐变]

LineChartView:

import SwiftUI
import Charts

struct TimeTakenLineChartView: UIViewRepresentable { \
        
    let entries: [ChartDataEntry]
    let lineChart = LineChartView()
    
    @Binding var selectedYear: Int
    @Binding var selectedItem: String
    
    func makeUIView(context: Context) -> LineChartView {
        lineChart.delegate = context.coordinator
        lineChart.animate(xAxisDuration: 2)
        lineChart.backgroundColor = UIColor(Color.gray)
        return lineChart
    }
    
    func updateUIView(_ uiView: LineChartView, context: Context) {
        let dataSet = LineChartDataSet(entries: entries)
        
        uiView.noDataText = "No Data"
        uiView.data = LineChartData(dataSet: dataSet)
        uiView.rightAxis.enabled = false
        

        uiView.setScaleEnabled(false)
        uiView.notifyDataSetChanged()
        
        formatDataSet(dataSet: dataSet)
        formatLeftAxis(leftAxis: uiView.leftAxis)
        formatXAxis(xAxis: uiView.xAxis)
        formatLegend(legend: uiView.legend)
                
        // data set updates
        dataSet.lineWidth = 3
        dataSet.label = "Seconds Taken"
        dataSet.drawValuesEnabled = false
        dataSet.drawCirclesEnabled = false
        dataSet.mode = .cubicBezier // add this line
        dataSet.drawHorizontalHighlightIndicatorEnabled = false
        dataSet.highlightColor = .white
        
        // Gradient
        let gradientColors = [UIColor(Color.blue).cgColor, UIColor(Color.green).cgColor] as CFArray // Colors of the gradient
        let colorLocations:[CGFloat] = [1.0, 1.0] // Positioning of the gradient
        let gradient = CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations) // Gradient Object
        
        dataSet.isDrawLineWithGradientEnabled = true
        dataSet.gradientPositions = colorLocations
        dataSet.fill =  LinearGradientFill(gradient: gradient!)
        dataSet.drawFilledEnabled = true // Draw the Gradient
    }
    
    class Coordinator: NSObject, ChartViewDelegate {
        let parent:TimeTakenLineChartView
        init(parent: TimeTakenLineChartView) {
            self.parent = parent
        }
        func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
            let quantity = Int(entry.y)
            parent.selectedItem = "\(quantity) seconds"
        }
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    
    func formatDataSet(dataSet: LineChartDataSet) {
        dataSet.colors = [.blue]
        dataSet.valueColors = [.blue]
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        dataSet.valueFormatter = DefaultValueFormatter(formatter: formatter)
    }
    
    func formatLeftAxis(leftAxis: YAxis) {
        leftAxis.labelTextColor = .white
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        leftAxis.valueFormatter = DefaultAxisValueFormatter(formatter: formatter)
        leftAxis.axisMinimum = 0
        leftAxis.drawGridLinesEnabled = false
        leftAxis.labelFont = .boldSystemFont(ofSize: 15)
        leftAxis.drawAxisLineEnabled = false
        leftAxis.drawLabelsEnabled = false
    }
    
    func formatXAxis(xAxis: XAxis) {
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        xAxis.valueFormatter = DefaultAxisValueFormatter(formatter: formatter)
        xAxis.labelPosition = .bottom
        xAxis.labelTextColor = .white
        xAxis.labelFont = .boldSystemFont(ofSize: 15)
        xAxis.drawGridLinesEnabled = false
        xAxis.drawAxisLineEnabled = false
    }
    
    func formatLegend(legend: Legend) {
        legend.textColor = .white
        legend.horizontalAlignment = .right
        legend.verticalAlignment = .top
        legend.drawInside = true
        legend.yOffset = 30.0
        legend.form = Legend.Form.circle
        legend.formSize = CGFloat(12.0)
        legend.font = .boldSystemFont(ofSize: 15)
    }
}

ContentView:


import SwiftUI
import Charts

struct ContentView: View {
    @State private var selectedYear: Int = 2019
    @State private var barEntries: [ChartDataEntry] = []
    @State private var selectedItem = ""
    @State private var entries = [ChartDataEntry]()
    
    var body: some View {
        VStack {
            Text("\(selectedYear)".replacingOccurrences(of: ",", with: ""))
                .font(.title2)
            Button("Change Year") {
//                if selectedYear == 2019 {
//                    selectedYear = 2020
//                } else {
//                    selectedYear = 2019
//                }
            }
            TimeTakenLineChartView(entries: entries, selectedYear: $selectedYear, selectedItem: $selectedItem)
                .frame(width: 300, height: 300)
            Text(selectedItem)
        }
        .onAppear {
            entries = WineTransaction.dataEntriesForYear(selectedYear, transactions: WineTransaction.allTransactions)
        }
    }
}

任何帮助表示赞赏!

What did you expect to happen?

When I tap or drag across the chart I expected it to select all the entries one-by-one.

What happened instead?

However, it only selects the values on the far right. Which is really weird.

Charts Environment

Latest Release: 4.0.2
XCode 13.2.1
Swift 5.5.2
iOS only
macOS 12.1 running XCode

Demo Project

[Code adapted from this tutorial by Stewart Lynch: https://www.youtube.com/watch?v=csd7pyfEXgw
He made a bar chart, I converted it to a Line chart and added some extra bits like the gradient]

LineChartView:

import SwiftUI
import Charts

struct TimeTakenLineChartView: UIViewRepresentable { \
        
    let entries: [ChartDataEntry]
    let lineChart = LineChartView()
    
    @Binding var selectedYear: Int
    @Binding var selectedItem: String
    
    func makeUIView(context: Context) -> LineChartView {
        lineChart.delegate = context.coordinator
        lineChart.animate(xAxisDuration: 2)
        lineChart.backgroundColor = UIColor(Color.gray)
        return lineChart
    }
    
    func updateUIView(_ uiView: LineChartView, context: Context) {
        let dataSet = LineChartDataSet(entries: entries)
        
        uiView.noDataText = "No Data"
        uiView.data = LineChartData(dataSet: dataSet)
        uiView.rightAxis.enabled = false
        

        uiView.setScaleEnabled(false)
        uiView.notifyDataSetChanged()
        
        formatDataSet(dataSet: dataSet)
        formatLeftAxis(leftAxis: uiView.leftAxis)
        formatXAxis(xAxis: uiView.xAxis)
        formatLegend(legend: uiView.legend)
                
        // data set updates
        dataSet.lineWidth = 3
        dataSet.label = "Seconds Taken"
        dataSet.drawValuesEnabled = false
        dataSet.drawCirclesEnabled = false
        dataSet.mode = .cubicBezier // add this line
        dataSet.drawHorizontalHighlightIndicatorEnabled = false
        dataSet.highlightColor = .white
        
        // Gradient
        let gradientColors = [UIColor(Color.blue).cgColor, UIColor(Color.green).cgColor] as CFArray // Colors of the gradient
        let colorLocations:[CGFloat] = [1.0, 1.0] // Positioning of the gradient
        let gradient = CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations) // Gradient Object
        
        dataSet.isDrawLineWithGradientEnabled = true
        dataSet.gradientPositions = colorLocations
        dataSet.fill =  LinearGradientFill(gradient: gradient!)
        dataSet.drawFilledEnabled = true // Draw the Gradient
    }
    
    class Coordinator: NSObject, ChartViewDelegate {
        let parent:TimeTakenLineChartView
        init(parent: TimeTakenLineChartView) {
            self.parent = parent
        }
        func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
            let quantity = Int(entry.y)
            parent.selectedItem = "\(quantity) seconds"
        }
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    
    func formatDataSet(dataSet: LineChartDataSet) {
        dataSet.colors = [.blue]
        dataSet.valueColors = [.blue]
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        dataSet.valueFormatter = DefaultValueFormatter(formatter: formatter)
    }
    
    func formatLeftAxis(leftAxis: YAxis) {
        leftAxis.labelTextColor = .white
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        leftAxis.valueFormatter = DefaultAxisValueFormatter(formatter: formatter)
        leftAxis.axisMinimum = 0
        leftAxis.drawGridLinesEnabled = false
        leftAxis.labelFont = .boldSystemFont(ofSize: 15)
        leftAxis.drawAxisLineEnabled = false
        leftAxis.drawLabelsEnabled = false
    }
    
    func formatXAxis(xAxis: XAxis) {
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        xAxis.valueFormatter = DefaultAxisValueFormatter(formatter: formatter)
        xAxis.labelPosition = .bottom
        xAxis.labelTextColor = .white
        xAxis.labelFont = .boldSystemFont(ofSize: 15)
        xAxis.drawGridLinesEnabled = false
        xAxis.drawAxisLineEnabled = false
    }
    
    func formatLegend(legend: Legend) {
        legend.textColor = .white
        legend.horizontalAlignment = .right
        legend.verticalAlignment = .top
        legend.drawInside = true
        legend.yOffset = 30.0
        legend.form = Legend.Form.circle
        legend.formSize = CGFloat(12.0)
        legend.font = .boldSystemFont(ofSize: 15)
    }
}

ContentView:


import SwiftUI
import Charts

struct ContentView: View {
    @State private var selectedYear: Int = 2019
    @State private var barEntries: [ChartDataEntry] = []
    @State private var selectedItem = ""
    @State private var entries = [ChartDataEntry]()
    
    var body: some View {
        VStack {
            Text("\(selectedYear)".replacingOccurrences(of: ",", with: ""))
                .font(.title2)
            Button("Change Year") {
//                if selectedYear == 2019 {
//                    selectedYear = 2020
//                } else {
//                    selectedYear = 2019
//                }
            }
            TimeTakenLineChartView(entries: entries, selectedYear: $selectedYear, selectedItem: $selectedItem)
                .frame(width: 300, height: 300)
            Text(selectedItem)
        }
        .onAppear {
            entries = WineTransaction.dataEntriesForYear(selectedYear, transactions: WineTransaction.allTransactions)
        }
    }
}

Any help appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文