Various improvements

This commit is contained in:
Ilya Laktyushin 2024-03-25 20:43:34 +04:00
parent b7c18980f6
commit 24d7deb3e8
43 changed files with 2076 additions and 1055 deletions

View file

@ -60,6 +60,18 @@ enum BaseConstants {
return numberFormatter
}()
static let tonNumberFormatter: NumberFormatter = {
let numberFormatter = TonNumberFormatter()
numberFormatter.allowsFloats = true
numberFormatter.numberStyle = .decimal
numberFormatter.usesGroupingSeparator = true
numberFormatter.groupingSeparator = " "
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 2
return numberFormatter
}()
static let detailsNumberFormatter: NumberFormatter = {
let detailsNumberFormatter = NumberFormatter()
detailsNumberFormatter.allowsFloats = false

View file

@ -280,6 +280,9 @@ class GeneralChartComponentController: ChartThemeContainer {
}
}
var verticalLimitsNumberFormatter: NumberFormatter = BaseConstants.chartNumberFormatter
var detailsNumberFormatter: NumberFormatter = BaseConstants.detailsNumberFormatter
func verticalLimitsLabels(verticalRange: ClosedRange<CGFloat>) -> (ClosedRange<CGFloat>, [LinesChartLabel]) {
let ditance = verticalRange.distance
let chartHeight = chartFrame().height
@ -313,7 +316,7 @@ class GeneralChartComponentController: ChartThemeContainer {
var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base
let lowerBound = verticalValue
let numberFormatter = BaseConstants.chartNumberFormatter
let numberFormatter = self.verticalLimitsNumberFormatter
numberFormatter.maximumFractionDigits = maximumNumberOfDecimals
while verticalValue < verticalRange.upperBound {
let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? ""
@ -331,7 +334,7 @@ class GeneralChartComponentController: ChartThemeContainer {
let (index, component) = arg
return ChartDetailsViewModel.Value(prefix: nil,
title: component.name,
value: BaseConstants.detailsNumberFormatter.string(from: NSNumber(value: component.values[pointIndex])) ?? "",
value: self.detailsNumberFormatter.string(from: NSNumber(value: component.values[pointIndex])) ?? "",
color: component.color,
visible: chartVisibility[index])
}

View file

@ -17,6 +17,7 @@ class BarsComponentController: GeneralChartComponentController {
let mainBarsRenderer: BarChartRenderer
let horizontalScalesRenderer: HorizontalScalesRenderer
let verticalScalesRenderer: VerticalScalesRenderer
let secondaryScalesRenderer: VerticalScalesRenderer?
let lineBulletsRenderer = LineBulletsRenderer()
let verticalLineRenderer = VerticalLinesRenderer()
@ -32,11 +33,13 @@ class BarsComponentController: GeneralChartComponentController {
mainBarsRenderer: BarChartRenderer,
horizontalScalesRenderer: HorizontalScalesRenderer,
verticalScalesRenderer: VerticalScalesRenderer,
secondaryScalesRenderer: VerticalScalesRenderer? = nil,
previewBarsChartRenderer: BarChartRenderer,
step: Bool = false) {
self.mainBarsRenderer = mainBarsRenderer
self.horizontalScalesRenderer = horizontalScalesRenderer
self.verticalScalesRenderer = verticalScalesRenderer
self.secondaryScalesRenderer = secondaryScalesRenderer
self.previewBarsChartRenderer = previewBarsChartRenderer
self.step = step
@ -122,6 +125,7 @@ class BarsComponentController: GeneralChartComponentController {
mainBarsRenderer.setVisible(visible, animated: animated)
horizontalScalesRenderer.setVisible(visible, animated: animated)
verticalScalesRenderer.setVisible(visible, animated: animated)
secondaryScalesRenderer?.setVisible(visible, animated: animated)
previewBarsChartRenderer.setVisible(visible, animated: animated)
}
@ -129,6 +133,7 @@ class BarsComponentController: GeneralChartComponentController {
mainBarsRenderer.setup(horizontalRange: horizontalRange, animated: animated)
horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated)
verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated)
secondaryScalesRenderer?.setup(horizontalRange: horizontalRange, animated: animated)
verticalLineRenderer.setup(horizontalRange: horizontalRange, animated: animated)
lineBulletsRenderer.setup(horizontalRange: horizontalRange, animated: animated)
@ -144,20 +149,49 @@ class BarsComponentController: GeneralChartComponentController {
components: visibleComponents)
}
var conversionRate: Double = 1.0
func verticalLimitsLabels(verticalRange: ClosedRange<CGFloat>, secondary: Bool) -> (ClosedRange<CGFloat>, [LinesChartLabel]) {
var (range, labels) = super.verticalLimitsLabels(verticalRange: verticalRange)
if secondary {
var updatedLabels: [LinesChartLabel] = []
for label in labels {
let convertedValue = (Double(label.text) ?? 0.0) * self.conversionRate
let text: String
if convertedValue > 1.0 {
text = String(format: "%0.1f", convertedValue)
} else {
text = String(format: "%0.3f", convertedValue)
}
updatedLabels.append(LinesChartLabel(value: label.value, text: "≈$\(text)"))
}
labels = updatedLabels
}
return (range, labels)
}
func updateChartVerticalRanges(horizontalRange: ClosedRange<CGFloat>, animated: Bool) {
if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars,
separate: self.step,
calculatingRange: horizontalRange,
addBounds: true) {
let (range, labels) = verticalLimitsLabels(verticalRange: range)
let (range, labels) = verticalLimitsLabels(verticalRange: range, secondary: false)
if verticalScalesRenderer.verticalRange.end != range {
verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated)
}
verticalScalesRenderer.setVisible(true, animated: animated)
if let secondaryScalesRenderer = self.secondaryScalesRenderer {
let (range, labels) = verticalLimitsLabels(verticalRange: range, secondary: true)
if secondaryScalesRenderer.verticalRange.end != range {
secondaryScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated)
}
secondaryScalesRenderer.setVisible(true, animated: animated)
}
setupMainChart(verticalRange: range, animated: animated)
} else {
verticalScalesRenderer.setVisible(false, animated: animated)
secondaryScalesRenderer?.setVisible(false, animated: animated)
}
if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars, separate: self.step) {
@ -169,6 +203,7 @@ class BarsComponentController: GeneralChartComponentController {
mainBarsRenderer.setup(verticalRange: verticalRange, animated: animated)
horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated)
verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated)
secondaryScalesRenderer?.setup(verticalRange: verticalRange, animated: animated)
lineBulletsRenderer.setup(verticalRange: verticalRange, animated: animated)
}
@ -232,6 +267,9 @@ class BarsComponentController: GeneralChartComponentController {
verticalScalesRenderer.labelsColor = theme.chartLabelsColor
verticalScalesRenderer.axisXColor = theme.barChartStrongLinesColor
verticalScalesRenderer.horizontalLinesColor = theme.barChartStrongLinesColor
secondaryScalesRenderer?.labelsColor = theme.chartLabelsColor
secondaryScalesRenderer?.axisXColor = .clear
secondaryScalesRenderer?.horizontalLinesColor = .clear
mainBarsRenderer.update(backgroundColor: theme.chartBackgroundColor, animated: false)
previewBarsChartRenderer.update(backgroundColor: theme.chartBackgroundColor, animated: false)
verticalLineRenderer.linesColor = theme.chartStrongLinesColor

View file

@ -23,14 +23,26 @@ public class StackedBarsChartController: BaseChartController {
}
}
override public init(chartsCollection: ChartsCollection) {
public init(chartsCollection: ChartsCollection, isCrypto: Bool = false, rate: Double = 1.0) {
let horizontalScalesRenderer = HorizontalScalesRenderer()
let verticalScalesRenderer = VerticalScalesRenderer()
var secondaryScalesRenderer: VerticalScalesRenderer?
if isCrypto {
verticalScalesRenderer.isCrypto = true
secondaryScalesRenderer = VerticalScalesRenderer()
secondaryScalesRenderer?.isRightAligned = true
}
barsController = BarsComponentController(isZoomed: false,
mainBarsRenderer: BarChartRenderer(),
horizontalScalesRenderer: horizontalScalesRenderer,
verticalScalesRenderer: verticalScalesRenderer,
secondaryScalesRenderer: secondaryScalesRenderer,
previewBarsChartRenderer: BarChartRenderer())
if isCrypto {
barsController.conversionRate = rate
barsController.verticalLimitsNumberFormatter = BaseConstants.tonNumberFormatter
barsController.detailsNumberFormatter = BaseConstants.tonNumberFormatter
}
zoomedBarsController = BarsComponentController(isZoomed: true,
mainBarsRenderer: BarChartRenderer(),
horizontalScalesRenderer: horizontalScalesRenderer,
@ -67,12 +79,16 @@ public class StackedBarsChartController: BaseChartController {
}
public override var mainChartRenderers: [ChartViewRenderer] {
return [barsController.mainBarsRenderer,
var renderers = [barsController.mainBarsRenderer,
zoomedBarsController.mainBarsRenderer,
barsController.horizontalScalesRenderer,
barsController.verticalScalesRenderer,
// performanceRenderer
]
if let secondary = barsController.secondaryScalesRenderer {
renderers.append(secondary)
}
return renderers
}
public override var navigationRenderers: [ChartViewRenderer] {

View file

@ -25,6 +25,7 @@ class VerticalScalesRenderer: BaseChartRenderer {
var axisXWidth: CGFloat = GView.oneDevicePixel
var isRightAligned: Bool = false
var isCrypto: Bool = false
var horizontalLinesColor: GColor = .black {
didSet {
@ -120,6 +121,45 @@ class VerticalScalesRenderer: BaseChartRenderer {
context.strokeLineSegments(between: lineSegments)
}
func drawTonSymbol(context: CGContext, color: UIColor, at point: CGPoint) {
let width: CGFloat = 8.0
let height: CGFloat = 7.5
let cornerRadius: CGFloat = 0.5
let topPoint = CGPoint(x: point.x + width / 2, y: point.y)
let bottomPoint = CGPoint(x: point.x + width / 2, y: point.y + height)
let leftTopPoint = CGPoint(x: point.x, y: point.y)
let rightTopPoint = CGPoint(x: point.x + width, y: point.y)
context.saveGState()
context.beginPath()
context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y))
context.addArc(tangent1End: leftTopPoint, tangent2End: bottomPoint, radius: cornerRadius)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel))
context.move(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y))
context.addArc(tangent1End: rightTopPoint, tangent2End: bottomPoint, radius: cornerRadius)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel))
context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y))
context.addLine(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y))
context.move(to: topPoint)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - 1.0))
context.setLineWidth(1.0)
context.setLineCap(.round)
context.setFillColor(UIColor.clear.cgColor)
context.setStrokeColor(color.withAlphaComponent(1.0).cgColor)
context.setAlpha(color.alphaValue)
context.strokePath()
context.restoreGState()
}
func drawVerticalLabels(_ labels: [LinesChartLabel], attributes: [NSAttributedString.Key: Any]) {
if isRightAligned {
for label in labels {
@ -133,7 +173,14 @@ class VerticalScalesRenderer: BaseChartRenderer {
let y = transform(toChartCoordinateVertical: label.value, chartFrame: chartFrame) - labelsFont.pointSize - labelsAxisOffset
let attributedString = NSAttributedString(string: label.text, attributes: attributes)
let textNode = LabelNode.layoutText(attributedString, bounds.size)
textNode.1.draw(CGRect(origin: CGPoint(x:chartFrame.minX, y: y), size: textNode.0.size), in: context, backingScaleFactor: deviceScale)
var xOffset = 0.0
if self.isCrypto {
xOffset += 11.0
drawTonSymbol(context: context, color: attributes[.foregroundColor] as? UIColor ?? .black, at: CGPoint(x: chartFrame.minX, y: y + 4.0))
}
textNode.1.draw(CGRect(origin: CGPoint(x: chartFrame.minX + xOffset, y: y), size: textNode.0.size), in: context, backingScaleFactor: deviceScale)
}
}
}

View file

@ -35,3 +35,28 @@ class ScalesNumberFormatter: NumberFormatter {
}
}
}
class TonNumberFormatter: NumberFormatter {
override func string(from number: NSNumber) -> String? {
var balanceText = "\(number.intValue)"
let decimalSeparator = self.decimalSeparator ?? "."
while balanceText.count < 10 {
balanceText.insert("0", at: balanceText.startIndex)
}
balanceText.insert(contentsOf: decimalSeparator, at: balanceText.index(balanceText.endIndex, offsetBy: -9))
while true {
if balanceText.hasSuffix("0") {
if balanceText.hasSuffix("\(decimalSeparator)0") {
balanceText.removeLast()
balanceText.removeLast()
break
} else {
balanceText.removeLast()
}
} else {
break
}
}
return balanceText
}
}