我很难将库图表(来自Daniel Gindi)从版本2(Swift 2.3)迁移到3(Swift 3)。
基本上,我不能将x标签(日期)与相应的图正确对齐。
这是我之前在第2版中所拥有的:
在版本2中,我有第7天,第8天,第10天和第11天的值。
所以我错过了中间的一天,但标签正确地与情节一致。
以下是版本3中的内容:
在版本3中,"标签"在x轴上现在已被替换为double(对于日期,它自1970年以来是timeInterval),并通过格式化程序格式化。
因此,无可否认,图表更加正确"现在,因为图表正确地推断了第9个的值,但是我无法找到如何将标签放在相应的图表下面。
这是我的x轴代码:
let chartView = LineChartView()
...
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelCount = entries.count
xAxis.drawLabelsEnabled = true
xAxis.drawLimitLinesBehindDataEnabled = true
xAxis.avoidFirstLastClippingEnabled = true
// Set the x values date formatter
let xValuesNumberFormatter = ChartXAxisFormatter()
xValuesNumberFormatter.dateFormatter = dayNumberAndShortNameFormatter // e.g. "wed 26"
xAxis.valueFormatter = xValuesNumberFormatter
这是我创建的ChartXAxisFormatter类:
import Foundation
import Charts
class ChartXAxisFormatter: NSObject {
var dateFormatter: DateFormatter?
}
extension ChartXAxisFormatter: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if let dateFormatter = dateFormatter {
let date = Date(timeIntervalSince1970: value)
return dateFormatter.string(from: date)
}
return ""
}
}
因此,这里的值是正确的,格式是正确的,图表的形状是正确的,但标签与相应图的对齐并不好。 谢谢你的帮助
答案 0 :(得分:14)
好的,明白了!
您必须定义参考时间间隔(" 0"表示x轴)。然后计算每个x值的附加时间间隔。
ChartXAxisFormatter变为:
import Foundation
import Charts
class ChartXAxisFormatter: NSObject {
fileprivate var dateFormatter: DateFormatter?
fileprivate var referenceTimeInterval: TimeInterval?
convenience init(referenceTimeInterval: TimeInterval, dateFormatter: DateFormatter) {
self.init()
self.referenceTimeInterval = referenceTimeInterval
self.dateFormatter = dateFormatter
}
}
extension ChartXAxisFormatter: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
guard let dateFormatter = dateFormatter,
let referenceTimeInterval = referenceTimeInterval
else {
return ""
}
let date = Date(timeIntervalSince1970: value * 3600 * 24 + referenceTimeInterval)
return dateFormatter.string(from: date)
}
}
然后,当我创建数据条目时,它的工作原理如下:
// (objects is defined as an array of struct with date and value)
// Define the reference time interval
var referenceTimeInterval: TimeInterval = 0
if let minTimeInterval = (objects.map { $0.date.timeIntervalSince1970 }).min() {
referenceTimeInterval = minTimeInterval
}
// Define chart xValues formatter
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
formatter.locale = Locale.current
let xValuesNumberFormatter = ChartXAxisFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: xValuesFormatter)
// Define chart entries
var entries = [ChartDataEntry]()
for object in objects {
let timeInterval = object.date.timeIntervalSince1970
let xValue = (timeInterval - referenceTimeInterval) / (3600 * 24)
let yValue = object.value
let entry = ChartDataEntry(x: xValue, y: yValue)
entries.append(entry)
}
// Pass these entries and the formatter to the Chart ...
答案 1 :(得分:2)
如果您确切知道x轴需要多少标签,可以编写此代码来解决它。例如,如果我需要在x轴上出现七个标签,那么这应该就够了。原因是图表库没有正确计算两个x轴点之间的间隔,因此绘图标签不匹配。当我们强制库对照给定数量的标签进行绘图时,问题似乎已经消失。
let xAxis = chart.xAxis
xAxis.centerAxisLabelsEnabled = false
xAxis.setLabelCount(7, force: true) //enter the number of labels here
答案 2 :(得分:0)
这是xValuesNumberFormatter的解决方案
let xValuesFormatter = DateFormatter()
xValuesFormatter.dateFormat = "MM/dd"
let xValuesNumberFormatter = ChartXAxisFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: xValuesFormatter)
xValuesNumberFormatter.dateFormatter = xValuesFormatter // e.g. "wed 26"
xAxis.valueFormatter = xValuesNumberFormatter
答案 3 :(得分:0)
我使用此答案解决了这个问题 https://stackoverflow.com/a/44554613/2087608
我怀疑这些偏移量是由于我的情况将X轴值调整为一天中的特定时间
这是我的代码
for i in 0..<valuesViewModel.entries.count {
let dataEntry = ChartDataEntry(x: roundDate(date: valuesViewModel.entries[i].date).timeIntervalSince1970, y: valuesViewModel.entries[i].value)
dataEntries.append(dataEntry)
}
func roundDate(date: Date) -> Date {
var comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date)
comp.timeZone = TimeZone(abbreviation: "UTC")!
let truncated = Calendar.current.date(from: comp)!
return truncated
}