Swiftchars - 条形图在特定点数后重叠
Swiftchars - bars chart overlap after specific number of points
如何使用 SwiftChars 库在条形图中指定最小值 space?
- 这是我使用 SwiftCharts 显示条形图的代码示例:
// xAxis
let labelSettings = ChartLabelSettings(font: .systemFont(ofSize: 13.0), fontColor: .aiduBlue)
var xValues = [ChartAxisValue]()
xValues.append(ChartAxisValueString(order: -1))
for (index, point) in barsDataSource.enumerated() {
let dateString = DateFormatter.shortDayOfWeekDayOnTwoLinesFormatter.string(from: point.departureDate)
xValues.append(ChartAxisValueString(dateString, order: index, labelSettings: labelSettings))
}
xValues.append(ChartAxisValueString(order: xValues.count - 1))
let xModel = ChartAxisModel(axisValues: xValues,
lineColor: .aiduSkyBlue,
axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings))
// yAxis
let yAxisMinSpaceBetweenPoints: CGFloat = 10.0
let yAxisTopBottomMargin = (((barsMaxPrice - barsMinPrice) / Double(barsDataSource.count)) + Double(yAxisMinSpaceBetweenPoints)) + 10
let yAxisGenerator = ChartAxisValuesGeneratorNice(minValue: barsMinPrice - yAxisTopBottomMargin,
maxValue: barsMaxPrice + yAxisTopBottomMargin,
preferredDividers: 1,
minSpace: yAxisMinSpaceBetweenPoints,
maxTextSize: CGFloat.greatestFiniteMagnitude,
multiplierUpdateMode: .nice)
let yLabelsGenerator = ChartAxisLabelsGeneratorFunc {scalar in
return ChartAxisLabel(text: "", settings: ChartLabelSettings())
}
let yModel = ChartAxisModel(lineColor: UIColor.white.withAlphaComponent(0),
firstModelValue: barsMinPrice,
lastModelValue: barsMaxPrice,
axisTitleLabels: [],
axisValuesGenerator: yAxisGenerator,
labelsGenerator: yLabelsGenerator)
// Char Bars layer
let frame = chartFrame(containerView.bounds)
let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings,
chartFrame: frame,
xModel: xModel,
yModel: yModel)
let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)
let barsModels: [ChartBarModel] = barsDataSource.enumerated().flatMap { index, item in
[
ChartBarModel(constant: ChartAxisValueInt(index),
axisValue1: ChartAxisValueDouble(0),
axisValue2: ChartAxisValueDouble(item.price),
bgColor: barColor(price: item.price, minPrice: barsMinPrice))
]
}
let chartBarSettings = ChartBarViewSettings(animDuration: 0,
animDelay: 0,
cornerRadius: 0,
roundedCorners: .allCorners,
selectionViewUpdater: nil,
delayInit: false)
let chartBarsLayer = ChartBarsLayer(xAxis: xAxisLayer.axis,
yAxis: yAxisLayer.axis,
bars: barsModels,
horizontal: false,
barWidth: 40,
settings: chartBarSettings,
mode: .translate,
tapHandler: { [weak self] (tappedBar) in
self?.chartBarTapHandler(tappedBar: tappedBar)
}, viewGenerator: { [weak self] (p1, p2, barWidth, color, settings, model, index) -> ChartPointViewBar in
var barBGColor = color
if let s = self, let lastTappedBarModel = s.lastTappedBarModel {
let currentBarModel = s.dataSource[index]
barBGColor = currentBarModel.departureDate == lastTappedBarModel.departureDate && currentBarModel.duration == lastTappedBarModel.duration ? s.barSelectionBgColor : color
}
let view = ChartPointViewBar(p1: p1, p2: p2, width: barWidth, bgColor: barBGColor, settings: settings)
return view
})
// Price labels layer
let labelToBarSpace: Double = 20
let labelChartPoints = barsModels.map { bar in
ChartPoint(x: bar.constant, y: bar.axisValue2.copy(bar.axisValue2.scalar + labelToBarSpace))
}
let priceLabelsLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis,
yAxis: yAxisLayer.axis,
chartPoints: labelChartPoints,
viewGenerator: {(chartPointModel, layer, chart) -> UIView? in
let label = HandlingLabel()
label.text = PriceFormatter.string(fromPrice: Float(chartPointModel.chartPoint.y.scalar - labelToBarSpace))
label.font = .boldSystemFont(ofSize: 10.0)
label.textColor = UIColor.aiduBlue
label.sizeToFit()
let pos = chartPointModel.chartPoint.y.scalar > 0
label.center = CGPoint(x: chartPointModel.screenLoc.x, y: pos ? innerFrame.origin.y : innerFrame.origin.y + innerFrame.size.height)
label.alpha = 0
label.isUserInteractionEnabled = false
label.movedToSuperViewHandler = {[weak label] in
label?.alpha = 1
label?.center.y = chartPointModel.screenLoc.y
}
return label
}, displayDelay: 0, mode: .translate)
return Chart(
frame: frame,
innerFrame: innerFrame,
settings: chartSettings,
layers: [
xAxisLayer,
yAxisLayer,
chartBarsLayer,
priceLabelsLayer
]
)
private var chartSettings: ChartSettings {
var chartSettings = ChartSettings()
chartSettings.leading = 2
chartSettings.top = 2
chartSettings.trailing = 2
chartSettings.bottom = 2
chartSettings.axisStrokeWidth = 0.4
chartSettings.spacingBetweenAxesX = 2
chartSettings.spacingBetweenAxesY = 2
chartSettings.labelsSpacing = 10
chartSettings.labelsToAxisSpacingY = 0
chartSettings.spacingBetweenAxesY = 0
chartSettings.axisTitleLabelsToLabelsSpacing = 0
chartSettings.zoomPan.panEnabled = true
chartSettings.zoomPan.zoomEnabled = false
chartSettings.zoomPan.maxZoomX = 3
chartSettings.zoomPan.minZoomX = 3
chartSettings.zoomPan.minZoomY = 1
chartSettings.zoomPan.maxZoomY = 1
return chartSettings
}
当数据源包含大约(前 10 个)点时,图表工作时不会重叠,但如果更改 (increase/decrease) 数据源,则柱之间没有固定的 space:
当数据源包含大约(前 35 个)点时,条重叠:
Swift图表版本 0.6.5
Swift 版本 5
最后我找到了解决方案:
我必须将 minZoomX 和 maxZoomX(在图表设置中)设置为固定值,即图表的页数(或可滚动区域的数量大于原始宽度)。
为什么?因为我想让图表水平滚动。
代码如下:
let barWidth: CGFloat = 30.0
let spaceBetweenBars: CGFloat = 80.0
let zoomXValue = CGFloat(barsDataSource.count) / (UIScreen.main.bounds.width / (barWidth + spaceBetweenBars))
chartSettings.zoomPan.minZoomX = zoomXValue
chartSettings.zoomPan.maxZoomX = zoomXValue
如何使用 SwiftChars 库在条形图中指定最小值 space?
- 这是我使用 SwiftCharts 显示条形图的代码示例:
// xAxis let labelSettings = ChartLabelSettings(font: .systemFont(ofSize: 13.0), fontColor: .aiduBlue) var xValues = [ChartAxisValue]() xValues.append(ChartAxisValueString(order: -1)) for (index, point) in barsDataSource.enumerated() { let dateString = DateFormatter.shortDayOfWeekDayOnTwoLinesFormatter.string(from: point.departureDate) xValues.append(ChartAxisValueString(dateString, order: index, labelSettings: labelSettings)) } xValues.append(ChartAxisValueString(order: xValues.count - 1)) let xModel = ChartAxisModel(axisValues: xValues, lineColor: .aiduSkyBlue, axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings)) // yAxis let yAxisMinSpaceBetweenPoints: CGFloat = 10.0 let yAxisTopBottomMargin = (((barsMaxPrice - barsMinPrice) / Double(barsDataSource.count)) + Double(yAxisMinSpaceBetweenPoints)) + 10 let yAxisGenerator = ChartAxisValuesGeneratorNice(minValue: barsMinPrice - yAxisTopBottomMargin, maxValue: barsMaxPrice + yAxisTopBottomMargin, preferredDividers: 1, minSpace: yAxisMinSpaceBetweenPoints, maxTextSize: CGFloat.greatestFiniteMagnitude, multiplierUpdateMode: .nice) let yLabelsGenerator = ChartAxisLabelsGeneratorFunc {scalar in return ChartAxisLabel(text: "", settings: ChartLabelSettings()) } let yModel = ChartAxisModel(lineColor: UIColor.white.withAlphaComponent(0), firstModelValue: barsMinPrice, lastModelValue: barsMaxPrice, axisTitleLabels: [], axisValuesGenerator: yAxisGenerator, labelsGenerator: yLabelsGenerator) // Char Bars layer let frame = chartFrame(containerView.bounds) let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings, chartFrame: frame, xModel: xModel, yModel: yModel) let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame) let barsModels: [ChartBarModel] = barsDataSource.enumerated().flatMap { index, item in [ ChartBarModel(constant: ChartAxisValueInt(index), axisValue1: ChartAxisValueDouble(0), axisValue2: ChartAxisValueDouble(item.price), bgColor: barColor(price: item.price, minPrice: barsMinPrice)) ] } let chartBarSettings = ChartBarViewSettings(animDuration: 0, animDelay: 0, cornerRadius: 0, roundedCorners: .allCorners, selectionViewUpdater: nil, delayInit: false) let chartBarsLayer = ChartBarsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, bars: barsModels, horizontal: false, barWidth: 40, settings: chartBarSettings, mode: .translate, tapHandler: { [weak self] (tappedBar) in self?.chartBarTapHandler(tappedBar: tappedBar) }, viewGenerator: { [weak self] (p1, p2, barWidth, color, settings, model, index) -> ChartPointViewBar in var barBGColor = color if let s = self, let lastTappedBarModel = s.lastTappedBarModel { let currentBarModel = s.dataSource[index] barBGColor = currentBarModel.departureDate == lastTappedBarModel.departureDate && currentBarModel.duration == lastTappedBarModel.duration ? s.barSelectionBgColor : color } let view = ChartPointViewBar(p1: p1, p2: p2, width: barWidth, bgColor: barBGColor, settings: settings) return view }) // Price labels layer let labelToBarSpace: Double = 20 let labelChartPoints = barsModels.map { bar in ChartPoint(x: bar.constant, y: bar.axisValue2.copy(bar.axisValue2.scalar + labelToBarSpace)) } let priceLabelsLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, chartPoints: labelChartPoints, viewGenerator: {(chartPointModel, layer, chart) -> UIView? in let label = HandlingLabel() label.text = PriceFormatter.string(fromPrice: Float(chartPointModel.chartPoint.y.scalar - labelToBarSpace)) label.font = .boldSystemFont(ofSize: 10.0) label.textColor = UIColor.aiduBlue label.sizeToFit() let pos = chartPointModel.chartPoint.y.scalar > 0 label.center = CGPoint(x: chartPointModel.screenLoc.x, y: pos ? innerFrame.origin.y : innerFrame.origin.y + innerFrame.size.height) label.alpha = 0 label.isUserInteractionEnabled = false label.movedToSuperViewHandler = {[weak label] in label?.alpha = 1 label?.center.y = chartPointModel.screenLoc.y } return label }, displayDelay: 0, mode: .translate) return Chart( frame: frame, innerFrame: innerFrame, settings: chartSettings, layers: [ xAxisLayer, yAxisLayer, chartBarsLayer, priceLabelsLayer ] ) private var chartSettings: ChartSettings { var chartSettings = ChartSettings() chartSettings.leading = 2 chartSettings.top = 2 chartSettings.trailing = 2 chartSettings.bottom = 2 chartSettings.axisStrokeWidth = 0.4 chartSettings.spacingBetweenAxesX = 2 chartSettings.spacingBetweenAxesY = 2 chartSettings.labelsSpacing = 10 chartSettings.labelsToAxisSpacingY = 0 chartSettings.spacingBetweenAxesY = 0 chartSettings.axisTitleLabelsToLabelsSpacing = 0 chartSettings.zoomPan.panEnabled = true chartSettings.zoomPan.zoomEnabled = false chartSettings.zoomPan.maxZoomX = 3 chartSettings.zoomPan.minZoomX = 3 chartSettings.zoomPan.minZoomY = 1 chartSettings.zoomPan.maxZoomY = 1 return chartSettings }
当数据源包含大约(前 10 个)点时,图表工作时不会重叠,但如果更改 (increase/decrease) 数据源,则柱之间没有固定的 space:
当数据源包含大约(前 35 个)点时,条重叠:
Swift图表版本 0.6.5 Swift 版本 5
最后我找到了解决方案:
我必须将 minZoomX 和 maxZoomX(在图表设置中)设置为固定值,即图表的页数(或可滚动区域的数量大于原始宽度)。 为什么?因为我想让图表水平滚动。
代码如下:
let barWidth: CGFloat = 30.0
let spaceBetweenBars: CGFloat = 80.0
let zoomXValue = CGFloat(barsDataSource.count) / (UIScreen.main.bounds.width / (barWidth + spaceBetweenBars))
chartSettings.zoomPan.minZoomX = zoomXValue
chartSettings.zoomPan.maxZoomX = zoomXValue