1

我正在使用基于库提供的趋势线示例的 SwiftCharts 创建图表。在我的应用程序中,我正在绘制举重事件图表,显示每个不同日期的单个最高举重重量。在我的示例中,我正在绘制 4 个卧推事件。

图表在第一次显示视图控制器时呈现,但是当我向右平移时,它会结结巴巴、展开,并且点会移动。这就是它的样子:

在此处输入图像描述

请注意,当图表第一次渲染时,最低绘制值 (208.0) 似乎在 3 月 12 日到 3 月 13 日之间,但在它出现这种卡顿之后,该点移动到了 3 月 13 日的右侧。

chartPoints正在绘制的是:

▿ 4 elements
  ▿ 0 : Mar 12, 239.17
  ▿ 1 : Mar 13, 208
  ▿ 2 : Mar 15, 267.17
  ▿ 3 : Mar 18, 240

这是视图控制器:

import UIKit
import SwiftCharts

class ChartViewController: UIViewController {

    fileprivate var chart: Chart? // arc
    fileprivate let dataManager = CoreDataHelper()

    override func viewDidLoad() {
        super.viewDidLoad()

        let labelSettings = ChartLabelSettings(font: ChartDefaults.labelFont)

        let liftEventTypeUuid = "98608870-E3CE-476A-B1E4-018D2AE4BDBF"

        let liftEvents = dataManager.fetchLiftsEventsOfType(liftEventTypeUuid)

        let dailyLiftEvents = liftEvents.reduce(into: [Date:[LiftEvent]](), { dailyLiftEvents, currentLiftEvent in
            dailyLiftEvents[Calendar.current.startOfDay(for: currentLiftEvent.date), default: [LiftEvent]()].append(currentLiftEvent)
        })
        let dailyMaxLiftEvents = dailyLiftEvents.map({$0.value.max(by: {$0.oneRepMax < $1.oneRepMax})})
        var sortedLiftEvents = dailyMaxLiftEvents.sorted(by: { $0?.date.compare(($1?.date)!) == .orderedAscending })


        var readFormatter = DateFormatter()
        readFormatter.dateFormat = "dd.MM.yyyy"

        var displayFormatter = DateFormatter()
        displayFormatter.dateFormat = "MMM dd"

        let date = {(str: String) -> Date in
            return readFormatter.date(from: str)!
        }

        let calendar = Calendar.current

        let dateWithComponents = {(day: Int, month: Int, year: Int) -> Date in
            var components = DateComponents()
            components.day = day
            components.month = month
            components.year = year
            return calendar.date(from: components)!
        }

        func filler(_ date: Date) -> ChartAxisValueDate {
            let filler = ChartAxisValueDate(date: date, formatter: displayFormatter)
            filler.hidden = true
            return filler
        }

        let chartPoints = sortedLiftEvents.map { ChartPoint(x: ChartAxisValueDate(date: ($0?.date)!, formatter: displayFormatter), y: ChartAxisValueDouble(($0?.calculateOneRepMax().value)!)) }

        let highestWeight = sortedLiftEvents.last??.oneRepMax.value
        let lowestWeight = sortedLiftEvents.first??.oneRepMax.value

        let yValues = stride(from: roundToTen(x: lowestWeight! - 40), through: roundToTen(x: highestWeight! + 40), by: 20).map {ChartAxisValueDouble(Double($0), labelSettings: labelSettings)}

        let xGeneratorDate = ChartAxisValuesGeneratorDate(unit: .day, preferredDividers: 2, minSpace: 1, maxTextSize: 12)
        let xLabelGeneratorDate = ChartAxisLabelsGeneratorDate(labelSettings: labelSettings, formatter: displayFormatter)
        let firstDate = sortedLiftEvents.first??.date
        let lastDate = sortedLiftEvents.last??.date

        let xModel = ChartAxisModel(firstModelValue: (firstDate?.timeIntervalSince1970)!, lastModelValue: (lastDate?.timeIntervalSince1970)!, axisTitleLabels: [ChartAxisLabel(text: "Date", settings: labelSettings)], axisValuesGenerator: xGeneratorDate, labelsGenerator: xLabelGeneratorDate)

        let yModel = ChartAxisModel(axisValues: yValues, axisTitleLabel: ChartAxisLabel(text: "1-RM", settings: labelSettings.defaultVertical()))
        let chartFrame = ChartDefaults.chartFrame(view.bounds)

        var chartSettings = ChartDefaults.chartSettingsWithPanZoom // was ChartDefaults.chartSettings
        chartSettings.trailing = 80

        // Set a fixed (horizontal) scrollable area 2x than the original width, with zooming disabled.
        chartSettings.zoomPan.maxZoomX = 2
        chartSettings.zoomPan.minZoomX = 2
        chartSettings.zoomPan.minZoomY = 1
        chartSettings.zoomPan.maxZoomY = 1

ChartAxisValuesStaticGenerator.generateYAxisValuesWithChartPoints(chartPoints, minSegmentCount: 10, maxSegmentCount: 20, multiple: 2, axisValueGenerator: {ChartAxisValueDouble($0, labelSettings: labelSettings)}, addPaddingSegmentIfEdge: false)

        let lineModel = ChartLineModel(chartPoints: chartPoints, lineColor: UIColor.red, lineCap: .round ,animDuration: 1, animDelay: 0)

        let trendLineModel = ChartLineModel(chartPoints: TrendlineGenerator.trendline(chartPoints), lineColor: UIColor.blue, animDuration: 0.5, animDelay: 1)

        let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings, chartFrame: chartFrame, xModel: xModel, yModel: yModel)
        let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)

        let chartPointsLineLayer = ChartPointsLineLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, lineModels: [lineModel])

        let trendLineLayer = ChartPointsLineLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, lineModels: [trendLineModel])

        let settings = ChartGuideLinesDottedLayerSettings(linesColor: UIColor.black, linesWidth: ChartDefaults.guidelinesWidth)
        let guidelinesLayer = ChartGuideLinesDottedLayer(xAxisLayer: xAxisLayer, yAxisLayer: yAxisLayer, settings: settings)

        let chart = Chart(
            frame: chartFrame,
            innerFrame: innerFrame,
            settings: chartSettings,
            layers: [
                xAxisLayer,
                yAxisLayer,
                guidelinesLayer,
                chartPointsLineLayer,
                trendLineLayer
            ]
        )

        view.addSubview(chart.view)
        self.chart = chart
    }

    private struct liftWeightItem {
        let number: Int
        let text: String

        init(number: Int, text: String) {
            self.number = number
            self.text = text
        }
    }

    private struct liftDateItem {
        let name: String
        let quantity: liftWeightItem

        init(name: String, quantity: liftWeightItem) {
            self.name = name
            self.quantity = quantity
        }
    }

    func createChartPoint(dateStr: String, percent: Double, readFormatter: DateFormatter, displayFormatter: DateFormatter) -> ChartPoint {
        return ChartPoint(x: createDateAxisValue(dateStr, readFormatter: readFormatter, displayFormatter: displayFormatter), y: ChartAxisValueDouble(percent))
    }

    func createDateAxisValue(_ dateStr: String, readFormatter: DateFormatter, displayFormatter: DateFormatter) -> ChartAxisValue {
        let date = readFormatter.date(from: dateStr)!
        let labelSettings = ChartLabelSettings(font: ChartDefaults.labelFont, rotation: 45, rotationKeep: .top)
        return ChartAxisValueDate(date: date, formatter: displayFormatter, labelSettings: labelSettings)
    }

    func roundToTen(x : Double) -> Int {
        return 10 * Int(round(x / 10.0))
    }

    class ChartAxisValuePercent: ChartAxisValueDouble {
        override var description: String {
            return "\(formatter.string(from: NSNumber(value: scalar))!)%"
        }
    }
}

我怀疑它与 x 轴的渲染有关,所以我尝试调整preferredDividersandminSpace值:

let xGeneratorDate = ChartAxisValuesGeneratorDate(unit: .day, preferredDividers: 2, minSpace: 1, maxTextSize: 12)

但这不仅不能解决问题,还会导致我将单独发布一个新问题。

我已经多次阅读文档,但我仍然无法弄清楚。这是一个编写精美的库,所以我真的很想能够使用它。任何帮助是极大的赞赏。

4

0 回答 0