Fix chart scales & zooming

This commit is contained in:
Ilya Laktyushin
2020-03-23 19:38:40 +04:00
parent 45cdcfba15
commit 850b19e607
12 changed files with 79 additions and 51 deletions

View File

@@ -269,16 +269,20 @@ class GeneralChartComponentController: ChartThemeContainer {
var numberOfOffsetsPerItem = ditance / approximateNumberOfChartValues
var multiplier: CGFloat = 1.0
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
}
}
var dividor: CGFloat = 1.0
var maximumNumberOfDecimals = 2
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
}
}
var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor

View File

@@ -107,6 +107,8 @@ public class BaseLinesChartController: BaseChartController {
color: component.color,
visible: actualChartVisibility[index])
}
let total = actualChartsCollection.chartValues.enumerated().map { $0.element.values[pointIndex] }.reduce(0, +)
let dateString: String
if isZoomed {
dateString = BaseConstants.timeDateFormatter.string(from: closestDate)
@@ -114,7 +116,7 @@ public class BaseLinesChartController: BaseChartController {
dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate)
}
let viewModel = ChartDetailsViewModel(title: dateString,
showArrow: self.isZoomable && !self.isZoomed,
showArrow: total > 0 && self.isZoomable && !self.isZoomed,
showPrefixes: false,
values: values,
totalValue: nil,
@@ -194,16 +196,20 @@ public class BaseLinesChartController: BaseChartController {
var numberOfOffsetsPerItem = distance / approximateNumberOfChartValues
var multiplier: CGFloat = 1.0
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
}
}
var dividor: CGFloat = 1.0
var maximumNumberOfDecimals = 2
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
}
}
var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor

View File

@@ -61,7 +61,7 @@ public class GeneralLinesChartController: BaseLinesChartController {
self.prevoiusHorizontalStrideInterval = -1
self.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange
self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange
self.lineBulletsRenderer.bullets = self.chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero,
self.lineBulletsRenderer.bullets = self.chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero, offset: .zero,
color: $0.color)}
let chartRange: ClosedRange<CGFloat>
@@ -133,7 +133,7 @@ public class GeneralLinesChartController: BaseLinesChartController {
super.chartInteractionDidBegin(point: point)
self.lineBulletsRenderer.bullets = chartLines.compactMap { chart in
return LineBulletsRenderer.Bullet(coordinate: chart.points[minIndex], color: chart.color)
return LineBulletsRenderer.Bullet(coordinate: chart.points[minIndex], offset: .zero, color: chart.color)
}
self.lineBulletsRenderer.isEnabled = true

View File

@@ -77,7 +77,7 @@ public class TwoAxisLinesChartController: BaseLinesChartController {
controller.verticalScalesRenderer.labelsColor = chart.color
controller.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange
self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange
controller.lineBulletsRenderer.bullets = chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero,
controller.lineBulletsRenderer.bullets = chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero, offset: .zero,
color: $0.color) }
controller.previewLinesRenderer.setup(horizontalRange: self.totalHorizontalRange, animated: animated)
controller.previewLinesRenderer.setup(verticalRange: controller.totalVerticalRange, animated: animated)
@@ -161,7 +161,7 @@ public class TwoAxisLinesChartController: BaseLinesChartController {
for graphController in graphControllers {
graphController.lineBulletsRenderer.bullets = graphController.chartLines.map { chart in
LineBulletsRenderer.Bullet(coordinate: chart.points[minIndex], color: chart.color)
LineBulletsRenderer.Bullet(coordinate: chart.points[minIndex], offset: .zero, color: chart.color)
}
graphController.lineBulletsRenderer.isEnabled = true
}
@@ -246,16 +246,20 @@ public class TwoAxisLinesChartController: BaseLinesChartController {
var numberOfOffsetsPerItem = verticalRange.distance / approximateNumberOfChartValues
var multiplier: CGFloat = 1.0
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
}
}
var dividor: CGFloat = 1.0
var maximumNumberOfDecimals = 2
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
}
}
let generalBase = Constants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor

View File

@@ -62,7 +62,7 @@ class LinesComponentController: GeneralChartComponentController {
let (chartLines, totalHorizontalRange, totalVerticalRange) = LinesChartRenderer.LineData.initialComponents(chartsCollection: chartsCollection)
self.chartLines = chartLines
self.lineBulletsRenderer.bullets = self.chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero,
self.lineBulletsRenderer.bullets = self.chartLines.map { LineBulletsRenderer.Bullet(coordinate: $0.points.first ?? .zero, offset: .zero,
color: $0.color)}
super.initialize(chartsCollection: chartsCollection,
@@ -190,7 +190,7 @@ class LinesComponentController: GeneralChartComponentController {
lineBulletsRenderer.isEnabled = true
lineBulletsRenderer.setVisible(true, animated: animted)
lineBulletsRenderer.bullets = chartLines.compactMap { chart in
return LineBulletsRenderer.Bullet(coordinate: chart.points[dataIndex], color: chart.color)
return LineBulletsRenderer.Bullet(coordinate: chart.points[dataIndex], offset: .zero, color: chart.color)
}
}

View File

@@ -72,7 +72,7 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
for i in 0 ..< chartBars.locations.count {
let location = chartBars.locations[i]
let value = component.values[i]
bullets.append(LineBulletsRenderer.Bullet(coordinate: CGPoint(x: location, y: value), color: component.color))
bullets.append(LineBulletsRenderer.Bullet(coordinate: CGPoint(x: location, y: value), offset: .zero, color: component.color))
}
}
@@ -155,12 +155,17 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
let chartInteractionWasBegin = isChartInteractionBegun
super.chartInteractionDidBegin(point: point)
var barOffset: CGFloat = 0.0
for graphController in graphControllers {
var bullets: [LineBulletsRenderer.Bullet] = []
if let component = graphController.chartBars.components.first {
let location = graphController.chartBars.locations[minIndex]
let value = component.values[minIndex]
bullets.append(LineBulletsRenderer.Bullet(coordinate: CGPoint(x: location, y: value), color: component.color))
let offset = -(graphController.mainBarsRenderer.transform(toChartCoordinateHorizontal: horizontalRange.lowerBound + graphController.barsWidth, chartFrame: chartFrame) - chartFrame.minX) / 2.0
barOffset = offset
bullets.append(LineBulletsRenderer.Bullet(coordinate: CGPoint(x: location, y: value), offset: CGPoint(x: offset, y: 0.0), color: component.color))
}
graphController.lineBulletsRenderer.bullets = bullets
graphController.lineBulletsRenderer.isEnabled = true
@@ -172,6 +177,7 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
self.setDetailsChartVisibleClosure?(true, true)
self.setDetailsViewPositionClosure?(detailsViewPosition)
self.verticalLineRenderer.values = [chartValue]
self.verticalLineRenderer.offset = barOffset
}
public override var currentChartHorizontalRangeFraction: ClosedRange<CGFloat> {
@@ -244,18 +250,22 @@ public class TwoAxisStepBarsChartController: BaseLinesChartController {
var numberOfOffsetsPerItem = verticalRange.distance / approximateNumberOfChartValues
var multiplier: CGFloat = 1.0
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem > 10 {
numberOfOffsetsPerItem /= 10
multiplier *= 10
}
}
var dividor: CGFloat = 1.0
var maximumNumberOfDecimals = 2
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
if numberOfOffsetsPerItem > 0 {
while numberOfOffsetsPerItem < 1 {
numberOfOffsetsPerItem *= 10
dividor *= 10
maximumNumberOfDecimals += 1
}
}
let generalBase = Constants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor
let base = generalBase * multiplier / dividor

View File

@@ -16,6 +16,7 @@ import UIKit
class LineBulletsRenderer: BaseChartRenderer {
struct Bullet {
var coordinate: CGPoint
var offset: CGPoint
var color: GColor
}
@@ -56,8 +57,8 @@ class LineBulletsRenderer: BaseChartRenderer {
let alpha = alphaAnimators[index].current
if alpha == 0 { continue }
let centerX = transform(toChartCoordinateHorizontal: bullet.coordinate.x, chartFrame: chartFrame)
let centerY = transform(toChartCoordinateVertical: bullet.coordinate.y, chartFrame: chartFrame)
let centerX = transform(toChartCoordinateHorizontal: bullet.coordinate.x, chartFrame: chartFrame) + bullet.offset.x
let centerY = transform(toChartCoordinateVertical: bullet.coordinate.y, chartFrame: chartFrame) + bullet.offset.y
context.setFillColor(innerColorAnimator.current.color.withAlphaComponent(alpha).cgColor)
context.setStrokeColor(bullet.color.withAlphaComponent(alpha).cgColor)
context.setLineWidth(linesWidth)

View File

@@ -20,6 +20,7 @@ class VerticalLinesRenderer: BaseChartRenderer {
setNeedsDisplay()
}
}
var offset: CGFloat = 0.0
private var alphaAnimators: [AnimationController<CGFloat>] = []
var linesColor: GColor = .black
@@ -39,7 +40,7 @@ class VerticalLinesRenderer: BaseChartRenderer {
if alpha == 0 { continue }
context.setStrokeColor(linesColor.withAlphaComponent(linesColor.alphaValue * alpha).cgColor)
let pointX = transform(toChartCoordinateHorizontal: value, chartFrame: chartFrame)
let pointX = transform(toChartCoordinateHorizontal: value, chartFrame: chartFrame) + offset
context.strokeLineSegments(between: [CGPoint(x: pointX, y: chartFrame.minY),
CGPoint(x: pointX, y: chartFrame.maxY)])
}

View File

@@ -100,11 +100,10 @@ class VerticalScalesRenderer: BaseChartRenderer {
if generalAlpha == 0 { return }
let labelColorAlpha = labelsColor.alphaValue
let spacing: CGFloat = 1.0
context.clip(to: CGRect(origin: CGPoint(x: 0.0, y: chartFrame.minY - spacing), size: CGSize(width: chartFrame.width + chartFrame.origin.x * 2.0, height: chartFrame.height + spacing * 2.0)))
func drawLines(_ labels: [LinesChartLabel], alpha: CGFloat) {
var labels = labels
if labels.count > 1 {
labels.removeFirst()
}
var lineSegments: [CGPoint] = []
let x0 = chartFrame.minX
let x1 = chartFrame.maxX
@@ -113,8 +112,10 @@ class VerticalScalesRenderer: BaseChartRenderer {
for lineInfo in labels {
let y = transform(toChartCoordinateVertical: lineInfo.value, chartFrame: chartFrame).roundedUpToPixelGrid()
lineSegments.append(CGPoint(x: x0, y: y))
lineSegments.append(CGPoint(x: x1, y: y))
if y < chartFrame.maxY - 2.0 {
lineSegments.append(CGPoint(x: x0, y: y))
lineSegments.append(CGPoint(x: x1, y: y))
}
}
context.strokeLineSegments(between: lineSegments)
}
@@ -164,5 +165,7 @@ class VerticalScalesRenderer: BaseChartRenderer {
attributes: [.foregroundColor: labelsColor.withAlphaComponent(animatedLabesAndLines.alphaAnimator.current * labelColorAlpha * generalAlpha),
.font: labelsFont])
}
context.resetClip()
}
}