From 052845d480dd5e5e195edd4ba849b97449aecc46 Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Thu, 29 Feb 2024 18:30:45 +0100 Subject: [PATCH] feat: added a timestamp to the line chart feat: added background for tooltip in the line chart --- Kit/Widgets/LineChart.swift | 4 +-- Kit/plugins/Charts.swift | 59 ++++++++++++++++++++++++++----------- Kit/types.swift | 12 ++++++++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/Kit/Widgets/LineChart.swift b/Kit/Widgets/LineChart.swift index b24b6f2c..7d1dab3e 100644 --- a/Kit/Widgets/LineChart.swift +++ b/Kit/Widgets/LineChart.swift @@ -110,9 +110,9 @@ public class LineChart: WidgetWrapper { } if preview { - var list: [Double] = [] + var list: [DoubleValue] = [] for _ in 0..<16 { - list.append(Double.random(in: 0..<1)) + list.append(DoubleValue(Double.random(in: 0..<1))) } self.chart.points = list self._value = 0.38 diff --git a/Kit/plugins/Charts.swift b/Kit/plugins/Charts.swift index 3bda89e4..4a4c50bd 100644 --- a/Kit/plugins/Charts.swift +++ b/Kit/plugins/Charts.swift @@ -71,8 +71,8 @@ private func scaleValue(scale: Scale = .linear, value: Double, maxValue: Double, public class LineChartView: NSView { public var id: String = UUID().uuidString - public var points: [Double] - public var shadowPoints: [Double] = [] + public var points: [DoubleValue] + public var shadowPoints: [DoubleValue] = [] public var transparent: Bool = true public var color: NSColor = .controlAccentColor public var suffix: String = "%" @@ -80,13 +80,16 @@ public class LineChartView: NSView { private var cursor: NSPoint? = nil private var stop: Bool = false + private let dateFormatter = DateFormatter() public init(frame: NSRect, num: Int, scale: Scale = .none) { - self.points = Array(repeating: 0, count: num) + self.points = Array(repeating: DoubleValue(), count: num) self.scale = scale super.init(frame: frame) + self.dateFormatter.dateFormat = "dd/MM HH:mm:ss" + self.addTrackingArea(NSTrackingArea( rect: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height), options: [ @@ -128,10 +131,10 @@ public class LineChartView: NSView { let height: CGFloat = self.frame.height - dirtyRect.origin.y - offset let xRatio: CGFloat = self.frame.width / CGFloat(points.count-1) - let list = points.enumerated().compactMap { (i: Int, v: Double) -> (value: Double, point: CGPoint) in + let list = points.enumerated().compactMap { (i: Int, v: DoubleValue) -> (value: DoubleValue, point: CGPoint) in return (v, CGPoint( x: (CGFloat(i) * xRatio) + dirtyRect.origin.x, - y: scaleValue(scale: self.scale, value: v, maxValue: maxValue, maxHeight: height) + dirtyRect.origin.y + offset + y: scaleValue(scale: self.scale, value: v.value, maxValue: maxValue, maxHeight: height) + dirtyRect.origin.y + offset )) } @@ -196,23 +199,39 @@ public class LineChartView: NSView { style.alignment = .left var textPosition: CGPoint = CGPoint(x: nearest.point.x+4, y: nearest.point.y+4) - if textPosition.x + 24 > self.frame.size.width+self.frame.origin.x { - textPosition.x = nearest.point.x - 30 + if textPosition.x + 78 > self.frame.size.width+self.frame.origin.x { + textPosition.x = nearest.point.x - 78 style.alignment = .right } - if textPosition.y + 14 > height { - textPosition.y = nearest.point.y - 14 + if textPosition.y + 22 > height { + textPosition.y = nearest.point.y - 24 } - let stringAttributes = [ - NSAttributedString.Key.font: NSFont.systemFont(ofSize: 10, weight: .regular), - NSAttributedString.Key.foregroundColor: isDarkMode ? NSColor.white : NSColor.textColor, + let box = NSBezierPath(roundedRect: NSRect(x: textPosition.x-4, y: textPosition.y-2, width: 78, height: 24), xRadius: 2, yRadius: 2) + NSColor.gray.setStroke() + box.stroke() + (isDarkMode ? NSColor.black : NSColor.white).withAlphaComponent(0.75).setFill() + box.fill() + + let tsAttributes = [ + NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .medium), + NSAttributedString.Key.foregroundColor: (isDarkMode ? NSColor.white : NSColor.textColor).withAlphaComponent(0.7), NSAttributedString.Key.paragraphStyle: style ] - let rect = CGRect(x: textPosition.x, y: textPosition.y, width: 26, height: 10) - let value = "\(Int(nearest.value.rounded(toPlaces: 2) * 100))\(self.suffix)" - let str = NSAttributedString.init(string: value, attributes: stringAttributes) - str.draw(with: rect) + let valueAttributes = [ + NSAttributedString.Key.font: NSFont.systemFont(ofSize: 12, weight: .regular), + NSAttributedString.Key.foregroundColor: isDarkMode ? NSColor.white : NSColor.textColor + ] + + let tsRect = CGRect(x: textPosition.x, y: textPosition.y, width: 70, height: 9) + var value = self.dateFormatter.string(from: nearest.value.ts) + var str = NSAttributedString.init(string: value, attributes: tsAttributes) + str.draw(with: tsRect) + + let valueRect = CGRect(x: textPosition.x, y: textPosition.y+11, width: 32, height: 12) + value = "\(Int(nearest.value.value.rounded(toPlaces: 2) * 100))\(self.suffix)" + str = NSAttributedString.init(string: value, attributes: valueAttributes) + str.draw(with: valueRect) } } @@ -230,7 +249,7 @@ public class LineChartView: NSView { super.updateTrackingAreas() } - public func addValue(_ value: Double) { + public func addValue(_ value: DoubleValue) { self.points.remove(at: 0) self.points.append(value) @@ -239,6 +258,10 @@ public class LineChartView: NSView { } } + public func addValue(_ value: Double) { + self.addValue(DoubleValue(value)) + } + public func reinit(_ num: Int = 60) { guard self.points.count != num else { return } @@ -246,7 +269,7 @@ public class LineChartView: NSView { self.points = Array(self.points[self.points.count-num.. Double? { self.max { $0.value < $1.value }?.value } +} + public struct ColorValue: Equatable { public let value: Double public let color: NSColor?