我正在使用SwiftCharts创建一个基于库提供的Trendline示例的图表。在我的应用程序中,我正在绘制举重事件,显示每个不同日期的单个最高提升重量。在我的例子中,我正在制作4个Bench Press活动。
图表在首次显示视图控制器时呈现,但是当我向右平移时,它会断断续续,展开,点移动。这是看起来像:
请注意,首次渲染图表时,最低绘制值(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轴的渲染有关,所以我尝试调整preferredDividers
和minSpace
值:
let xGeneratorDate = ChartAxisValuesGeneratorDate(unit: .day, preferredDividers: 2, minSpace: 1, maxTextSize: 12)
但这不仅无法解决问题,而且还会产生一个我将单独发布的新内容。
我已多次阅读文档,但我仍然无法弄明白。这是一个写得很漂亮的图书馆,所以我真的很想能够使用它。非常感谢任何帮助。