// // BalloonMarker.swift // ChartsDemo-Swift // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda // A port of MPAndroidChart for iOS // Licensed under Apache License 2.0 // // https://github.com/danielgindi/Charts // import Foundation import Charts #if canImport(UIKit) import UIKit #endif open class BalloonMarker: MarkerImage { open var isBarchart : Bool = false open var color: UIColor open var arrowSize = CGSize(width: 0, height: 0) open var font: UIFont open var textColor: UIColor open var insets: UIEdgeInsets open var minimumSize = CGSize() fileprivate var label: String? fileprivate var _labelSize: CGSize = CGSize() fileprivate var _paragraphStyle: NSMutableParagraphStyle? fileprivate var _drawAttributes = [NSAttributedString.Key : Any]() public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets) { self.color = color self.font = font self.textColor = textColor self.insets = insets _paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle _paragraphStyle?.alignment = .center super.init() } var leftView: UIView? var rightView: UIView? var circleView:UIView? open override func offsetForDrawing(atPoint point: CGPoint) -> CGPoint { var offset = self.offset var size = self.size if size.width == 0.0 && image != nil { size.width = image!.size.width } if size.height == 0.0 && image != nil { size.height = image!.size.height } let width = size.width let height = size.height let padding: CGFloat = 8.0 var origin = point origin.x -= width / 2 origin.y = 0 if origin.x + offset.x < 0.0 { offset.x = -origin.x + padding } else if let chart = chartView, origin.x + width + offset.x > chart.bounds.size.width { offset.x = chart.bounds.size.width - origin.x - width - padding } if origin.y + offset.y < 0 { // offset.y = height + padding; } else if let chart = chartView, origin.y + height + offset.y > chart.bounds.size.height { // offset.y = chart.bounds.size.height - origin.y - height - padding } return offset } open override func draw(context: CGContext, point: CGPoint) { guard let label = label else { return } let offset = self.offsetForDrawing(atPoint: point) let size = self.size var rect = CGRect( origin: CGPoint( x: point.x + offset.x, y: point.y + offset.y), size: size) rect.origin.x -= size.width / 2.0 rect.origin.y = 0 // if isBarchart == true { if circleView == nil { circleView = UIView() chartView?.addSubview(circleView!) circleView?.backgroundColor = .white circleView?.layer.masksToBounds = true circleView?.layer.cornerRadius = 5 circleView?.layer.borderWidth = 2 circleView?.layer.borderColor = UIColor(hexString: "#573F95").cgColor } circleView?.frame = CGRect(x: point.x - 5, y: point.y - 5, width: 10, height: 10) //} context.saveGState() context.setFillColor(color.cgColor) // if offset.y > 0 // { // context.beginPath() // context.move(to: CGPoint( // x: rect.origin.x, // y: rect.origin.y + arrowSize.height)) // context.addLine(to: CGPoint( // x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0, // y: rect.origin.y + arrowSize.height)) // //arrow vertex // context.addLine(to: CGPoint( // x: point.x, // y: point.y)) // context.addLine(to: CGPoint( // x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0, // y: rect.origin.y + arrowSize.height)) // context.addLine(to: CGPoint( // x: rect.origin.x + rect.size.width, // y: rect.origin.y + arrowSize.height)) // context.addLine(to: CGPoint( // x: rect.origin.x + rect.size.width, // y: rect.origin.y + rect.size.height)) // context.addLine(to: CGPoint( // x: rect.origin.x, // y: rect.origin.y + rect.size.height)) // context.addLine(to: CGPoint( // x: rect.origin.x, // y: rect.origin.y + arrowSize.height)) // context.fillPath() // } // else // { context.beginPath() context.move(to: CGPoint( x: rect.origin.x, y: rect.origin.y)) context.addLine(to: CGPoint( x: rect.origin.x + rect.size.width, y: rect.origin.y)) context.addLine(to: CGPoint( x: rect.origin.x + rect.size.width, y: rect.origin.y + rect.size.height - arrowSize.height)) context.addLine(to: CGPoint( x: rect.origin.x + (rect.size.width + arrowSize.width) / 2.0, y: rect.origin.y + rect.size.height - arrowSize.height)) //arrow vertex context.addLine(to: CGPoint( x: point.x, y: point.y)) context.addLine(to: CGPoint( x: rect.origin.x + (rect.size.width - arrowSize.width) / 2.0, y: rect.origin.y + rect.size.height - arrowSize.height)) context.addLine(to: CGPoint( x: rect.origin.x, y: rect.origin.y + rect.size.height - arrowSize.height)) context.addLine(to: CGPoint( x: rect.origin.x, y: rect.origin.y)) context.fillPath() rect.origin.y += self.insets.top rect.size.height -= self.insets.top + self.insets.bottom UIGraphicsPushContext(context) label.draw(in: rect, withAttributes: _drawAttributes) UIGraphicsPopContext() context.restoreGState() if leftView == nil { leftView = UIView() chartView?.addSubview(leftView!) } leftView?.backgroundColor = UIColor(hexString: "#FFFFFF", transparency: 0.60) leftView?.frame = CGRect(x: 0, y: 0, width: rect.origin.x, height: (chartView?.bounds.size.height)!) if rightView == nil { rightView = UIView() chartView?.addSubview(rightView!) } rightView?.backgroundColor = UIColor(hexString: "#FFFFFF", transparency: 0.60) rightView!.frame = CGRect(x: rect.origin.x + rect.size.width, y: 0, width: (chartView?.bounds.size.width)! - rect.origin.x - rect.size.width, height: (chartView?.bounds.size.height)!) } open override func refreshContent(entry: ChartDataEntry, highlight: Highlight) { setLabel(String(entry.y)) } open func setLabel(_ newLabel: String) { label = newLabel _drawAttributes.removeAll() _drawAttributes[.font] = self.font _drawAttributes[.paragraphStyle] = _paragraphStyle _drawAttributes[.foregroundColor] = self.textColor _labelSize = label?.size(withAttributes: _drawAttributes) ?? CGSize.zero var size = CGSize() size.width = _labelSize.width + self.insets.left + self.insets.right size.height = _labelSize.height + self.insets.top + self.insets.bottom size.width = max(minimumSize.width, size.width) size.height = max(minimumSize.height, size.height) self.size = size } }