Диаграммы iOS в виде таблицы: правильное использование делегата и глобальное масштабирование - PullRequest
0 голосов
/ 26 ноября 2018

Я использую диаграммы iOS в своем проекте и смог встроить свои диаграммы в табличное представление (каждая ячейка будет содержать диаграмму с максимальным количеством возможных записей, чтобы контролировать производительность).

Я хотел бы использовать функцию «touchMatrix», чтобы увеличить масштаб оси x на одной диаграмме (в ячейке) и иметь все остальные видимые диаграммы, чтобы следовать шкале масштабирования (ось x),возможно, с вертикальной осью, показывающей значение Y на каждой видимой диаграмме для этой координаты x, но я немного застрял, поскольку даже методы делегата, такие как chartValueNothingSelected, не работают (возможно, я ошибся, когда пытался связатьделегат в диаграмме, так как диаграмма встроена в ячейку, и это не типичный случай привязки делегата к контроллеру представления).Назначение делегата в ячейку просто не работает.

Есть советы?

Заранее спасибо.

Вот код:

import UIKit Графики импорта

class CustomChartCell: UITableViewCell, ChartViewDelegate {

    @IBOutlet weak var lineChartView: LineChartView!
    var yValues     = [Double]()
    var xValues     = [Double]()
    var chartColor  = UIColor()
    var channelName = ""
    var yMin = 0.0
    var yMax = 0.0
    var yAvg = 0.0

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code

        self.lineChartView.noDataFont = UIFont.systemFont(ofSize: 28.0)
        self.lineChartView.noDataText = NSLocalizedString("No chart data available", comment: "No Chart Data Available Title")
        self.lineChartView.xAxis.labelPosition = .bottom
        self.lineChartView.highlightPerTapEnabled = true
        self.lineChartView.autoScaleMinMaxEnabled = true

        self.lineChartView.chartDescription?.enabled = true
        self.lineChartView.dragEnabled = true
        self.lineChartView.setScaleEnabled(true)
        self.lineChartView.pinchZoomEnabled = false

        self.lineChartView.xAxis.gridLineDashLengths = [10, 10]
        self.lineChartView.xAxis.gridLineDashPhase = 0

        self.lineChartView.leftAxis.gridLineDashLengths = [5, 5]
        self.lineChartView.leftAxis.drawLimitLinesBehindDataEnabled = true

        self.lineChartView.rightAxis.enabled = false

        let marker = BalloonMarker(color: UIColor(white: 180/255, alpha: 1),
                                   font: .systemFont(ofSize: 12),
                                   textColor: .white,
                                   insets: UIEdgeInsets(top: 8, left: 8, bottom: 20, right: 8))
        marker.chartView = self.lineChartView
        marker.minimumSize = CGSize(width: 80, height: 40)
        self.lineChartView.marker = marker
        self.lineChartView.legend.form = .line

        self.lineChartView.delegate = self
    }

    func setChart(_ xValues: [Double], _ yValues: [Double]) {

        var dataEntries: [ChartDataEntry] = []

        for i in 0..<xValues.count {
            let dataEntry = ChartDataEntry(x: xValues[i], y: yValues[i])
            dataEntries.append(dataEntry)
        }

        let chartDataSet = LineChartDataSet(values: dataEntries, label: self.channelName)
        let chartData = LineChartData(dataSets: [chartDataSet])

        chartDataSet.setColor(self.chartColor.withAlphaComponent(0.5))
        chartDataSet.drawCirclesEnabled = false
        chartDataSet.lineWidth = 2
        chartDataSet.drawValuesEnabled = false
        chartDataSet.highlightEnabled = true
        chartDataSet.drawFilledEnabled = false

        lineChartView.data = chartData

        self.lineChartView!.leftAxis.axisMinimum = self.yValues.min()! - self.yValues.max()!*0.2
        self.lineChartView!.leftAxis.axisMaximum = self.yValues.max()! + self.yValues.max()!*0.2

        self.lineChartView!.chartDescription?.font = UIFont.systemFont(ofSize: 11.0)
        self.lineChartView!.chartDescription?.text = "y_min: \(self.yMin), y_max: \(self.yMax), y_avg: \(self.yAvg)"
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}


class ChartTableViewController: UITableViewController, ChartViewDelegate {

    var dataSet : [LineChartData] = []
    let data = LineChartData()
    var channelNames : [String] = []
    let channelColors = [UIColor.blue,   UIColor.green,  UIColor.red,
                         UIColor.orange, UIColor.purple, UIColor.darkGray]
    var averageValues : [Double] = []
    var minValues     : [Double] = []
    var maxValues     : [Double] = []
    var xValues       : [[Double]] = []
    var yValues       : [[Double]] = []


    @IBAction func chartZoomOut(_ sender: Any) {

        tableView?.visibleCells.forEach { cell in
            if let cell = cell as? CustomChartCell {
                cell.lineChartView.zoomOut()
            }
        }
    }

    @IBAction func chartZoom100(_ sender: Any) {
        tableView?.visibleCells.forEach { cell in
            if let cell = cell as? CustomChartCell {
                cell.lineChartView.zoomToCenter(scaleX: 0, scaleY: 0)
            }
        }
    }

    @IBAction func chartZoomIn(_ sender: Any) {
        tableView?.visibleCells.forEach { cell in
            if let cell = cell as? CustomChartCell {
                cell.lineChartView.zoomIn()
    }

    func chartValueNothingSelected(_ chartView: ChartViewBase) {
        chartView.chartDescription?.text = ""
    }


    func chartScaled(chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
        print(scaleX)
        print(scaleY)
    }

    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {

        chartView.chartDescription?.text = "x: \(entry.x), y: \(entry.y), y_min: \(minValues[0]), y_max: \(maxValues[0]), y_avg: \(averageValues[0])"

        chartView.reloadInputViews()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.isEditing = false
        self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
        self.tableView.separatorColor = UIColor.clear

        self.navigationItem.rightBarButtonItem = self.editButtonItem


        self.loadFile()
        self.tableView.reloadData()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.tableView.isEditing = false
        self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
    }



    // MARK: Load Chart File
    func loadFile() {
        // Try to load the file content
        do {
            // get the documents folder url
            let documentDirectoryURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            // create the destination url for the text file to be saved
            let fileDestinationUrl = documentDirectoryURL.appendingPathComponent(Constants.CHART_FILE_NAME)

            // reading from disk
            do {
                let file = try String(contentsOf: fileDestinationUrl)

                let newFile = file.replacingOccurrences(of: "\r", with: "") // Get rid of additional new lines

                let cleanChannels = self.generateCleanChannels(newFile)  // // a function used to retrieve the channels from the file (since the file it's not a plain CSV file but something different)
                channelNames.removeAll()
                dataSet.removeAll()
                channelNames  = self.getChannelNames(newFile)  // a function used to retrieve the channel names from the file (since the file it's not a plain CSV file but something different)

                var lineChartEntry = [ChartDataEntry]()


                data.clearValues()

                for (index,channel) in cleanChannels.enumerated() {
                    if (index <= Constants.MAX_CHART_CHANNELS) {
                        let csvImage = CSV(string: channel, delimiter: ";")

                        var y_max = 0.0
                        var firstXValueSampled : Bool = false
                        var firstXValue : Double = 0.0

                        var average = 0.0
                        var min     = 0.0
                        var max     = 0.0
                        var count   = 0

                        var new_xValues : [Double] = []
                        var new_yValues : [Double] = []

                        csvImage.enumerateAsDict { dict in
                            print(dict["X_Value"]!)

                            new_xValues.append(Double(dict["X_Value"]!)!)
                            new_yValues.append(Double(dict["Y_Value"]!)!)

                            if !firstXValueSampled {
                                firstXValueSampled = true
                                firstXValue = Double(dict["X_Value"]!)!
                            }

                            average = average + Double(dict["Y_Value"]!)!
                            count   = count + 1

                            let value = ChartDataEntry(x: (Double(dict["X_Value"]!)! - firstXValue), y: Double(dict["Y_Value"]!)! )
                            lineChartEntry.append(value)

                            if Double(dict["Y_Value"]!)! > max {
                                max = Double(dict["Y_Value"]!)!
                            }
                            if Double(dict["Y_Value"]!)! < min {
                                min = Double(dict["Y_Value"]!)!
                            }

                            if Double(dict["Y_Value"]!)! > y_max {
                                y_max = Double(dict["Y_Value"]!)!
                            }
                        }

                        xValues.append(new_xValues)
                        yValues.append(new_yValues)

                        average = average / Double(count)
                        averageValues.append(average)
                        minValues.append(min)
                        maxValues.append(max)

                        let line = LineChartDataSet(values: lineChartEntry, label: channelNames[index])

                        line.axisDependency = .left

                        line.colors = [channelColors[index]] // Set the color

                        line.setColor(channelColors[index].withAlphaComponent(0.5))
                        line.setCircleColor(channelColors[index])
                        line.lineWidth = 2.0
                        line.circleRadius = 3.0
                        line.fillAlpha = 65 / 255.0
                        line.fillColor = channelColors[index]
                        line.highlightColor = UIColor(red: 244/255, green: 117/255, blue: 117/255, alpha: 1)
                        line.drawCircleHoleEnabled = false
                        line.highlightLineWidth = 2.0
                        line.drawHorizontalHighlightIndicatorEnabled = true
                        data.setValueFont(.systemFont(ofSize: 9))

                        data.addDataSet(line)  // Add the line to the dataSet

                        let newData = LineChartData()
                        newData.setValueFont(.systemFont(ofSize: 9))
                        newData.addDataSet(line)
                        dataSet.append(newData)
                    }
                }

            } catch let error as NSError {
                print("error loading contentsOf url \(fileDestinationUrl)")
                print(error.localizedDescription)
            }

        } catch let error as NSError {
            print("error getting documentDirectoryURL")
            print(error.localizedDescription)
        }
    }


    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return dataSet.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cellIdentifier = "CustomChartCell"
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,
                                                 for: indexPath) as! CustomChartCell
        cell.lineChartView.delegate = self

        if dataSet.count > 0 {
            cell.xValues     = xValues[indexPath.row]
            cell.yValues     = yValues[indexPath.row]
            cell.chartColor  = channelColors[indexPath.row]
            cell.channelName = channelNames[indexPath.row]
            cell.yMin        = minValues[indexPath.row]
            cell.yMax        = maxValues[indexPath.row]
            cell.yAvg        = averageValues[indexPath.row]

            cell.lineChartView.leftAxis.axisMaximum = cell.yValues.max()! + 1
            cell.lineChartView.leftAxis.axisMinimum = cell.yValues.min()! - 1
            cell.setChart(cell.xValues, cell.yValues)
        } else {
            cell.lineChartView.clearValues()
        }

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //tableView.deselectRow(at: indexPath, animated: true)

        let selectedCell = tableView.cellForRow(at: indexPath) as! CustomChartCell
        selectedCell.contentView.backgroundColor = UIColor.lightGray
        //let currentMatrix = selectedCell.lineChartView.viewPortHandler.touchMatrix

        //let selectedCell:UITableViewCell = tableView.cellForRow(at: indexPath)! as! CustomChartCell
        //selectedCell.contentView.backgroundColor = UIColor.lightGray
        //let currentMatrix = selectedCell.lineChartView.viewPortHandler.touchMatrix

        /*
         tableView.visibleCells.forEach { cell in
         if let cell = cell as? CustomChartCell {
         if cell.channelName != selectedCell.channelName {
         cell.lineChartView.viewPortHandler.refresh(newMatrix: currentMatrix, chart: cell.lineChartView, invalidate: true)
         }
         }
         }
         */
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 250
    }

    override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .none
    }

    override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
        return false
    }

    override func setEditing (_ editing:Bool, animated:Bool)
    {
        super.setEditing(editing,animated:animated)
        if (self.isEditing) {
            //self.editButtonItem.title = "Editing"
            self.editButtonItem.title = NSLocalizedString("Done", comment: "Done Title")
        }
        else {
            self.editButtonItem.title = NSLocalizedString("Edit", comment: "Edit Title")
        }
    }

    override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let movedObject = self.dataSet[sourceIndexPath.row]
        dataSet.remove(at: sourceIndexPath.row)
        dataSet.insert(movedObject, at: destinationIndexPath.row)
    }
}
...