BalloonMarker.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. //
  2. // BalloonMarker.swift
  3. // ChartsDemo
  4. //
  5. // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
  6. // A port of MPAndroidChart for iOS
  7. // Licensed under Apache License 2.0
  8. //
  9. // https://github.com/danielgindi/Charts
  10. //
  11. import Foundation
  12. import Charts
  13. open class BalloonMarker: MarkerImage
  14. {
  15. @objc open var color: UIColor
  16. @objc open var arrowSize = CGSize(width: 15, height: 11)
  17. @objc open var font: UIFont
  18. @objc open var textColor: UIColor
  19. @objc open var insets: UIEdgeInsets
  20. @objc open var minimumSize = CGSize()
  21. fileprivate var label: String?
  22. fileprivate var _labelSize: CGSize = CGSize()
  23. fileprivate var _paragraphStyle: NSMutableParagraphStyle?
  24. fileprivate var _drawAttributes = [NSAttributedStringKey : AnyObject]()
  25. @objc public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets)
  26. {
  27. self.color = color
  28. self.font = font
  29. self.textColor = textColor
  30. self.insets = insets
  31. _paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle
  32. _paragraphStyle?.alignment = .center
  33. super.init()
  34. }
  35. open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint
  36. {
  37. var offset = self.offset
  38. var size = self.size
  39. if size.width == 0.0 && image != nil
  40. {
  41. size.width = image!.size.width
  42. }
  43. if size.height == 0.0 && image != nil
  44. {
  45. size.height = image!.size.height
  46. }
  47. let width = size.width
  48. let height = size.height
  49. let padding: CGFloat = 8.0
  50. var origin = point
  51. origin.x -= width / 2
  52. origin.y -= height
  53. if origin.x + offset.x < 0.0
  54. {
  55. offset.x = -origin.x + padding
  56. }
  57. else if let chart = chartView,
  58. origin.x + width + offset.x > chart.bounds.size.width
  59. {
  60. offset.x = chart.bounds.size.width - origin.x - width - padding
  61. }
  62. if origin.y + offset.y < 0
  63. {
  64. offset.y = height + padding;
  65. }
  66. else if let chart = chartView,
  67. origin.y + height + offset.y > chart.bounds.size.height
  68. {
  69. offset.y = chart.bounds.size.height - origin.y - height - padding
  70. }
  71. return offset
  72. }
  73. open override func draw(context: CGContext, point: CGPoint)
  74. {
  75. guard let label = label else { return }
  76. let offset = self.offsetForDrawing(atPoint: point)
  77. let size = self.size
  78. var rect = CGRect(
  79. origin: CGPoint(
  80. x: point.x + offset.x,
  81. y: point.y + offset.y),
  82. size: size)
  83. rect.origin.x -= size.width / 2.0
  84. rect.origin.y -= size.height
  85. context.saveGState()
  86. context.setFillColor(color.cgColor)
  87. if offset.y > 0
  88. {
  89. context.beginPath()
  90. context.move(to: CGPoint(
  91. x: rect.origin.x,
  92. y: rect.origin.y + arrowSize.height))
  93. context.addLine(to: CGPoint(
  94. x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
  95. y: rect.origin.y + arrowSize.height))
  96. //arrow vertex
  97. context.addLine(to: CGPoint(
  98. x: point.x,
  99. y: point.y))
  100. context.addLine(to: CGPoint(
  101. x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
  102. y: rect.origin.y + arrowSize.height))
  103. context.addLine(to: CGPoint(
  104. x: rect.origin.x + rect.size.width,
  105. y: rect.origin.y + arrowSize.height))
  106. context.addLine(to: CGPoint(
  107. x: rect.origin.x + rect.size.width,
  108. y: rect.origin.y + rect.size.height))
  109. context.addLine(to: CGPoint(
  110. x: rect.origin.x,
  111. y: rect.origin.y + rect.size.height))
  112. context.addLine(to: CGPoint(
  113. x: rect.origin.x,
  114. y: rect.origin.y + arrowSize.height))
  115. context.fillPath()
  116. }
  117. else
  118. {
  119. context.beginPath()
  120. context.move(to: CGPoint(
  121. x: rect.origin.x,
  122. y: rect.origin.y))
  123. context.addLine(to: CGPoint(
  124. x: rect.origin.x + rect.size.width,
  125. y: rect.origin.y))
  126. context.addLine(to: CGPoint(
  127. x: rect.origin.x + rect.size.width,
  128. y: rect.origin.y + rect.size.height - arrowSize.height))
  129. context.addLine(to: CGPoint(
  130. x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0,
  131. y: rect.origin.y + rect.size.height - arrowSize.height))
  132. //arrow vertex
  133. context.addLine(to: CGPoint(
  134. x: point.x,
  135. y: point.y))
  136. context.addLine(to: CGPoint(
  137. x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0,
  138. y: rect.origin.y + rect.size.height - arrowSize.height))
  139. context.addLine(to: CGPoint(
  140. x: rect.origin.x,
  141. y: rect.origin.y + rect.size.height - arrowSize.height))
  142. context.addLine(to: CGPoint(
  143. x: rect.origin.x,
  144. y: rect.origin.y))
  145. context.fillPath()
  146. }
  147. if offset.y > 0 {
  148. rect.origin.y += self.insets.top + arrowSize.height
  149. } else {
  150. rect.origin.y += self.insets.top
  151. }
  152. rect.size.height -= self.insets.top + self.insets.bottom
  153. UIGraphicsPushContext(context)
  154. label.draw(in: rect, withAttributes: _drawAttributes)
  155. UIGraphicsPopContext()
  156. context.restoreGState()
  157. }
  158. open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
  159. {
  160. setLabel(String(entry.y))
  161. }
  162. @objc open func setLabel(_ newLabel: String)
  163. {
  164. label = newLabel
  165. _drawAttributes.removeAll()
  166. _drawAttributes[.font] = self.font
  167. _drawAttributes[.paragraphStyle] = _paragraphStyle
  168. _drawAttributes[.foregroundColor] = self.textColor
  169. _labelSize = label?.size(withAttributes: _drawAttributes) ?? CGSize.zero
  170. var size = CGSize()
  171. size.width = _labelSize.width + self.insets.left + self.insets.right
  172. size.height = _labelSize.height + self.insets.top + self.insets.bottom
  173. size.width = max(minimumSize.width, size.width)
  174. size.height = max(minimumSize.height, size.height)
  175. self.size = size
  176. }
  177. }