Chart.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // LoopFollow
  2. // Chart.swift
  3. // Created by Jon Fawcett on 2020-06-05.
  4. import Charts
  5. import Foundation
  6. final class OverrideFillFormatter: FillFormatter {
  7. func getFillLinePosition(dataSet: Charts.LineChartDataSetProtocol, dataProvider _: Charts.LineChartDataProvider) -> CGFloat {
  8. return CGFloat(dataSet.entryForIndex(0)!.y)
  9. // return 375
  10. }
  11. }
  12. final class basalFillFormatter: FillFormatter {
  13. func getFillLinePosition(dataSet _: Charts.LineChartDataSetProtocol, dataProvider _: Charts.LineChartDataProvider) -> CGFloat {
  14. return 0
  15. }
  16. }
  17. final class ChartXValueFormatter: AxisValueFormatter {
  18. func stringForValue(_ value: Double, axis _: AxisBase?) -> String {
  19. let dateFormatter = DateFormatter()
  20. // let timezoneOffset = TimeZone.current.secondsFromGMT()
  21. // let epochTimezoneOffset = value + Double(timezoneOffset)
  22. if dateTimeUtils.is24Hour() {
  23. dateFormatter.setLocalizedDateFormatFromTemplate("HH:mm")
  24. } else {
  25. dateFormatter.setLocalizedDateFormatFromTemplate("hh:mm")
  26. }
  27. // let date = Date(timeIntervalSince1970: epochTimezoneOffset)
  28. let date = Date(timeIntervalSince1970: value)
  29. let formattedDate = dateFormatter.string(from: date)
  30. return formattedDate
  31. }
  32. }
  33. final class ChartYDataValueFormatter: ValueFormatter {
  34. func stringForValue(_: Double, entry: ChartDataEntry, dataSetIndex _: Int, viewPortHandler _: ViewPortHandler?) -> String {
  35. if entry.data != nil {
  36. return entry.data as? String ?? ""
  37. } else {
  38. return ""
  39. }
  40. }
  41. }
  42. final class ChartYOverrideValueFormatter: ValueFormatter {
  43. func stringForValue(_: Double, entry: ChartDataEntry, dataSetIndex _: Int, viewPortHandler _: ViewPortHandler?) -> String {
  44. if entry.data != nil {
  45. return entry.data as? String ?? ""
  46. } else {
  47. return ""
  48. }
  49. }
  50. }
  51. final class ChartYMMOLValueFormatter: AxisValueFormatter {
  52. func stringForValue(_ value: Double, axis _: AxisBase?) -> String {
  53. return Localizer.toDisplayUnits(String(value))
  54. }
  55. }
  56. class PillMarker: MarkerImage {
  57. private(set) var color: UIColor
  58. private(set) var font: UIFont
  59. private(set) var textColor: UIColor
  60. private var labelText: String = ""
  61. private var attrs: [NSAttributedString.Key: AnyObject]!
  62. static let formatter: DateComponentsFormatter = {
  63. let f = DateComponentsFormatter()
  64. f.allowedUnits = [.minute, .second]
  65. f.unitsStyle = .short
  66. return f
  67. }()
  68. init(color: UIColor, font: UIFont, textColor: UIColor) {
  69. self.color = color
  70. self.font = font
  71. self.textColor = textColor
  72. let paragraphStyle = NSMutableParagraphStyle()
  73. paragraphStyle.alignment = .center
  74. attrs = [.font: font, .paragraphStyle: paragraphStyle, .foregroundColor: textColor, .baselineOffset: NSNumber(value: -4)]
  75. super.init()
  76. }
  77. override func draw(context: CGContext, point: CGPoint) {
  78. // custom padding around text
  79. let labelWidth = labelText.size(withAttributes: attrs).width + 10
  80. // if you modify labelHeigh you will have to tweak baselineOffset in attrs
  81. let labelHeight = labelText.size(withAttributes: attrs).height + 4
  82. // place pill above the marker, centered along x
  83. var rectangle = CGRect(x: point.x, y: point.y, width: labelWidth, height: labelHeight)
  84. rectangle.origin.x -= rectangle.width / 2.0
  85. var spacing: CGFloat = 20
  86. if point.y < 300 { spacing = -40 }
  87. rectangle.origin.y -= rectangle.height + spacing
  88. // rounded rect
  89. let clipPath = UIBezierPath(roundedRect: rectangle, cornerRadius: 6.0).cgPath
  90. context.addPath(clipPath)
  91. context.setFillColor(UIColor.secondarySystemBackground.cgColor)
  92. context.setStrokeColor(UIColor.label.cgColor)
  93. context.closePath()
  94. context.drawPath(using: .fillStroke)
  95. // add the text
  96. labelText.draw(with: rectangle, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
  97. }
  98. override func refreshContent(entry: ChartDataEntry, highlight _: Highlight) {
  99. if entry.data != nil {
  100. // var multiplier = entry.data as! Double * 100.0
  101. // labelText = String(format: "%.0f%%", multiplier)
  102. labelText = entry.data as? String ?? ""
  103. } else {
  104. labelText = String(entry.y)
  105. }
  106. }
  107. private func customString(_ value: Double) -> String {
  108. let formattedString = PillMarker.formatter.string(from: TimeInterval(value))!
  109. // using this to convert the left axis values formatting, ie 2 min
  110. return "\(formattedString)"
  111. }
  112. }